diff --git a/.gitignore b/.gitignore
index b6a79e3..d044c16 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5 +5,2 @@
.*
+/valgrind.supp
diff --git a/source/g3d_viewer/main.cpp b/source/g3d_viewer/main.cpp
index 399ac7f..9024c1e 100644
--- a/source/g3d_viewer/main.cpp
+++ b/source/g3d_viewer/main.cpp
@@ -1218,3 +1218,3 @@ void MainWindow::loadParticle(string path) {
UnitParticleSystemType *unitParticleSystemType = new UnitParticleSystemType();
- unitParticleSystemType->load(dir, dir + folderDelimiter + particlePath,
+ unitParticleSystemType->load(NULL, dir, dir + folderDelimiter + particlePath, //### if we knew which particle it was, we could be more accurate
renderer,loadedFileList,"g3dviewer","");
@@ -1315,3 +1315,3 @@ void MainWindow::loadProjectileParticle(string path) {
ParticleSystemTypeProjectile *projectileParticleSystemType= new ParticleSystemTypeProjectile();
- projectileParticleSystemType->load(dir,
+ projectileParticleSystemType->load(NULL, dir, //### we don't know if there are overrides in the unit XML
dir + folderDelimiter + particlePath,renderer, loadedFileList,
@@ -1418,3 +1418,3 @@ void MainWindow::loadSplashParticle(string path) { // uses ParticleSystemTypeSp
ParticleSystemTypeSplash *splashParticleSystemType= new ParticleSystemTypeSplash();
- splashParticleSystemType->load(dir, dir + folderDelimiter + particlePath,renderer,
+ splashParticleSystemType->load(NULL, dir, dir + folderDelimiter + particlePath,renderer, //### we don't know if there are overrides in the unit XML
loadedFileList,"g3dviewer",""); // <---- only that must be splash...
diff --git a/source/glest_game/graphics/particle_type.cpp b/source/glest_game/graphics/particle_type.cpp
index 41d96cc..b909565 100644
--- a/source/glest_game/graphics/particle_type.cpp
+++ b/source/glest_game/graphics/particle_type.cpp
@@ -12,2 +12,3 @@
#include "particle_type.h"
+#include "unit_particle_type.h"
@@ -59,2 +60,4 @@ ParticleSystemType::~ParticleSystemType() {
}
+ for(Children::iterator it = children.begin(); it != children.end(); it++)
+ delete *it;
}
@@ -64,2 +67,3 @@ void ParticleSystemType::load(const XmlNode *particleSystemNode, const string &d
string parentLoader, string techtreePath) {
+
//texture
@@ -99,2 +103,8 @@ void ParticleSystemType::load(const XmlNode *particleSystemNode, const string &d
loadedFileList[path].push_back(make_pair(parentLoader,modelNode->getAttribute("path")->getRestrictedValue()));
+
+ if(modelNode->hasChild("cycles")) {
+ modelCycle = modelNode->getChild("cycles")->getAttribute("value")->getFloatValue();
+ if(modelCycle < 0.0)
+ throw runtime_error("negative model cycle value is bad");
+ }
}
@@ -180,2 +190,21 @@ void ParticleSystemType::load(const XmlNode *particleSystemNode, const string &d
}
+
+ // child particles
+ if(particleSystemNode->hasChild("child-particles")) {
+ const XmlNode *childrenNode= particleSystemNode->getChild("child-particles");
+ if(childrenNode->getAttribute("value")->getBoolValue()) {
+ for(int i = 0; i < childrenNode->getChildCount(); ++i) {
+ const XmlNode *particleFileNode= childrenNode->getChild("particle-file",i);
+ string path= particleFileNode->getAttribute("path")->getRestrictedValue();
+ UnitParticleSystemType *unitParticleSystemType= new UnitParticleSystemType();
+ string childPath= dir;
+ endPathWithSlash(childPath);
+ childPath += path;
+ string childDir = extractDirectoryPathFromFile(childPath);
+ unitParticleSystemType->load(particleFileNode,childDir,childPath,renderer,loadedFileList,parentLoader,techtreePath);
+ loadedFileList[childPath].push_back(make_pair(parentLoader,path));
+ children.push_back(unitParticleSystemType);
+ }
+ }
+ }
}
@@ -183,2 +212,9 @@ void ParticleSystemType::load(const XmlNode *particleSystemNode, const string &d
void ParticleSystemType::setValues(AttackParticleSystem *ats){
+ // add instances of all children; some settings will cascade to all children
+ for(Children::iterator i=children.begin(); i!=children.end(); i++){
+ UnitParticleSystem *child = new UnitParticleSystem();
+ (*i)->setValues(child);
+ ats->addChild(child);
+ child->setState(ParticleSystem::sPlay);
+ }
ats->setTexture(texture);
@@ -196,2 +232,3 @@ void ParticleSystemType::setValues(AttackParticleSystem *ats){
ats->setModel(model);
+ ats->setModelCycle(modelCycle);
ats->setTeamcolorNoEnergy(teamcolorNoEnergy);
@@ -206,3 +243,3 @@ void ParticleSystemType::setValues(AttackParticleSystem *ats){
-void ParticleSystemTypeProjectile::load(const string &dir, const string &path,
+void ParticleSystemTypeProjectile::load(const XmlNode* particleFileNode, const string &dir, const string &path,
RendererInterface *renderer, std::map<string,vector<pair<string, string> > > &loadedFileList,
@@ -219,2 +256,8 @@ void ParticleSystemTypeProjectile::load(const string &dir, const string &path,
const XmlNode *particleSystemNode= xmlTree.getRootNode();
+
+ if(particleFileNode){
+ // immediate children in the particleFileNode will override the particleSystemNode
+ particleFileNode->setSuper(particleSystemNode);
+ particleSystemNode= particleFileNode;
+ }
@@ -273,3 +316,3 @@ ProjectileParticleSystem *ParticleSystemTypeProjectile::create() {
-void ParticleSystemTypeSplash::load(const string &dir, const string &path,
+void ParticleSystemTypeSplash::load(const XmlNode* particleFileNode, const string &dir, const string &path,
RendererInterface *renderer, std::map<string,vector<pair<string, string> > > &loadedFileList,
@@ -287,2 +330,8 @@ void ParticleSystemTypeSplash::load(const string &dir, const string &path,
+ if(particleFileNode){
+ // immediate children in the particleFileNode will override the particleSystemNode
+ particleFileNode->setSuper(particleSystemNode);
+ particleSystemNode= particleFileNode;
+ }
+
ParticleSystemType::load(particleSystemNode, dir, renderer, loadedFileList, parentLoader, techtreePath);
diff --git a/source/glest_game/graphics/particle_type.h b/source/glest_game/graphics/particle_type.h
index 4e5e808..5ebf89a 100644
--- a/source/glest_game/graphics/particle_type.h
+++ b/source/glest_game/graphics/particle_type.h
@@ -15,2 +15,3 @@
#include <string>
+#include <list>
@@ -30,2 +31,3 @@ namespace Glest{ namespace Game{
using Shared::Graphics::ParticleSystem;
+using Shared::Graphics::UnitParticleSystem;
using Shared::Graphics::AttackParticleSystem;
@@ -40,2 +42,4 @@ using Shared::Xml::XmlNode;
+class UnitParticleSystemType;
+
// ===========================================================
@@ -51,2 +55,3 @@ protected:
Model *model;
+ float modelCycle;
string primitive;
@@ -66,2 +71,4 @@ protected:
int alternations;
+ typedef std::list<UnitParticleSystemType*> Children;
+ Children children;
@@ -74,4 +81,3 @@ public:
ParticleSystemType();
- ~ParticleSystemType();
-
+ virtual ~ParticleSystemType();
void load(const XmlNode *particleSystemNode, const string &dir,
@@ -109,3 +115,3 @@ private:
public:
- void load(const string &dir, const string &path,
+ void load(const XmlNode *particleFileNode, const string &dir, const string &path,
RendererInterface *renderer, std::map<string,vector<pair<string, string> > > &loadedFileList,
@@ -122,3 +128,3 @@ class ParticleSystemTypeSplash: public ParticleSystemType {
public:
- void load(const string &dir, const string &path,
+ void load(const XmlNode *particleFileNode, const string &dir, const string &path,
RendererInterface *renderer, std::map<string,vector<pair<string, string> > > &loadedFileList,
diff --git a/source/glest_game/graphics/unit_particle_type.cpp b/source/glest_game/graphics/unit_particle_type.cpp
index 77bfa3d..be10ad8 100644
--- a/source/glest_game/graphics/unit_particle_type.cpp
+++ b/source/glest_game/graphics/unit_particle_type.cpp
@@ -18,2 +18,3 @@
#include "game_constants.h"
+#include "platform_common.h"
@@ -24,2 +25,3 @@ using namespace Shared::Graphics;
using namespace Shared::Util;
+using namespace Shared::PlatformCommon;
@@ -34,4 +36,36 @@ void UnitParticleSystemType::load(const XmlNode *particleSystemNode, const strin
string parentLoader, string techtreePath) {
+
ParticleSystemType::load(particleSystemNode, dir, renderer, loadedFileList,
parentLoader,techtreePath);
+
+ //shape
+ angle= 0.0f;
+ if(particleSystemNode->hasChild("shape")){
+ const XmlNode *shapeNode= particleSystemNode->getChild("shape");
+ shape= UnitParticleSystem::strToShape(shapeNode->getAttribute("value")->getRestrictedValue());
+ if(shape == UnitParticleSystem::sConical){
+ angle= shapeNode->getChild("angle")->getAttribute("value")->getFloatValue();
+ }
+ } else {
+ shape = UnitParticleSystem::sLinear;
+ }
+ if(shape != UnitParticleSystem::sSpherical){
+ //direction
+ const XmlNode *directionNode= particleSystemNode->getChild("direction");
+ direction.x= directionNode->getAttribute("x")->getFloatValue();
+ direction.y= directionNode->getAttribute("y")->getFloatValue();
+ direction.z= directionNode->getAttribute("z")->getFloatValue();
+ if((shape == UnitParticleSystem::sConical) && (0.0 == direction.length()))
+ throw runtime_error("direction cannot be zero");
+ // ought to warn about 0 directions generally
+ }
+
+ //emission rate fade
+ if(particleSystemNode->hasChild("emission-rate-fade")){
+ const XmlNode *emissionRateFadeNode= particleSystemNode->getChild("emission-rate-fade");
+ emissionRateFade= emissionRateFadeNode->getAttribute("value")->getFloatValue();
+ } else {
+ emissionRateFade = 0;
+ }
+
//radius
@@ -39,2 +73,17 @@ void UnitParticleSystemType::load(const XmlNode *particleSystemNode, const strin
radius= radiusNode->getAttribute("value")->getFloatValue();
+
+ // min radius
+ if(particleSystemNode->hasChild("min-radius")){
+ const XmlNode *minRadiusNode= particleSystemNode->getChild("min-radius");
+ minRadius= minRadiusNode->getAttribute("value")->getFloatValue();
+ if(minRadius > radius)
+ throw runtime_error("min-radius cannot be bigger than radius");
+ } else {
+ minRadius = 0;
+ }
+ if((minRadius == 0) && (shape == UnitParticleSystem::sConical)) {
+ minRadius = 0.001; // fudge it so we aren't generating particles that are exactly centred
+ if(minRadius > radius)
+ radius = minRadius;
+ }
@@ -44,7 +93,2 @@ void UnitParticleSystemType::load(const XmlNode *particleSystemNode, const strin
- //direction
- const XmlNode *directionNode= particleSystemNode->getChild("direction");
- direction.x= directionNode->getAttribute("x")->getFloatValue();
- direction.y= directionNode->getAttribute("y")->getFloatValue();
- direction.z= directionNode->getAttribute("z")->getFloatValue();
@@ -95,5 +139,27 @@ void UnitParticleSystemType::load(const XmlNode *particleSystemNode, const strin
- //fixed
- const XmlNode *fixedNode= particleSystemNode->getChild("fixed");
- fixed= fixedNode->getAttribute("value")->getBoolValue();
+ //fixed
+ const XmlNode *fixedNode= particleSystemNode->getChild("fixed");
+ fixed= fixedNode->getAttribute("value")->getBoolValue();
+
+ // delay
+ if(particleSystemNode->hasChild("delay")) {
+ const XmlNode* delayNode = particleSystemNode->getChild("delay");
+ const float delay_secs = delayNode->getAttribute("value")->getFloatValue();
+ if(delay_secs < 0)
+ throw runtime_error("particle effect delay cannot be negative");
+ delay = delay_secs * GameConstants::updateFps;
+ } else{
+ delay= 0;
+ }
+
+ // lifetime
+ if(particleSystemNode->hasChild("lifetime")) {
+ const XmlNode* lifetimeNode = particleSystemNode->getChild("lifetime");
+ const float lifetime_secs = lifetimeNode->getAttribute("value")->getFloatValue();
+ if(lifetime_secs < 0 && lifetime_secs != -1)
+ throw runtime_error("particle effect lifetime cannot be negative (-1 means inherited from parent particle)");
+ lifetime = lifetime_secs * GameConstants::updateFps;
+ } else{
+ lifetime= -1; //default
+ }
}
@@ -101,2 +167,12 @@ void UnitParticleSystemType::load(const XmlNode *particleSystemNode, const strin
const void UnitParticleSystemType::setValues(UnitParticleSystem *ups){
+ // whilst we extend ParticleSystemType we don't use ParticleSystemType::setValues()
+ // add instances of all children; some settings will cascade to all children
+ for(Children::iterator i=children.begin(); i!=children.end(); i++){
+ UnitParticleSystem *child = new UnitParticleSystem();
+ (*i)->setValues(child);
+ ups->addChild(child);
+ }
+ // set values
+ ups->setModel(model);
+ ups->setModelCycle(modelCycle);
ups->setTexture(texture);
@@ -104,2 +180,4 @@ const void UnitParticleSystemType::setValues(UnitParticleSystem *ups){
ups->setOffset(offset);
+ ups->setShape(shape);
+ ups->setAngle(angle);
ups->setDirection(direction);
@@ -117,2 +195,5 @@ const void UnitParticleSystemType::setValues(UnitParticleSystem *ups){
ups->setRelativeDirection(relativeDirection);
+ ups->setDelay(delay);
+ ups->setLifetime(lifetime);
+ ups->setEmissionRateFade(emissionRateFade);
ups->setTeamcolorNoEnergy(teamcolorNoEnergy);
@@ -125,2 +206,3 @@ const void UnitParticleSystemType::setValues(UnitParticleSystem *ups){
ups->setRadius(radius);
+ ups->setMinRadius(minRadius);
ups->setBlendMode(ParticleSystem::strToBlendMode(mode));
@@ -139,3 +221,3 @@ const void UnitParticleSystemType::setValues(UnitParticleSystem *ups){
-void UnitParticleSystemType::load(const string &dir, const string &path,
+void UnitParticleSystemType::load(const XmlNode *particleFileNode, const string &dir, const string &path,
RendererInterface *renderer, std::map<string,vector<pair<string, string> > > &loadedFileList,
@@ -152,2 +234,8 @@ void UnitParticleSystemType::load(const string &dir, const string &path,
+ if(particleFileNode){
+ // immediate children in the particleFileNode will override the particleSystemNode
+ particleFileNode->setSuper(particleSystemNode);
+ particleSystemNode= particleFileNode;
+ }
+
UnitParticleSystemType::load(particleSystemNode, dir, renderer,
diff --git a/source/glest_game/graphics/unit_particle_type.h b/source/glest_game/graphics/unit_particle_type.h
index 22f0360..a90ae6d 100644
--- a/source/glest_game/graphics/unit_particle_type.h
+++ b/source/glest_game/graphics/unit_particle_type.h
@@ -15,2 +15,3 @@
#include <string>
+#include <list>
@@ -30,2 +31,3 @@ namespace Glest{ namespace Game{
+using Shared::Graphics::ParticleManager;
using Shared::Graphics::ParticleSystem;
@@ -46,4 +48,7 @@ class UnitParticleSystemType: public ParticleSystemType {
protected:
-
+ UnitParticleSystem::Shape shape;
+ float angle;
float radius;
+ float minRadius;
+ float emissionRateFade;
Vec3f direction;
@@ -56,2 +61,4 @@ protected:
bool radiusBasedStartenergy;
+ int delay;
+ int lifetime;
@@ -61,3 +68,3 @@ public:
string parentLoader, string techtreePath);
- void load(const string &dir, const string &path, RendererInterface *newTexture,
+ void load(const XmlNode *particleFileNode, const string &dir, const string &path, RendererInterface *newTexture,
std::map<string,vector<pair<string, string> > > &loadedFileList,string parentLoader,
diff --git a/source/glest_game/types/resource_type.cpp b/source/glest_game/types/resource_type.cpp
index 2f73817..f802b7e 100644
--- a/source/glest_game/types/resource_type.cpp
+++ b/source/glest_game/types/resource_type.cpp
@@ -108,3 +108,3 @@ void ResourceType::load(const string &dir, Checksum* checksum, Checksum *techtre
ObjectParticleSystemType *objectParticleSystemType= new ObjectParticleSystemType();
- objectParticleSystemType->load(dir, currentPath + particlePath,
+ objectParticleSystemType->load(particleFileNode, dir, currentPath + particlePath,
&Renderer::getInstance(), loadedFileList, sourceXMLFile, techtreePath);
diff --git a/source/glest_game/types/skill_type.cpp b/source/glest_game/types/skill_type.cpp
index 07248d0..49e34be 100644
--- a/source/glest_game/types/skill_type.cpp
+++ b/source/glest_game/types/skill_type.cpp
@@ -184,3 +184,3 @@ void SkillType::load(const XmlNode *sn, const string &dir, const TechTree *tt,
UnitParticleSystemType *unitParticleSystemType= new UnitParticleSystemType();
- unitParticleSystemType->load(dir, currentPath + path, &Renderer::getInstance(),
+ unitParticleSystemType->load(particleFileNode, dir, currentPath + path, &Renderer::getInstance(),
loadedFileList,parentLoader,tt->getPath());
@@ -257,6 +257,5 @@ void SkillType::load(const XmlNode *sn, const string &dir, const TechTree *tt,
attackBoost.unitParticleSystemTypeForSourceUnit = new UnitParticleSystemType();
- attackBoost.unitParticleSystemTypeForSourceUnit->load(dir, currentPath + path, &Renderer::getInstance(),
+ attackBoost.unitParticleSystemTypeForSourceUnit->load(particleFileNode, dir, currentPath + path, &Renderer::getInstance(),
loadedFileList,parentLoader,tt->getPath());
loadedFileList[currentPath + path].push_back(make_pair(parentLoader,particleFileNode->getAttribute("path")->getRestrictedValue()));
-
}
@@ -266,3 +265,3 @@ void SkillType::load(const XmlNode *sn, const string &dir, const TechTree *tt,
attackBoost.unitParticleSystemTypeForAffectedUnit = new UnitParticleSystemType();
- attackBoost.unitParticleSystemTypeForAffectedUnit->load(dir, currentPath + path, &Renderer::getInstance(),
+ attackBoost.unitParticleSystemTypeForAffectedUnit->load(particleFileNode, dir, currentPath + path, &Renderer::getInstance(),
loadedFileList,parentLoader,tt->getPath());
@@ -487,3 +486,3 @@ void AttackSkillType::load(const XmlNode *sn, const string &dir, const TechTree
projectileParticleSystemType= new ParticleSystemTypeProjectile();
- projectileParticleSystemType->load(dir, currentPath + path,
+ projectileParticleSystemType->load(particleNode, dir, currentPath + path,
&Renderer::getInstance(), loadedFileList, parentLoader,
@@ -523,3 +522,3 @@ void AttackSkillType::load(const XmlNode *sn, const string &dir, const TechTree
splashParticleSystemType= new ParticleSystemTypeSplash();
- splashParticleSystemType->load(dir, currentPath + path,
+ splashParticleSystemType->load(particleNode, dir, currentPath + path,
&Renderer::getInstance(),loadedFileList, parentLoader,
diff --git a/source/glest_game/types/unit_type.cpp b/source/glest_game/types/unit_type.cpp
index 1019390..c800899 100644
--- a/source/glest_game/types/unit_type.cpp
+++ b/source/glest_game/types/unit_type.cpp
@@ -297,3 +297,3 @@ void UnitType::load(int id,const string &dir, const TechTree *techTree,
- unitParticleSystemType->load(dir, currentPath + path,
+ unitParticleSystemType->load(particleFileNode, dir, currentPath + path,
&Renderer::getInstance(),loadedFileList, sourceXMLFile,
diff --git a/source/glest_game/world/tileset.cpp b/source/glest_game/world/tileset.cpp
index a6be3f8..bacbd78 100644
--- a/source/glest_game/world/tileset.cpp
+++ b/source/glest_game/world/tileset.cpp
@@ -228,3 +228,3 @@ void Tileset::load(const string &dir, Checksum *checksum, Checksum *tilesetCheck
ObjectParticleSystemType *objectParticleSystemType= new ObjectParticleSystemType();
- objectParticleSystemType->load(dir, currentPath + path,
+ objectParticleSystemType->load(particleFileNode, dir, currentPath + path,
&Renderer::getInstance(), loadedFileList, sourceXMLFile,"");
diff --git a/source/shared_lib/include/graphics/gl/particle_renderer_gl.h b/source/shared_lib/include/graphics/gl/particle_renderer_gl.h
index ac24550..f5e58d8 100644
--- a/source/shared_lib/include/graphics/gl/particle_renderer_gl.h
+++ b/source/shared_lib/include/graphics/gl/particle_renderer_gl.h
@@ -40,3 +40,3 @@ public:
virtual void renderSystemLineAlpha(ParticleSystem *ps);
- virtual void renderModel(AttackParticleSystem *ps, ModelRenderer *mr);
+ virtual void renderModel(GameParticleSystem *ps, ModelRenderer *mr);
diff --git a/source/shared_lib/include/graphics/particle.h b/source/shared_lib/include/graphics/particle.h
index 68a71a0..9533653 100644
--- a/source/shared_lib/include/graphics/particle.h
+++ b/source/shared_lib/include/graphics/particle.h
@@ -134,3 +134,2 @@ protected:
int alternations;
-
ParticleObserver *particleObserver;
@@ -141,3 +140,2 @@ public:
virtual ~ParticleSystem();
-
virtual ParticleSystemType getParticleSystemType() const = 0;
@@ -160,5 +158,5 @@ public:
//set
- void setState(State state);
+ virtual void setState(State state);
void setTexture(Texture *texture);
- void setPos(Vec3f pos);
+ virtual void setPos(Vec3f pos);
void setColor(Vec4f color);
@@ -170,5 +168,5 @@ public:
void setSpeed(float speed);
- void setActive(bool active);
+ virtual void setActive(bool active);
void setObserver(ParticleObserver *particleObserver);
- void setVisible(bool visible);
+ virtual void setVisible(bool visible);
void setBlendMode(BlendMode blendMode) {this->blendMode= blendMode;}
@@ -181,4 +179,8 @@ public:
//misc
- void fade();
+ virtual void fade();
int isEmpty() const;
+
+ //children
+ virtual int getChildCount() { return 0; }
+ virtual ParticleSystem* getChild(int i);
@@ -219,2 +221,46 @@ public:
// =====================================================
+// class GameParticleSystem
+/// base-class for unit and attack systems
+// =====================================================
+
+class UnitParticleSystem;
+
+class GameParticleSystem: public ParticleSystem{
+public:
+ enum Primitive{
+ pQuad,
+ pLine,
+ pLineAlpha
+ };
+ static Primitive strToPrimitive(const string &str);
+ virtual ~GameParticleSystem();
+ int getChildCount();
+ ParticleSystem* getChild(int i);
+ void addChild(UnitParticleSystem* child);
+ void removeChild(UnitParticleSystem* child);
+ void setPos(Vec3f pos);
+ void setOffset(Vec3f offset);
+ void setModel(Model *model) {this->model= model;}
+ virtual void render(ParticleRenderer *pr, ModelRenderer *mr);
+ float getTween() { return tween; } // 0.0 -> 1.0 for animation of model
+ Model *getModel() const {return model;}
+ void setPrimitive(Primitive primitive) {this->primitive= primitive;}
+ Vec3f getDirection() const {return direction;}
+ void setModelCycle(float modelCycle) {this->modelCycle= modelCycle;}
+protected:
+ typedef std::vector<UnitParticleSystem*> Children;
+ Children children;
+ Primitive primitive;
+ Model *model;
+ float modelCycle;
+ Vec3f offset;
+ Vec3f direction;
+ float tween;
+
+ GameParticleSystem(int particleCount);
+ void positionChildren();
+ void setTween(float relative,float absolute);
+};
+
+// =====================================================
// class UnitParticleSystem
@@ -222,3 +268,3 @@ public:
-class UnitParticleSystem: public ParticleSystem{
+class UnitParticleSystem: public GameParticleSystem{
public:
@@ -227,2 +273,3 @@ private:
float radius;
+ float minRadius;
Vec3f windSpeed;
@@ -232,7 +279,8 @@ private:
bool energyUp;
+
public:
- enum Primitive{
- pQuad,
- pLine,
- pLineAlpha
+ enum Shape{
+ sLinear, // generated in a sphere, flying in direction
+ sSpherical, // generated in a sphere, flying away from center
+ sConical, // generated in a cone at angle from direction
};
@@ -241,6 +289,4 @@ public:
bool fixed;
- Model *model;
- Primitive primitive;
- Vec3f offset;
- Vec3f direction;
+ Shape shape;
+ float angle;
float sizeNoEnergy;
@@ -251,4 +297,7 @@ public:
bool radiusBasedStartenergy;
-
int staticParticleCount;
+ int delay;
+ int lifetime;
+ float emissionRateFade;
+ GameParticleSystem* parent;
@@ -256,2 +305,3 @@ public:
UnitParticleSystem(int particleCount= 2000);
+ ~UnitParticleSystem();
@@ -263,14 +313,17 @@ public:
virtual void update();
- virtual void render(ParticleRenderer *pr, ModelRenderer *mr);
virtual bool getVisible() const;
+ virtual void fade();
+ virtual void render(ParticleRenderer *pr, ModelRenderer *mr);
//set params
- void setRadius(float radius);
+ void setRadius(float radius) {this->radius= radius;}
+ void setMinRadius(float minRadius) {this->minRadius= minRadius;}
+ void setEmissionRateFade(float emissionRateFade) {this->emissionRateFade= emissionRateFade;}
+
void setWind(float windAngle, float windSpeed);
- void setOffset(Vec3f offset) {this->offset= offset;}
- void setDirection(Vec3f direction) {this->direction= direction;}
+ void setDirection(Vec3f direction) {this->direction= direction;}
void setSizeNoEnergy(float sizeNoEnergy) {this->sizeNoEnergy= sizeNoEnergy;}
void setGravity(float gravity) {this->gravity= gravity;}
- void setRotation(float rotation) {this->rotation= rotation;}
+ void setRotation(float rotation);
void setRelative(bool relative) {this->relative= relative;}
@@ -283,5 +336,11 @@ public:
void setRadiusBasedStartenergy(bool value) {this->radiusBasedStartenergy= value;}
-
- static Primitive strToPrimitive(const string &str);
+ void setShape(Shape shape) {this->shape= shape;}
+ void setAngle(float angle) {this->angle= angle;}
+ void setDelay(int delay) {this->delay= delay;}
+ void setLifetime(int lifetime) {this->lifetime= lifetime;}
+ void setParent(GameParticleSystem* parent) {this->parent= parent;}
+ GameParticleSystem* getParent() const {return parent;}
+ void setParentDirection(Vec3f parentDirection);
+ static Shape strToShape(const string& str);
};
@@ -338,19 +397,7 @@ public:
-class AttackParticleSystem: public ParticleSystem{
-public:
- enum Primitive{
- pQuad,
- pLine,
- pLineAlpha
- };
+class AttackParticleSystem: public GameParticleSystem{
protected:
- Model *model;
- Primitive primitive;
- Vec3f offset;
float sizeNoEnergy;
float gravity;
- float tween;
- Vec3f direction;
-
public:
@@ -360,17 +407,6 @@ public:
- virtual void render(ParticleRenderer *pr, ModelRenderer *mr);
-
- Model *getModel() const {return model;}
- Vec3f getDirection() const {return direction;}
-
- void setModel(Model *model) {this->model= model;}
- void setOffset(Vec3f offset) {this->offset= offset;}
void setSizeNoEnergy(float sizeNoEnergy) {this->sizeNoEnergy= sizeNoEnergy;}
void setGravity(float gravity) {this->gravity= gravity;}
- void setPrimitive(Primitive primitive) {this->primitive= primitive;}
- float getTween() { return tween; } // 0.0 -> 1.0 for animation of model
virtual void initParticleSystem() {} // opportunity to do any initialization when the system has been created and all settings set
-
- static Primitive strToPrimitive(const string &str);
};
@@ -403,4 +439,2 @@ private:
- float modelCycle;
-
Trajectory trajectory;
@@ -411,2 +445,4 @@ private:
float trajectoryFrequency;
+
+ void rotateChildren();
@@ -429,3 +465,2 @@ public:
- void setModelCycle(float modelCycle) {this->modelCycle= modelCycle;}
void setPath(Vec3f startPos, Vec3f endPos);
diff --git a/source/shared_lib/include/graphics/particle_renderer.h b/source/shared_lib/include/graphics/particle_renderer.h
index cadbee7..324cc3f 100644
--- a/source/shared_lib/include/graphics/particle_renderer.h
+++ b/source/shared_lib/include/graphics/particle_renderer.h
@@ -33,3 +33,3 @@ public:
virtual void renderSystemLineAlpha(ParticleSystem *ps)=0;
- virtual void renderModel(AttackParticleSystem *ps, ModelRenderer *mr)=0;
+ virtual void renderModel(GameParticleSystem *ps, ModelRenderer *mr)=0;
};
diff --git a/source/shared_lib/include/graphics/vec.h b/source/shared_lib/include/graphics/vec.h
index 167cb06..082af58 100644
--- a/source/shared_lib/include/graphics/vec.h
+++ b/source/shared_lib/include/graphics/vec.h
@@ -158,2 +158,18 @@ public:
}
+
+ Vec2<T> rotate(float rad){
+ const float
+#ifdef USE_STREFLOP
+ c = streflop::cosf(rad),
+ s = streflop::sinf(rad);
+#else
+ c = scosf(rad),
+ s = ssinf(rad);
+#endif
+ return Vec2<T>(x*c-y*s,x*s+y*c);
+ }
+
+ Vec2<T> rotateAround(float rad,const Vec2<T>& pt){
+ return pt+(*this-pt).rotate(rad);
+ }
diff --git a/source/shared_lib/include/xml/xml_parser.h b/source/shared_lib/include/xml/xml_parser.h
index edd29ba..5e32778 100644
--- a/source/shared_lib/include/xml/xml_parser.h
+++ b/source/shared_lib/include/xml/xml_parser.h
@@ -66,3 +66,3 @@ private:
XmlNode *rootNode;
-
+ string loadPath;
private:
@@ -92,2 +92,3 @@ private:
vector<XmlAttribute*> attributes;
+ mutable const XmlNode* superNode;
@@ -101,2 +102,4 @@ public:
~XmlNode();
+
+ void setSuper(const XmlNode* superNode) const { this->superNode = superNode; }
@@ -124,2 +127,3 @@ private:
string getTreeString() const;
+ bool hasChildNoSuper(const string& childName) const;
};
diff --git a/source/shared_lib/sources/graphics/gl/particle_renderer_gl.cpp b/source/shared_lib/sources/graphics/gl/particle_renderer_gl.cpp
index a5caf70..06ee62b 100644
--- a/source/shared_lib/sources/graphics/gl/particle_renderer_gl.cpp
+++ b/source/shared_lib/sources/graphics/gl/particle_renderer_gl.cpp
@@ -225,3 +225,3 @@ void ParticleRendererGl::renderSystemLineAlpha(ParticleSystem *ps){
-void ParticleRendererGl::renderModel(AttackParticleSystem *ps, ModelRenderer *mr){
+void ParticleRendererGl::renderModel(GameParticleSystem *ps, ModelRenderer *mr){
//render model
@@ -264,3 +264,5 @@ void ParticleRendererGl::renderModel(AttackParticleSystem *ps, ModelRenderer *mr
mr->begin(true, true, false);
- model->updateInterpolationData(ps->getTween(), false);
+ float t = ps->getTween();
+ assert(t >= 0.0f && t <= 1.0f);
+ model->updateInterpolationData(t, false);
mr->render(model);
diff --git a/source/shared_lib/sources/graphics/particle.cpp b/source/shared_lib/sources/graphics/particle.cpp
index 720be82..7e15785 100644
--- a/source/shared_lib/sources/graphics/particle.cpp
+++ b/source/shared_lib/sources/graphics/particle.cpp
@@ -137,3 +137,3 @@ ParticleSystem::BlendMode ParticleSystem::strToBlendMode(const string &str){
else{
- throw "Unknown particle mode: " + str;
+ throw runtime_error("Unknown particle mode: " + str);
}
@@ -145,2 +145,4 @@ void ParticleSystem::setState(State state){
this->state= state;
+ for(int i=getChildCount()-1; i>=0; i--)
+ getChild(i)->setState(state);
}
@@ -153,2 +155,4 @@ void ParticleSystem::setPos(Vec3f pos){
this->pos= pos;
+ for(int i=getChildCount()-1; i>=0; i--)
+ getChild(i)->setPos(pos);
}
@@ -185,2 +189,4 @@ void ParticleSystem::setActive(bool active){
this->active= active;
+ for(int i=getChildCount()-1; i>=0; i--)
+ getChild(i)->setActive(active);
}
@@ -191,4 +197,10 @@ void ParticleSystem::setObserver(ParticleObserver *particleObserver){
+ParticleSystem* ParticleSystem::getChild(int i){
+ throw std::out_of_range("ParticleSystem::getChild bad");
+}
+
void ParticleSystem::setVisible(bool visible){
this->visible= visible;
+ for(int i=getChildCount()-1; i>=0; i--)
+ getChild(i)->setVisible(visible);
}
@@ -211,2 +223,4 @@ void ParticleSystem::fade(){
}
+ for(int i=getChildCount()-1; i>=0; i--)
+ getChild(i)->fade();
}
@@ -299,2 +313,4 @@ void ParticleSystem::setFactionColor(Vec3f factionColor){
}
+ for(int i=getChildCount()-1; i>=0; i--)
+ getChild(i)->setFactionColor(factionColor);
}
@@ -381,2 +397,120 @@ void FireParticleSystem::setWind(float windAngle, float windSpeed){
// ===========================================================================
+// GameParticleSystem
+// ===========================================================================
+
+GameParticleSystem::GameParticleSystem(int particleCount):
+ ParticleSystem(particleCount),
+ primitive(pQuad),
+ model(NULL),
+ modelCycle(0.0f),
+ tween(0.0f),
+ offset(0.0f),
+ direction(0.0f, 1.0f, 0.0f)
+{}
+
+GameParticleSystem::~GameParticleSystem(){
+ for(Children::iterator it= children.begin(); it != children.end(); it++){
+ (*it)->setParent(NULL);
+ (*it)->fade();
+ }
+}
+
+GameParticleSystem::Primitive GameParticleSystem::strToPrimitive(const string &str){
+ if(str == "quad"){
+ return pQuad;
+ }
+ else if(str == "line"){
+ return pLine;
+ }
+ else{
+ throw runtime_error("Unknown particle primitive: " + str);
+ }
+}
+
+int GameParticleSystem::getChildCount(){
+ return children.size();
+}
+
+ParticleSystem* GameParticleSystem::getChild(int i){
+ return children.at(i); // does bounds checking
+}
+
+void GameParticleSystem::addChild(UnitParticleSystem* child) {
+ assert(!child->getParent());
+ child->setParent(this);
+ children.push_back(child);
+}
+
+void GameParticleSystem::removeChild(UnitParticleSystem* child){
+ assert(this == child->getParent());
+ Children::iterator it = std::find(children.begin(),children.end(),child);
+ assert(it != children.end());
+ children.erase(it);
+}
+
+void GameParticleSystem::setPos(Vec3f pos){
+ this->pos= pos;
+ positionChildren();
+}
+
+void GameParticleSystem::positionChildren() {
+ Vec3f child_pos = pos - offset;
+ for(int i=getChildCount()-1; i>=0; i--)
+ getChild(i)->setPos(child_pos);
+}
+
+void GameParticleSystem::setOffset(Vec3f offset){
+ this->offset= offset;
+ positionChildren();
+}
+
+void GameParticleSystem::render(ParticleRenderer *pr, ModelRenderer *mr){
+ if(active){
+ if(model != NULL){
+ pr->renderModel(this, mr);
+ }
+ switch(primitive){
+ case pQuad:
+ pr->renderSystem(this);
+ break;
+ case pLine:
+ pr->renderSystemLine(this);
+ break;
+ default:
+ assert(false);
+ }
+ }
+}
+
+void GameParticleSystem::setTween(float relative,float absolute) {
+ if(model){
+ // animation?
+ if(modelCycle == 0.0f) {
+ tween= relative;
+ }
+ else {
+ #ifdef USE_STREFLOP
+ if(streflop::fabs(absolute) <= 0.00001f){
+ #else
+ if(fabs(absolute) <= 0.00001f){
+ #endif
+ tween = 0.0f;
+ }
+ else {
+ #ifdef USE_STREFLOP
+ tween= streflop::fmod(absolute, modelCycle);
+ #else
+ tween= fmod(absolute, modelCycle);
+ #endif
+ tween /= modelCycle;
+ }
+ }
+ assert(tween >= 0.0f && tween <= 1.0f);
+ tween= clamp(tween, 0.0f, 1.0f);
+ }
+ for(Children::iterator it= children.begin(); it != children.end(); it++)
+ (*it)->setTween(relative,absolute);
+}
+
+// ===========================================================================
// UnitParticleSystem
@@ -385,4 +519,5 @@ bool UnitParticleSystem::isNight= false;
-UnitParticleSystem::UnitParticleSystem(int particleCount) :
- ParticleSystem(particleCount){
+UnitParticleSystem::UnitParticleSystem(int particleCount):
+ GameParticleSystem(particleCount),
+ parent(NULL){
radius= 0.5f;
@@ -395,4 +530,2 @@ UnitParticleSystem::UnitParticleSystem(int particleCount) :
primitive= pQuad;
- offset= Vec3f(0.0f);
- direction= Vec3f(0.0f, 1.0f, 0.0f);
gravity= 0.0f;
@@ -415,2 +548,11 @@ UnitParticleSystem::UnitParticleSystem(int particleCount) :
energyUp= false;
+
+ delay = 0; // none
+ lifetime = -1; // forever
+}
+
+UnitParticleSystem::~UnitParticleSystem(){
+ if(parent){
+ parent->removeChild(this);
+ }
}
@@ -427,26 +569,30 @@ bool UnitParticleSystem::getVisible() const{
-void UnitParticleSystem::render(ParticleRenderer *pr, ModelRenderer *mr){
- //if(active){
- switch(primitive){
- case pQuad:
- pr->renderSystem(this);
- break;
- case pLine:
- pr->renderSystemLine(this);
- break;
- default:
- assert(false);
+void UnitParticleSystem::render(ParticleRenderer *pr, ModelRenderer *mr) {
+ GameParticleSystem::render(pr,mr);
+}
+
+void UnitParticleSystem::setRotation(float rotation){
+ this->rotation= rotation;
+ for(Children::iterator it= children.begin(); it != children.end(); it++)
+ (*it)->setRotation(rotation);
+}
+
+void UnitParticleSystem::fade(){
+ if(!parent || (lifetime<=0 && !(emissionRateFade && emissionRate > 0))){ // particle has its own lifetime?
+ GameParticleSystem::fade();
}
- //}
}
-UnitParticleSystem::Primitive UnitParticleSystem::strToPrimitive(const string &str){
- if(str == "quad"){
- return pQuad;
+UnitParticleSystem::Shape UnitParticleSystem::strToShape(const string& str){
+ if(str == "spherical"){
+ return sSpherical;
+ }
+ else if(str == "conical"){
+ return sConical;
}
- else if(str == "line"){
- return pLine;
+ else if(str == "linear"){
+ return sLinear;
}
else{
- throw "Unknown particle primitive: " + str;
+ throw runtime_error("Unkown particle shape: " + str);
}
@@ -457,20 +603,10 @@ void UnitParticleSystem::initParticle(Particle *p, int particleIndex){
- float ang= random.randRange(-2.0f * pi, 2.0f * pi);
-#ifdef USE_STREFLOP
- float mod= streflop::fabsf(random.randRange(-radius, radius));
-
- float x= streflop::sinf(ang)*mod;
- float y= streflop::cosf(ang)*mod;
-
- float radRatio= streflop::sqrtf(streflop::sqrtf(mod/radius));
+ const float ang= random.randRange(-2.0f * pi, 2.0f * pi);
+#ifdef USE_STREFLOP
+ const float mod= streflop::fabsf(random.randRange(-radius, radius));
+ const float radRatio= streflop::sqrtf(streflop::sqrtf(mod/radius));
#else
- float mod= fabsf(random.randRange(-radius, radius));
-
- float x= sinf(ang) * mod;
- float y= cosf(ang) * mod;
-
- float radRatio= sqrtf(sqrtf(mod / radius));
+ const float mod= fabsf(random.randRange(-radius, radius));
+ const float radRatio= sqrtf(sqrtf(mod / radius));
#endif
-
- //p->color= color*0.5f + color*0.5f*radRatio;
p->color= color;
@@ -487,28 +623,51 @@ void UnitParticleSystem::initParticle(Particle *p, int particleIndex){
p->size= particleSize;
-
- p->speed= Vec3f(direction.x + direction.x * random.randRange(-0.5f, 0.5f), direction.y + direction.y
- * random.randRange(-0.5f, 0.5f), direction.z + direction.z * random.randRange(-0.5f, 0.5f));
- p->speed= p->speed * speed;
p->accel= Vec3f(0.0f, -gravity, 0.0f);
-
- if(relative == false){
- p->pos= Vec3f(pos.x + x + offset.x, pos.y + random.randRange(-radius / 2, radius / 2) + offset.y, pos.z + y
- + offset.z);
- }
- else{// rotate it according to rotation
- float rad= degToRad(rotation);
-#ifdef USE_STREFLOP
- p->pos= Vec3f(pos.x+x+offset.z*streflop::sinf(rad)+offset.x*streflop::cosf(rad), pos.y+random.randRange(-radius/2, radius/2)+offset.y, pos.z+y+(offset.z*streflop::cosf(rad)-offset.x*streflop::sinf(rad)));
- if(relativeDirection){
+
+ // work out where we start for our shape (set speed and pos)
+ switch(shape){
+ case sSpherical:
+ angle = random.randRange(0,360);
+ // fall through
+ case sConical:{
+ Vec2f horiz = Vec2f(1,0).rotate(ang);
+ Vec2f vert = Vec2f(1,0).rotate(degToRad(angle));
+ Vec3f start = Vec3f(horiz.x*vert.y,vert.x,horiz.y).getNormalized(); // close enough
+ p->speed = start * speed;
+ start = start * random.randRange(minRadius,radius);
+ p->pos = pos + offset + start;
+ } break;
+ case sLinear:{
+ #ifdef USE_STREFLOP
+ float x= streflop::sinf(ang)*mod;
+ float y= streflop::cosf(ang)*mod;
+ #else
+ float x= sinf(ang) * mod;
+ float y= cosf(ang) * mod;
+ #endif
+ const float rad= degToRad(rotation);
+ if(!relative){
+ p->pos= Vec3f(pos.x + x + offset.x, pos.y + random.randRange(-radius / 2, radius / 2) + offset.y, pos.z + y
+ + offset.z);
+ }
+ else{// rotate it according to rotation
+ #ifdef USE_STREFLOP
+ p->pos= Vec3f(pos.x+x+offset.z*streflop::sinf(rad)+offset.x*streflop::cosf(rad), pos.y+random.randRange(-radius/2, radius/2)+offset.y, pos.z+y+(offset.z*streflop::cosf(rad)-offset.x*streflop::sinf(rad)));
+ #else
+ p->pos= Vec3f(pos.x + x + offset.z * sinf(rad) + offset.x * cosf(rad), pos.y + random.randRange(-radius / 2,
+ radius / 2) + offset.y, pos.z + y + (offset.z * cosf(rad) - offset.x * sinf(rad)));
+ #endif
+ }
+ p->speed= Vec3f(direction.x + direction.x * random.randRange(-0.5f, 0.5f), direction.y + direction.y
+ * random.randRange(-0.5f, 0.5f), direction.z + direction.z * random.randRange(-0.5f, 0.5f));
+ p->speed= p->speed * speed;
+ if(relative && relativeDirection){
+ #ifdef USE_STREFLOP
p->speed=Vec3f(p->speed.z*streflop::sinf(rad)+p->speed.x*streflop::cosf(rad),p->speed.y,(p->speed.z*streflop::cosf(rad)-p->speed.x*streflop::sinf(rad)));
- }
-#else
- p->pos= Vec3f(pos.x + x + offset.z * sinf(rad) + offset.x * cosf(rad), pos.y + random.randRange(-radius / 2,
- radius / 2) + offset.y, pos.z + y + (offset.z * cosf(rad) - offset.x * sinf(rad)));
- if(relativeDirection){
+ #else
p->speed= Vec3f(p->speed.z * sinf(rad) + p->speed.x * cosf(rad), p->speed.y, (p->speed.z * cosf(rad)
- - p->speed.x * sinf(rad)));
+ - p->speed.x * sinf(rad)));
+ #endif
}
-
-#endif
+ } break;
+ default: throw runtime_error("bad shape");
}
@@ -517,2 +676,15 @@ void UnitParticleSystem::initParticle(Particle *p, int particleIndex){
void UnitParticleSystem::update(){
+ // delay and timeline are only applicable for child particles
+ if(parent && delay>0 && delay--){
+ return;
+ }
+ if(parent && lifetime>0 && !--lifetime) {
+ fade();
+ }
+ if(state != sPause) {
+ emissionRate-= emissionRateFade;
+ if(parent && emissionRate < 0.0f) {
+ fade();
+ }
+ }
if(fixed){
@@ -575,6 +747,2 @@ void UnitParticleSystem::updateParticle(Particle *p){
-void UnitParticleSystem::setRadius(float radius){
- this->radius= radius;
-}
-
void UnitParticleSystem::setWind(float windAngle, float windSpeed){
@@ -702,39 +870,5 @@ void SnowParticleSystem::setWind(float windAngle, float windSpeed){
AttackParticleSystem::AttackParticleSystem(int particleCount) :
- ParticleSystem(particleCount){
- model= NULL;
+ GameParticleSystem(particleCount){
primitive= pQuad;
- offset= Vec3f(0.0f);
gravity= 0.0f;
- tween= 0.0f;
- direction= Vec3f(1.0f, 0.0f, 0.0f);
-}
-
-void AttackParticleSystem::render(ParticleRenderer *pr, ModelRenderer *mr){
- if(active){
- if(model != NULL){
- pr->renderModel(this, mr);
- }
- switch(primitive){
- case pQuad:
- pr->renderSystem(this);
- break;
- case pLine:
- pr->renderSystemLine(this);
- break;
- default:
- assert(false);
- }
- }
-}
-
-AttackParticleSystem::Primitive AttackParticleSystem::strToPrimitive(const string &str){
- if(str == "quad"){
- return pQuad;
- }
- else if(str == "line"){
- return pLine;
- }
- else{
- throw "Unknown particle primitive: " + str;
- }
}
@@ -777,3 +911,2 @@ void ProjectileParticleSystem::link(SplashParticleSystem *particleSystem){
void ProjectileParticleSystem::update(){
-
if(state == sPlay){
@@ -787,15 +920,3 @@ void ProjectileParticleSystem::update(){
float t= clamp(currentVector.length() / targetVector.length(), 0.0f, 1.0f);
-
- // animation?
- if(modelCycle == 0.0f) {
- tween= t;
- }
- else {
- #ifdef USE_STREFLOP
- tween= streflop::fmod(currentVector.length(), modelCycle);
- #else
- tween= fmod(currentVector.length(), modelCycle);
- #endif
- tween= clamp(tween / currentVector.length(), 0.0f, 1.0f);
- }
+ setTween(t,currentVector.length());
@@ -835,2 +956,5 @@ void ProjectileParticleSystem::update(){
direction.normalize();
+ // trigger update of child particles
+ positionChildren();
+ rotateChildren();
@@ -838,3 +962,3 @@ void ProjectileParticleSystem::update(){
if(flatPos.dist(endPos) < 0.5f){
- state= sFade;
+ fade();
model= NULL;
@@ -856,2 +980,14 @@ void ProjectileParticleSystem::update(){
+void ProjectileParticleSystem::rotateChildren() {
+ //### only on horizontal plane :(
+#ifdef USE_STREFLOP
+ float rotation = streflop::atan2(direction.x, direction.z);
+#else
+ float rotation = atan2(direction.x, direction.z);
+#endif
+ rotation = radToDeg(rotation);
+ for(Children::iterator it = children.begin(); it != children.end(); it++)
+ (*it)->setRotation(rotation);
+}
+
void ProjectileParticleSystem::initParticle(Particle *p, int particleIndex){
@@ -908,2 +1044,7 @@ void ProjectileParticleSystem::setPath(Vec3f startPos, Vec3f endPos){
this->endPos= endPos;
+
+ // direction
+ direction = (endPos - lastPos);
+ direction.normalize();
+ rotateChildren();
}
@@ -921,3 +1062,3 @@ ProjectileParticleSystem::Trajectory ProjectileParticleSystem::strToTrajectory(c
else{
- throw "Unknown particle system trajectory: " + str;
+ throw runtime_error("Unknown particle system trajectory: " + str);
}
@@ -961,4 +1102,5 @@ void SplashParticleSystem::update() {
- tween= 1.0f - ((emissionRate + startEmissionRate) / (startEmissionRate * 2.0f));
- tween= clamp(tween, 0.0f, 1.0f);
+ float t= 1.0f - ((emissionRate + startEmissionRate) / (startEmissionRate * 2.0f));
+ t= clamp(t, 0.0f, 1.0f);
+ setTween(t,t);
@@ -1134,3 +1276,6 @@ void ParticleManager::cleanupUnitParticleSystems(vector<UnitParticleSystem *> &p
void ParticleManager::manage(ParticleSystem *ps){
+ assert((std::find(particleSystems.begin(),particleSystems.end(),ps) == particleSystems.end()) && "particle cannot be added twice");
particleSystems.push_back(ps);
+ for(int i=ps->getChildCount()-1; i>=0; i--)
+ manage(ps->getChild(i));
}
diff --git a/source/shared_lib/sources/xml/xml_parser.cpp b/source/shared_lib/sources/xml/xml_parser.cpp
index c6cfe6b..280d9ff 100644
--- a/source/shared_lib/sources/xml/xml_parser.cpp
+++ b/source/shared_lib/sources/xml/xml_parser.cpp
@@ -15,2 +15,4 @@
#include <stdexcept>
+#include <vector>
+#include <algorithm>
@@ -174,3 +176,14 @@ void XmlTree::init(const string &name){
+typedef std::vector<XmlTree*> LoadStack;
+static LoadStack loadStack;
+
void XmlTree::load(const string &path, std::map<string,string> mapTagReplacementValues) {
+ assert(!loadPath.size());
+ for(LoadStack::iterator it= loadStack.begin(); it!= loadStack.end(); it++){
+ if((*it)->loadPath == path){
+ throw runtime_error(path + " recursively included");
+ }
+ }
+ loadPath = path;
+ loadStack.push_back(this);
this->rootNode= XmlIo::getInstance().load(path, mapTagReplacementValues);
@@ -183,2 +196,5 @@ void XmlTree::save(const string &path){
XmlTree::~XmlTree(){
+ LoadStack::iterator it= find(loadStack.begin(),loadStack.end(),this);
+ if(it != loadStack.end())
+ loadStack.erase(it);
delete rootNode;
@@ -190,3 +206,3 @@ XmlTree::~XmlTree(){
-XmlNode::XmlNode(DOMNode *node, std::map<string,string> mapTagReplacementValues) {
+XmlNode::XmlNode(DOMNode *node, std::map<string,string> mapTagReplacementValues): superNode(NULL) {
if(node == NULL || node->getNodeName() == NULL) {
@@ -237,3 +253,3 @@ XmlNode::XmlNode(DOMNode *node, std::map<string,string> mapTagReplacementValues)
-XmlNode::XmlNode(const string &name) {
+XmlNode::XmlNode(const string &name): superNode(NULL) {
this->name= name;
@@ -271,2 +287,3 @@ XmlAttribute *XmlNode::getAttribute(const string &name,bool mustExist) const {
XmlNode *XmlNode::getChild(unsigned int i) const {
+ assert(!superNode);
if(i >= children.size()) {
@@ -289,2 +306,4 @@ vector<XmlNode *> XmlNode::getChildList(const string &childName) const {
XmlNode *XmlNode::getChild(const string &childName, unsigned int i) const{
+ if(superNode && !hasChildNoSuper(childName))
+ return superNode->getChild(childName,i);
if(i>=children.size()){
@@ -307,2 +326,4 @@ XmlNode *XmlNode::getChild(const string &childName, unsigned int i) const{
bool XmlNode::hasChildAtIndex(const string &childName, int i) const {
+ if(superNode && !hasChildNoSuper(childName))
+ return superNode->hasChildAtIndex(childName,i);
int count= 0;
@@ -320,4 +341,7 @@ bool XmlNode::hasChildAtIndex(const string &childName, int i) const {
-
bool XmlNode::hasChild(const string &childName) const {
+ return hasChildNoSuper(childName) || (superNode && superNode->hasChild(childName));
+}
+
+bool XmlNode::hasChildNoSuper(const string &childName) const {
int count= 0;
@@ -328,3 +352,2 @@ bool XmlNode::hasChild(const string &childName) const {
}
-
return false;
@@ -333,2 +356,3 @@ bool XmlNode::hasChild(const string &childName) const {
XmlNode *XmlNode::addChild(const string &name){
+ assert(!superNode);
XmlNode *node= new XmlNode(name);