diff --git a/source/g3d_viewer/main.cpp b/source/g3d_viewer/main.cpp index 399ac7f97..9024c1e1f 100644 --- a/source/g3d_viewer/main.cpp +++ b/source/g3d_viewer/main.cpp @@ -1216,7 +1216,7 @@ void MainWindow::loadParticle(string path) { std::map > > loadedFileList; 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",""); unitParticleSystemTypes.push_back(unitParticleSystemType); @@ -1313,7 +1313,7 @@ void MainWindow::loadProjectileParticle(string path) { std::map > > loadedFileList; 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, "g3dviewer",""); @@ -1416,7 +1416,7 @@ void MainWindow::loadSplashParticle(string path) { // uses ParticleSystemTypeSp std::map > > loadedFileList; 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... // std::cout << "Values loaded, about to read..." << std::endl; diff --git a/source/glest_game/graphics/particle_type.cpp b/source/glest_game/graphics/particle_type.cpp index 41d96cc15..b90956511 100644 --- a/source/glest_game/graphics/particle_type.cpp +++ b/source/glest_game/graphics/particle_type.cpp @@ -10,6 +10,7 @@ // ============================================================== #include "particle_type.h" +#include "unit_particle_type.h" #include "util.h" #include "core_data.h" @@ -57,11 +58,14 @@ ParticleSystemType::~ParticleSystemType() { memoryObjectList[this]--; assert(memoryObjectList[this] == 0); } + for(Children::iterator it = children.begin(); it != children.end(); it++) + delete *it; } void ParticleSystemType::load(const XmlNode *particleSystemNode, const string &dir, RendererInterface *renderer, std::map > > &loadedFileList, string parentLoader, string techtreePath) { + //texture const XmlNode *textureNode= particleSystemNode->getChild("texture"); bool textureEnabled= textureNode->getAttribute("value")->getBoolValue(); @@ -97,6 +101,12 @@ void ParticleSystemType::load(const XmlNode *particleSystemNode, const string &d model->load(path, false, &loadedFileList, &parentLoader); 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"); + } } } else { @@ -178,9 +188,35 @@ void ParticleSystemType::load(const XmlNode *particleSystemNode, const string &d else { mode="normal"; } + + // 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); + } + } + } } 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); ats->setPrimitive(AttackParticleSystem::strToPrimitive(primitive)); ats->setOffset(offset); @@ -194,6 +230,7 @@ void ParticleSystemType::setValues(AttackParticleSystem *ats){ ats->setMaxParticleEnergy(energyMax); ats->setVarParticleEnergy(energyVar); ats->setModel(model); + ats->setModelCycle(modelCycle); ats->setTeamcolorNoEnergy(teamcolorNoEnergy); ats->setTeamcolorEnergy(teamcolorEnergy); ats->setAlternations(alternations); @@ -204,7 +241,7 @@ void ParticleSystemType::setValues(AttackParticleSystem *ats){ // class ParticleSystemTypeProjectile // =========================================================== -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 > > &loadedFileList, string parentLoader, string techtreePath) { @@ -217,6 +254,12 @@ void ParticleSystemTypeProjectile::load(const string &dir, const string &path, loadedFileList[path].push_back(make_pair(parentLoader,parentLoader)); const XmlNode *particleSystemNode= xmlTree.getRootNode(); + + if(particleFileNode){ + // immediate children in the particleFileNode will override the particleSystemNode + particleFileNode->setSuper(particleSystemNode); + particleSystemNode= particleFileNode; + } ParticleSystemType::load(particleSystemNode, dir, renderer, loadedFileList,parentLoader, techtreePath); @@ -271,7 +314,7 @@ ProjectileParticleSystem *ParticleSystemTypeProjectile::create() { // class ParticleSystemTypeSplash // =========================================================== -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 > > &loadedFileList, string parentLoader, string techtreePath) { @@ -285,6 +328,12 @@ void ParticleSystemTypeSplash::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; + } + ParticleSystemType::load(particleSystemNode, dir, renderer, loadedFileList, parentLoader, techtreePath); //emission rate fade diff --git a/source/glest_game/graphics/particle_type.h b/source/glest_game/graphics/particle_type.h index 4e5e80862..5ebf89a4a 100644 --- a/source/glest_game/graphics/particle_type.h +++ b/source/glest_game/graphics/particle_type.h @@ -13,6 +13,7 @@ #define _GLEST_GAME_PARTICLETYPE_H_ #include +#include #include "particle.h" #include "factory.h" @@ -28,6 +29,7 @@ using namespace Shared::Graphics; namespace Glest{ namespace Game{ using Shared::Graphics::ParticleSystem; +using Shared::Graphics::UnitParticleSystem; using Shared::Graphics::AttackParticleSystem; using Shared::Graphics::ProjectileParticleSystem; using Shared::Graphics::SplashParticleSystem; @@ -38,6 +40,8 @@ using Shared::Graphics::Model; using Shared::Util::MultiFactory; using Shared::Xml::XmlNode; +class UnitParticleSystemType; + // =========================================================== // class ParticleSystemType // @@ -49,6 +53,7 @@ protected: string type; Texture2D *texture; Model *model; + float modelCycle; string primitive; Vec3f offset; Vec4f color; @@ -64,6 +69,8 @@ protected: bool teamcolorNoEnergy; bool teamcolorEnergy; int alternations; + typedef std::list Children; + Children children; bool minmaxEnabled; int minHp; @@ -72,8 +79,7 @@ protected: public: ParticleSystemType(); - ~ParticleSystemType(); - + virtual ~ParticleSystemType(); void load(const XmlNode *particleSystemNode, const string &dir, RendererInterface *renderer, std::map > > &loadedFileList, string parentLoader, string techtreePath); @@ -107,7 +113,7 @@ private: float trajectoryFrequency; public: - void load(const string &dir, const string &path, + void load(const XmlNode *particleFileNode, const string &dir, const string &path, RendererInterface *renderer, std::map > > &loadedFileList, string parentLoader, string techtreePath); ProjectileParticleSystem *create(); @@ -120,7 +126,7 @@ public: 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 > > &loadedFileList, string parentLoader, string techtreePath); SplashParticleSystem *create(); diff --git a/source/glest_game/graphics/unit_particle_type.cpp b/source/glest_game/graphics/unit_particle_type.cpp index 77bfa3d5a..be10ad897 100644 --- a/source/glest_game/graphics/unit_particle_type.cpp +++ b/source/glest_game/graphics/unit_particle_type.cpp @@ -16,12 +16,14 @@ #include "xml_parser.h" #include "config.h" #include "game_constants.h" +#include "platform_common.h" #include "leak_dumper.h" using namespace Shared::Xml; using namespace Shared::Graphics; using namespace Shared::Util; +using namespace Shared::PlatformCommon; namespace Glest{ namespace Game{ @@ -32,21 +34,63 @@ namespace Glest{ namespace Game{ void UnitParticleSystemType::load(const XmlNode *particleSystemNode, const string &dir, RendererInterface *renderer, std::map > > &loadedFileList, 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 const XmlNode *radiusNode= particleSystemNode->getChild("radius"); 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; + } //relative const XmlNode *relativeNode= particleSystemNode->getChild("relative"); relative= relativeNode->getAttribute("value")->getBoolValue(); - //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(); //relativeDirection if(particleSystemNode->hasChild("relativeDirection")){ @@ -93,15 +137,49 @@ void UnitParticleSystemType::load(const XmlNode *particleSystemNode, const strin radiusBasedStartenergy= true; } - //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 + } } 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); ups->setPrimitive(UnitParticleSystem::strToPrimitive(primitive)); ups->setOffset(offset); + ups->setShape(shape); + ups->setAngle(angle); ups->setDirection(direction); ups->setColor(color); ups->setColorNoEnergy(colorNoEnergy); @@ -115,6 +193,9 @@ const void UnitParticleSystemType::setValues(UnitParticleSystem *ups){ ups->setFixed(fixed); ups->setRelative(relative); ups->setRelativeDirection(relativeDirection); + ups->setDelay(delay); + ups->setLifetime(lifetime); + ups->setEmissionRateFade(emissionRateFade); ups->setTeamcolorNoEnergy(teamcolorNoEnergy); ups->setTeamcolorEnergy(teamcolorEnergy); ups->setAlternations(alternations); @@ -123,6 +204,7 @@ const void UnitParticleSystemType::setValues(UnitParticleSystem *ups){ ups->setIsVisibleAtDay(isVisibleAtDay); ups->setStaticParticleCount(staticParticleCount); ups->setRadius(radius); + ups->setMinRadius(minRadius); ups->setBlendMode(ParticleSystem::strToBlendMode(mode)); ups->setRadiusBasedStartenergy(radiusBasedStartenergy); //prepare system for given staticParticleCount @@ -137,7 +219,7 @@ 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 > > &loadedFileList, string parentLoader, string techtreePath) { @@ -150,6 +232,12 @@ void UnitParticleSystemType::load(const string &dir, const string &path, loadedFileList[path].push_back(make_pair(parentLoader,parentLoader)); const XmlNode *particleSystemNode= xmlTree.getRootNode(); + if(particleFileNode){ + // immediate children in the particleFileNode will override the particleSystemNode + particleFileNode->setSuper(particleSystemNode); + particleSystemNode= particleFileNode; + } + UnitParticleSystemType::load(particleSystemNode, dir, renderer, loadedFileList, parentLoader, techtreePath); } diff --git a/source/glest_game/graphics/unit_particle_type.h b/source/glest_game/graphics/unit_particle_type.h index 22f036027..a90ae6dc1 100644 --- a/source/glest_game/graphics/unit_particle_type.h +++ b/source/glest_game/graphics/unit_particle_type.h @@ -13,6 +13,7 @@ #define _GLEST_GAME_UNITPARTICLETYPE_H_ #include +#include #include "particle.h" #include "factory.h" @@ -28,6 +29,7 @@ using namespace Shared::Graphics; namespace Glest{ namespace Game{ +using Shared::Graphics::ParticleManager; using Shared::Graphics::ParticleSystem; using Shared::Graphics::UnitParticleSystem; using Shared::Graphics::Texture2D; @@ -44,8 +46,11 @@ using Shared::Xml::XmlNode; class UnitParticleSystemType: public ParticleSystemType { protected: - + UnitParticleSystem::Shape shape; + float angle; float radius; + float minRadius; + float emissionRateFade; Vec3f direction; bool relative; bool relativeDirection; @@ -54,12 +59,14 @@ protected: bool isVisibleAtNight; bool isVisibleAtDay; bool radiusBasedStartenergy; + int delay; + int lifetime; public: void load(const XmlNode *particleSystemNode, const string &dir, RendererInterface *newTexture, std::map > > &loadedFileList, 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 > > &loadedFileList,string parentLoader, string techtreePath); const void setValues (UnitParticleSystem *uts); diff --git a/source/glest_game/types/resource_type.cpp b/source/glest_game/types/resource_type.cpp index 2f7381792..f802b7e69 100644 --- a/source/glest_game/types/resource_type.cpp +++ b/source/glest_game/types/resource_type.cpp @@ -106,7 +106,7 @@ void ResourceType::load(const string &dir, Checksum* checksum, Checksum *techtre string particlePath= particleFileNode->getAttribute("path")->getRestrictedValue(); ObjectParticleSystemType *objectParticleSystemType= new ObjectParticleSystemType(); - objectParticleSystemType->load(dir, currentPath + particlePath, + objectParticleSystemType->load(particleFileNode, dir, currentPath + particlePath, &Renderer::getInstance(), loadedFileList, sourceXMLFile, techtreePath); loadedFileList[currentPath + particlePath].push_back(make_pair(sourceXMLFile,particleFileNode->getAttribute("path")->getRestrictedValue())); diff --git a/source/glest_game/types/skill_type.cpp b/source/glest_game/types/skill_type.cpp index 07248d02d..49e34bebb 100644 --- a/source/glest_game/types/skill_type.cpp +++ b/source/glest_game/types/skill_type.cpp @@ -182,7 +182,7 @@ void SkillType::load(const XmlNode *sn, const string &dir, const TechTree *tt, const XmlNode *particleFileNode= particleNode->getChild("particle-file", i); string path= particleFileNode->getAttribute("path")->getRestrictedValue(); UnitParticleSystemType *unitParticleSystemType= new UnitParticleSystemType(); - unitParticleSystemType->load(dir, currentPath + path, &Renderer::getInstance(), + unitParticleSystemType->load(particleFileNode, dir, currentPath + path, &Renderer::getInstance(), loadedFileList,parentLoader,tt->getPath()); loadedFileList[currentPath + path].push_back(make_pair(parentLoader,particleFileNode->getAttribute("path")->getRestrictedValue())); unitParticleSystemTypes.push_back(unitParticleSystemType); @@ -255,16 +255,15 @@ void SkillType::load(const XmlNode *sn, const string &dir, const TechTree *tt, const XmlNode *particleFileNode= particleNode->getChild("originator-particle-file"); string path= particleFileNode->getAttribute("path")->getRestrictedValue(); 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())); - } if(particleNode->hasChild("affected-particle-file") == true) { const XmlNode *particleFileNode= particleNode->getChild("affected-particle-file"); string path= particleFileNode->getAttribute("path")->getRestrictedValue(); 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()); loadedFileList[currentPath + path].push_back(make_pair(parentLoader,particleFileNode->getAttribute("path")->getRestrictedValue())); } @@ -485,7 +484,7 @@ void AttackSkillType::load(const XmlNode *sn, const string &dir, const TechTree if(particleEnabled){ string path= particleNode->getAttribute("path")->getRestrictedValue(); projectileParticleSystemType= new ParticleSystemTypeProjectile(); - projectileParticleSystemType->load(dir, currentPath + path, + projectileParticleSystemType->load(particleNode, dir, currentPath + path, &Renderer::getInstance(), loadedFileList, parentLoader, tt->getPath()); } @@ -521,7 +520,7 @@ void AttackSkillType::load(const XmlNode *sn, const string &dir, const TechTree if(particleEnabled){ string path= particleNode->getAttribute("path")->getRestrictedValue(); splashParticleSystemType= new ParticleSystemTypeSplash(); - splashParticleSystemType->load(dir, currentPath + path, + splashParticleSystemType->load(particleNode, dir, currentPath + path, &Renderer::getInstance(),loadedFileList, parentLoader, tt->getPath()); } diff --git a/source/glest_game/types/unit_type.cpp b/source/glest_game/types/unit_type.cpp index 1019390e1..c800899e2 100644 --- a/source/glest_game/types/unit_type.cpp +++ b/source/glest_game/types/unit_type.cpp @@ -295,7 +295,7 @@ void UnitType::load(int id,const string &dir, const TechTree *techTree, //Texture2D *newTexture = Renderer::getInstance().newTexture2D(rsGame); Texture2D *newTexture = NULL; - unitParticleSystemType->load(dir, currentPath + path, + unitParticleSystemType->load(particleFileNode, dir, currentPath + path, &Renderer::getInstance(),loadedFileList, sourceXMLFile, techTree->getPath()); loadedFileList[currentPath + path].push_back(make_pair(sourceXMLFile,particleFileNode->getAttribute("path")->getRestrictedValue())); diff --git a/source/glest_game/world/tileset.cpp b/source/glest_game/world/tileset.cpp index a6be3f818..bacbd7863 100644 --- a/source/glest_game/world/tileset.cpp +++ b/source/glest_game/world/tileset.cpp @@ -226,7 +226,7 @@ void Tileset::load(const string &dir, Checksum *checksum, Checksum *tilesetCheck const XmlNode *particleFileNode= particleNode->getChild("particle-file", k); string path= particleFileNode->getAttribute("path")->getRestrictedValue(); ObjectParticleSystemType *objectParticleSystemType= new ObjectParticleSystemType(); - objectParticleSystemType->load(dir, currentPath + path, + objectParticleSystemType->load(particleFileNode, dir, currentPath + path, &Renderer::getInstance(), loadedFileList, sourceXMLFile,""); loadedFileList[currentPath + path].push_back(make_pair(sourceXMLFile,particleFileNode->getAttribute("path")->getRestrictedValue())); 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 ac2455071..f5e58d849 100644 --- a/source/shared_lib/include/graphics/gl/particle_renderer_gl.h +++ b/source/shared_lib/include/graphics/gl/particle_renderer_gl.h @@ -38,7 +38,7 @@ public: virtual void renderSystem(ParticleSystem *ps); virtual void renderSystemLine(ParticleSystem *ps); virtual void renderSystemLineAlpha(ParticleSystem *ps); - virtual void renderModel(AttackParticleSystem *ps, ModelRenderer *mr); + virtual void renderModel(GameParticleSystem *ps, ModelRenderer *mr); protected: void renderBufferQuads(int quadCount); diff --git a/source/shared_lib/include/graphics/particle.h b/source/shared_lib/include/graphics/particle.h index 68a71a075..95336539c 100644 --- a/source/shared_lib/include/graphics/particle.h +++ b/source/shared_lib/include/graphics/particle.h @@ -132,14 +132,12 @@ protected: bool teamcolorNoEnergy; bool teamcolorEnergy; int alternations; - ParticleObserver *particleObserver; public: //conmstructor and destructor ParticleSystem(int particleCount); virtual ~ParticleSystem(); - virtual ParticleSystemType getParticleSystemType() const = 0; //public @@ -158,9 +156,9 @@ public: virtual bool getVisible() const {return visible;} //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); void setColorNoEnergy(Vec4f color); void setEmissionRate(float emissionRate); @@ -168,9 +166,9 @@ public: void setVarParticleEnergy(int varParticleEnergy); void setParticleSize(float particleSize); 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;} void setTeamcolorNoEnergy(bool teamcolorNoEnergy) {this->teamcolorNoEnergy= teamcolorNoEnergy;} void setTeamcolorEnergy(bool teamcolorEnergy) {this->teamcolorEnergy= teamcolorEnergy;} @@ -179,8 +177,12 @@ public: static BlendMode strToBlendMode(const string &str); //misc - void fade(); + virtual void fade(); int isEmpty() const; + + //children + virtual int getChildCount() { return 0; } + virtual ParticleSystem* getChild(int i); protected: //protected @@ -217,43 +219,91 @@ public: }; // ===================================================== -// class UnitParticleSystem +// class GameParticleSystem +/// base-class for unit and attack systems // ===================================================== -class UnitParticleSystem: public ParticleSystem{ -public: - static bool isNight; -private: - float radius; - Vec3f windSpeed; - Vec3f cRotation; - Vec3f fixedAddition; - Vec3f oldPosition; - bool energyUp; +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 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 +// ===================================================== + +class UnitParticleSystem: public GameParticleSystem{ +public: + static bool isNight; +private: + float radius; + float minRadius; + Vec3f windSpeed; + Vec3f cRotation; + Vec3f fixedAddition; + Vec3f oldPosition; + bool energyUp; + +public: + 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 + }; bool relative; bool relativeDirection; bool fixed; - Model *model; - Primitive primitive; - Vec3f offset; - Vec3f direction; + Shape shape; + float angle; float sizeNoEnergy; float gravity; float rotation; bool isVisibleAtNight; bool isVisibleAtDay; bool radiusBasedStartenergy; - int staticParticleCount; + int delay; + int lifetime; + float emissionRateFade; + GameParticleSystem* parent; public: UnitParticleSystem(int particleCount= 2000); + ~UnitParticleSystem(); virtual ParticleSystemType getParticleSystemType() const { return pst_UnitParticleSystem;} @@ -261,18 +311,21 @@ public: virtual void initParticle(Particle *p, int particleIndex); virtual void updateParticle(Particle *p); 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;} void setRelativeDirection(bool relativeDirection) {this->relativeDirection= relativeDirection;} void setFixed(bool fixed) {this->fixed= fixed;} @@ -281,9 +334,15 @@ public: void setIsVisibleAtNight(bool value) {this->isVisibleAtNight= value;} void setIsVisibleAtDay(bool value) {this->isVisibleAtDay= value;} 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); }; // ===================================================== @@ -336,43 +395,20 @@ public: /// Base class for Projectiles and Splashes // =========================================================================== -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: AttackParticleSystem(int particleCount); virtual ParticleSystemType getParticleSystemType() const { return pst_ProjectileParticleSystem;} - 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); }; // ===================================================== @@ -401,14 +437,14 @@ private: Vec3f yVector; Vec3f zVector; - float modelCycle; - Trajectory trajectory; float trajectorySpeed; //parabolic float trajectoryScale; float trajectoryFrequency; + + void rotateChildren(); public: ProjectileParticleSystem(int particleCount= 1000); @@ -427,7 +463,6 @@ public: void setTrajectoryScale(float trajectoryScale) {this->trajectoryScale= trajectoryScale;} void setTrajectoryFrequency(float trajectoryFrequency) {this->trajectoryFrequency= trajectoryFrequency;} - void setModelCycle(float modelCycle) {this->modelCycle= modelCycle;} void setPath(Vec3f startPos, Vec3f endPos); static Trajectory strToTrajectory(const string &str); diff --git a/source/shared_lib/include/graphics/particle_renderer.h b/source/shared_lib/include/graphics/particle_renderer.h index cadbee727..324cc3fc5 100644 --- a/source/shared_lib/include/graphics/particle_renderer.h +++ b/source/shared_lib/include/graphics/particle_renderer.h @@ -31,7 +31,7 @@ public: virtual void renderSystem(ParticleSystem *ps)=0; virtual void renderSystemLine(ParticleSystem *ps)=0; virtual void renderSystemLineAlpha(ParticleSystem *ps)=0; - virtual void renderModel(AttackParticleSystem *ps, ModelRenderer *mr)=0; + virtual void renderModel(GameParticleSystem *ps, ModelRenderer *mr)=0; }; }}//end namespace diff --git a/source/shared_lib/include/graphics/vec.h b/source/shared_lib/include/graphics/vec.h index 167cb0653..082af584a 100644 --- a/source/shared_lib/include/graphics/vec.h +++ b/source/shared_lib/include/graphics/vec.h @@ -156,6 +156,22 @@ public: x/= m; y/= m; } + + Vec2 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(x*c-y*s,x*s+y*c); + } + + Vec2 rotateAround(float rad,const Vec2& pt){ + return pt+(*this-pt).rotate(rad); + } std::string getString() const { std::ostringstream streamOut; diff --git a/source/shared_lib/include/platform/common/cache_manager.h b/source/shared_lib/include/platform/common/cache_manager.h index 0d19643f6..53d82949b 100644 --- a/source/shared_lib/include/platform/common/cache_manager.h +++ b/source/shared_lib/include/platform/common/cache_manager.h @@ -38,13 +38,22 @@ static const char *getFolderTreeContentsCheckSumListRecursivelyCacheLookupKey1; static const char *getFolderTreeContentsCheckSumListRecursivelyCacheLookupKey2; protected: - static Mutex mutexCache; - typedef enum { cacheItemGet, cacheItemSet } CacheAccessorType; + template + static Mutex & manageCachedItemMutex(string cacheKey) { + // Here is the actual type-safe instantiation + static std::map itemCacheMutexList; + if(itemCacheMutexList.find(cacheKey) == itemCacheMutexList.end()) { + itemCacheMutexList[cacheKey] = Mutex(); + } + Mutex &mutex = itemCacheMutexList[cacheKey]; + return mutex; + } + template static T & manageCachedItem(string cacheKey, T *value,CacheAccessorType accessor) { // Here is the actual type-safe instantiation @@ -52,6 +61,7 @@ protected: if(accessor == cacheItemSet) { if(value == NULL) { try { + Mutex &mutexCache = manageCachedItemMutex(cacheKey); MutexSafeWrapper safeMutex(&mutexCache); if(itemCache.find(cacheKey) != itemCache.end()) { itemCache.erase(cacheKey); @@ -64,6 +74,7 @@ protected: } try { + Mutex &mutexCache = manageCachedItemMutex(cacheKey); MutexSafeWrapper safeMutex(&mutexCache); itemCache[cacheKey] = *value; safeMutex.ReleaseLock(); @@ -94,6 +105,10 @@ public: return manageCachedItem(cacheKey,NULL,cacheItemSet); } + template + static Mutex & getMutexForItem(string cacheKey) { + return manageCachedItemMutex(cacheKey); + } }; }}//end namespace diff --git a/source/shared_lib/include/xml/xml_parser.h b/source/shared_lib/include/xml/xml_parser.h index edd29ba60..5e3277863 100644 --- a/source/shared_lib/include/xml/xml_parser.h +++ b/source/shared_lib/include/xml/xml_parser.h @@ -64,7 +64,7 @@ public: class XmlTree{ private: XmlNode *rootNode; - + string loadPath; private: XmlTree(XmlTree&); void operator =(XmlTree&); @@ -90,6 +90,7 @@ private: string text; vector children; vector attributes; + mutable const XmlNode* superNode; private: XmlNode(XmlNode&); @@ -99,6 +100,8 @@ public: XmlNode(XERCES_CPP_NAMESPACE::DOMNode *node, std::map mapTagReplacementValues); XmlNode(const string &name); ~XmlNode(); + + void setSuper(const XmlNode* superNode) const { this->superNode = superNode; } const string &getName() const {return name;} size_t getChildCount() const {return children.size();} @@ -122,6 +125,7 @@ public: 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 a5caf7051..06ee62b64 100644 --- a/source/shared_lib/sources/graphics/gl/particle_renderer_gl.cpp +++ b/source/shared_lib/sources/graphics/gl/particle_renderer_gl.cpp @@ -223,7 +223,7 @@ void ParticleRendererGl::renderSystemLineAlpha(ParticleSystem *ps){ assertGl(); } -void ParticleRendererGl::renderModel(AttackParticleSystem *ps, ModelRenderer *mr){ +void ParticleRendererGl::renderModel(GameParticleSystem *ps, ModelRenderer *mr){ //render model Model *model = ps->getModel(); if(model != NULL) { @@ -262,7 +262,9 @@ void ParticleRendererGl::renderModel(AttackParticleSystem *ps, ModelRenderer *mr //render 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); mr->end(); diff --git a/source/shared_lib/sources/graphics/particle.cpp b/source/shared_lib/sources/graphics/particle.cpp index 720be823e..7e15785cf 100644 --- a/source/shared_lib/sources/graphics/particle.cpp +++ b/source/shared_lib/sources/graphics/particle.cpp @@ -135,7 +135,7 @@ ParticleSystem::BlendMode ParticleSystem::strToBlendMode(const string &str){ return bmOneMinusAlpha; } else{ - throw "Unknown particle mode: " + str; + throw runtime_error("Unknown particle mode: " + str); } } @@ -143,6 +143,8 @@ ParticleSystem::BlendMode ParticleSystem::strToBlendMode(const string &str){ void ParticleSystem::setState(State state){ this->state= state; + for(int i=getChildCount()-1; i>=0; i--) + getChild(i)->setState(state); } void ParticleSystem::setTexture(Texture *texture){ @@ -151,6 +153,8 @@ void ParticleSystem::setTexture(Texture *texture){ void ParticleSystem::setPos(Vec3f pos){ this->pos= pos; + for(int i=getChildCount()-1; i>=0; i--) + getChild(i)->setPos(pos); } void ParticleSystem::setColor(Vec4f color){ @@ -183,14 +187,22 @@ void ParticleSystem::setSpeed(float speed){ void ParticleSystem::setActive(bool active){ this->active= active; + for(int i=getChildCount()-1; i>=0; i--) + getChild(i)->setActive(active); } void ParticleSystem::setObserver(ParticleObserver *particleObserver){ this->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); } // =============== MISC ========================= @@ -209,6 +221,8 @@ void ParticleSystem::fade(){ if(particleObserver != NULL){ particleObserver->update(this); } + for(int i=getChildCount()-1; i>=0; i--) + getChild(i)->fade(); } int ParticleSystem::isEmpty() const{ @@ -297,6 +311,8 @@ void ParticleSystem::setFactionColor(Vec3f factionColor){ if(teamcolorNoEnergy){ this->colorNoEnergy= Vec4f(factionColor.x, factionColor.y, factionColor.z, this->colorNoEnergy.w); } + for(int i=getChildCount()-1; i>=0; i--) + getChild(i)->setFactionColor(factionColor); } // =========================================================================== @@ -378,13 +394,132 @@ void FireParticleSystem::setWind(float windAngle, float windSpeed){ #endif } +// =========================================================================== +// 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 // =========================================================================== bool UnitParticleSystem::isNight= false; -UnitParticleSystem::UnitParticleSystem(int particleCount) : - ParticleSystem(particleCount){ +UnitParticleSystem::UnitParticleSystem(int particleCount): + GameParticleSystem(particleCount), + parent(NULL){ radius= 0.5f; speed= 0.01f; windSpeed= Vec3f(0.0f); @@ -393,8 +528,6 @@ UnitParticleSystem::UnitParticleSystem(int particleCount) : setColorNoEnergy(Vec4f(1.0f, 0.5f, 0.0f, 1.0f)); primitive= pQuad; - offset= Vec3f(0.0f); - direction= Vec3f(0.0f, 1.0f, 0.0f); gravity= 0.0f; fixed= false; @@ -413,6 +546,15 @@ UnitParticleSystem::UnitParticleSystem(int particleCount) : emissionState= (float) staticParticleCount; } energyUp= false; + + delay = 0; // none + lifetime = -1; // forever +} + +UnitParticleSystem::~UnitParticleSystem(){ + if(parent){ + parent->removeChild(this); + } } bool UnitParticleSystem::getVisible() const{ @@ -425,54 +567,48 @@ bool UnitParticleSystem::getVisible() const{ else return false; } -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); } -UnitParticleSystem::Primitive UnitParticleSystem::strToPrimitive(const string &str){ - if(str == "quad"){ - return pQuad; +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(); } - else if(str == "line"){ - return pLine; +} + +UnitParticleSystem::Shape UnitParticleSystem::strToShape(const string& str){ + if(str == "spherical"){ + return sSpherical; + } + else if(str == "conical"){ + return sConical; + } + else if(str == "linear"){ + return sLinear; } else{ - throw "Unknown particle primitive: " + str; + throw runtime_error("Unkown particle shape: " + str); } } void UnitParticleSystem::initParticle(Particle *p, int particleIndex){ ParticleSystem::initParticle(p, 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; if(radiusBasedStartenergy == true){ p->energy= static_cast (maxParticleEnergy * radRatio) + random.randRange(-varParticleEnergy, @@ -485,36 +621,72 @@ void UnitParticleSystem::initParticle(Particle *p, int particleIndex){ p->lastPos= pos; oldPosition= pos; 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"); } } 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){ fixedAddition= Vec3f(pos.x - oldPosition.x, pos.y - oldPosition.y, pos.z - oldPosition.z); oldPosition= pos; @@ -573,10 +745,6 @@ void UnitParticleSystem::updateParticle(Particle *p){ // ================= SET PARAMS ==================== -void UnitParticleSystem::setRadius(float radius){ - this->radius= radius; -} - void UnitParticleSystem::setWind(float windAngle, float windSpeed){ #ifdef USE_STREFLOP this->windSpeed.x= streflop::sinf(degToRad(windAngle))*windSpeed; @@ -700,43 +868,9 @@ 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; - } } // =========================================================================== @@ -775,7 +909,6 @@ void ProjectileParticleSystem::link(SplashParticleSystem *particleSystem){ } void ProjectileParticleSystem::update(){ - if(state == sPlay){ lastPos= pos; @@ -785,19 +918,7 @@ void ProjectileParticleSystem::update(){ // ratio 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()); // trajectory switch(trajectory) { @@ -833,10 +954,13 @@ void ProjectileParticleSystem::update(){ direction= pos - lastPos; direction.normalize(); + // trigger update of child particles + positionChildren(); + rotateChildren(); //arrive destination if(flatPos.dist(endPos) < 0.5f){ - state= sFade; + fade(); model= NULL; if(particleObserver != NULL){ @@ -854,6 +978,18 @@ void ProjectileParticleSystem::update(){ ParticleSystem::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){ ParticleSystem::initParticle(p, particleIndex); @@ -906,6 +1042,11 @@ void ProjectileParticleSystem::setPath(Vec3f startPos, Vec3f endPos){ // set members this->startPos= startPos; this->endPos= endPos; + + // direction + direction = (endPos - lastPos); + direction.normalize(); + rotateChildren(); } ProjectileParticleSystem::Trajectory ProjectileParticleSystem::strToTrajectory(const string &str){ @@ -919,7 +1060,7 @@ ProjectileParticleSystem::Trajectory ProjectileParticleSystem::strToTrajectory(c return tSpiral; } else{ - throw "Unknown particle system trajectory: " + str; + throw runtime_error("Unknown particle system trajectory: " + str); } } @@ -959,8 +1100,9 @@ void SplashParticleSystem::update() { if(state != sPause) { emissionRate-= emissionRateFade; - 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); if(emissionRate < 0.0f) {//otherwise this system lives forever! fade(); @@ -1132,7 +1274,10 @@ void ParticleManager::cleanupUnitParticleSystems(vector &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)); } void ParticleManager::end(){ diff --git a/source/shared_lib/sources/platform/common/cache_manager.cpp b/source/shared_lib/sources/platform/common/cache_manager.cpp index e708a6cc8..cad6862c1 100644 --- a/source/shared_lib/sources/platform/common/cache_manager.cpp +++ b/source/shared_lib/sources/platform/common/cache_manager.cpp @@ -13,7 +13,7 @@ namespace Shared { namespace PlatformCommon { -Mutex CacheManager::mutexCache; +//Mutex CacheManager::mutexCache; const char *CacheManager::getFolderTreeContentsCheckSumRecursivelyCacheLookupKey1 = "CRC_Cache_FileTree1"; const char *CacheManager::getFolderTreeContentsCheckSumRecursivelyCacheLookupKey2 = "CRC_Cache_FileTree2"; const char *CacheManager::getFolderTreeContentsCheckSumListRecursivelyCacheLookupKey1 = "CRC_Cache_FileTreeList1"; diff --git a/source/shared_lib/sources/xml/xml_parser.cpp b/source/shared_lib/sources/xml/xml_parser.cpp index c6cfe6bf4..90df91699 100644 --- a/source/shared_lib/sources/xml/xml_parser.cpp +++ b/source/shared_lib/sources/xml/xml_parser.cpp @@ -13,6 +13,8 @@ #include #include +#include +#include #include "conversion.h" #include @@ -23,6 +25,7 @@ #include "properties.h" #include "platform_common.h" #include "platform_util.h" +#include "cache_manager.h" #include "leak_dumper.h" @@ -172,7 +175,26 @@ void XmlTree::init(const string &name){ this->rootNode= new XmlNode(name); } +typedef std::vector LoadStack; +static LoadStack loadStack; +//static string loadStackCacheName = string(__FILE__) + string("_loadStackCacheName"); + void XmlTree::load(const string &path, std::map mapTagReplacementValues) { + //printf("XmlTree::load p [%p]\n",this); + assert(!loadPath.size()); + + //LoadStack &loadStack = CacheManager::getCachedItem(loadStackCacheName); + //Mutex &mutex = CacheManager::getMutexForItem(loadStackCacheName); + //MutexSafeWrapper safeMutex(&mutex); + + for(LoadStack::iterator it= loadStack.begin(); it!= loadStack.end(); it++){ + if((*it)->loadPath == path){ + throw runtime_error(path + " recursively included"); + } + } + loadStack.push_back(this); + + loadPath = path; this->rootNode= XmlIo::getInstance().load(path, mapTagReplacementValues); } @@ -180,7 +202,17 @@ void XmlTree::save(const string &path){ XmlIo::getInstance().save(path, rootNode); } -XmlTree::~XmlTree(){ +XmlTree::~XmlTree() { + //printf("XmlTree::~XmlTree p [%p]\n",this); + + //LoadStack &loadStack = CacheManager::getCachedItem(loadStackCacheName); + //Mutex &mutex = CacheManager::getMutexForItem(loadStackCacheName); + //MutexSafeWrapper safeMutex(&mutex); + + LoadStack::iterator it= find(loadStack.begin(),loadStack.end(),this); + if(it != loadStack.end()) { + loadStack.erase(it); + } delete rootNode; } @@ -188,7 +220,7 @@ XmlTree::~XmlTree(){ // class XmlNode // ===================================================== -XmlNode::XmlNode(DOMNode *node, std::map mapTagReplacementValues) { +XmlNode::XmlNode(DOMNode *node, std::map mapTagReplacementValues): superNode(NULL) { if(node == NULL || node->getNodeName() == NULL) { throw runtime_error("XML structure seems to be corrupt!"); } @@ -235,7 +267,7 @@ XmlNode::XmlNode(DOMNode *node, std::map mapTagReplacementValues) } } -XmlNode::XmlNode(const string &name) { +XmlNode::XmlNode(const string &name): superNode(NULL) { this->name= name; } @@ -269,6 +301,7 @@ XmlAttribute *XmlNode::getAttribute(const string &name,bool mustExist) const { } XmlNode *XmlNode::getChild(unsigned int i) const { + assert(!superNode); if(i >= children.size()) { throw runtime_error("\"" + getName()+"\" node doesn't have "+intToStr(i+1)+" children"); } @@ -287,6 +320,8 @@ vector 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()){ throw runtime_error("\"" + name + "\" node doesn't have "+intToStr(i+1)+" children named \"" + childName + "\"\n\nTree: "+getTreeString()); } @@ -305,6 +340,8 @@ 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; for(unsigned int j = 0; j < children.size(); ++j) { if(children[j]->getName()==childName) { @@ -318,19 +355,22 @@ bool XmlNode::hasChildAtIndex(const string &childName, int i) const { return false; } - bool XmlNode::hasChild(const string &childName) const { + return hasChildNoSuper(childName) || (superNode && superNode->hasChild(childName)); +} + +bool XmlNode::hasChildNoSuper(const string &childName) const { int count= 0; for(unsigned int j = 0; j < children.size(); ++j) { if(children[j]->getName() == childName) { return true; } } - return false; } XmlNode *XmlNode::addChild(const string &name){ + assert(!superNode); XmlNode *node= new XmlNode(name); children.push_back(node); return node;