// ============================================================== // This file is part of Glest (www.glest.org) // // Copyright (C) 2010-2010 Titus Tscharntke // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published // by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version // ============================================================== #include "particle_type.h" #include "unit_particle_type.h" #include "util.h" #include "core_data.h" #include "xml_parser.h" #include "model.h" #include "config.h" #include "game_constants.h" #include "util.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{ // ===================================================== // class ParticleSystemType // ===================================================== const bool checkMemory = false; static map memoryObjectList; ParticleSystemType::ParticleSystemType() { if(checkMemory) { printf("++ Create ParticleSystemType [%p]\n",this); memoryObjectList[this]++; } teamcolorNoEnergy=false; teamcolorEnergy=false; alternations=false; texture=NULL; model=NULL; minmaxEnabled=false; minHp=0; maxHp=0; minmaxIsPercent=false; } ParticleSystemType::ParticleSystemType(const ParticleSystemType &src) { if(checkMemory) { printf("++ Create ParticleSystemType #2 [%p]\n",this); memoryObjectList[this]++; } copyAll(src); } ParticleSystemType & ParticleSystemType::operator=(const ParticleSystemType &src) { if(checkMemory) { printf("++ Create ParticleSystemType #3 [%p]\n",this); memoryObjectList[this]++; } copyAll(src); return *this; } ParticleSystemType::~ParticleSystemType() { if(checkMemory) { printf("-- Delete ParticleSystemType [%p] type = [%s]\n",this,type.c_str()); memoryObjectList[this]--; assert(memoryObjectList[this] == 0); } for(Children::iterator it = children.begin(); it != children.end(); ++it) delete *it; } void ParticleSystemType::copyAll(const ParticleSystemType &src) { this->type = src.type; this->texture = src.texture; this->model = src.model; this->modelCycle = src.modelCycle; this->primitive = src.primitive; this->offset = src.offset; this->color = src.color; this->colorNoEnergy = src.colorNoEnergy; this->size = src.size; this->sizeNoEnergy = src.sizeNoEnergy; this->speed = src.speed; this->gravity = src.gravity; this->emissionRate = src.emissionRate; this->energyMax = src.energyMax; this->energyVar = src.energyVar; this->mode = src.mode; this->teamcolorNoEnergy = src.teamcolorNoEnergy; this->teamcolorEnergy = src.teamcolorEnergy; this->alternations = src.alternations; for(Children::iterator it = children.begin(); it != children.end(); ++it) { UnitParticleSystemType *child = *it; // Deep copy the child particles UnitParticleSystemType *newCopy = new UnitParticleSystemType(); *newCopy = *child; children.push_back(newCopy); } this->minmaxEnabled = src.minmaxEnabled; this->minHp = src.minHp; this->maxHp = src.maxHp; this->minmaxIsPercent = src.minmaxIsPercent; } 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(); if(textureEnabled){ texture= renderer->newTexture2D(rsGame); if(texture) { if(textureNode->getAttribute("luminance")->getBoolValue()){ texture->setFormat(Texture::fAlpha); texture->getPixmap()->init(1); } else{ texture->getPixmap()->init(4); } } string currentPath = dir; endPathWithSlash(currentPath); if(texture) { texture->load(textureNode->getAttribute("path")->getRestrictedValue(currentPath)); } loadedFileList[textureNode->getAttribute("path")->getRestrictedValue(currentPath)].push_back(make_pair(parentLoader,textureNode->getAttribute("path")->getRestrictedValue())); } else { texture= NULL; } //model if(particleSystemNode->hasChild("model")){ const XmlNode *modelNode= particleSystemNode->getChild("model"); bool modelEnabled= modelNode->getAttribute("value")->getBoolValue(); if(modelEnabled) { string currentPath = dir; endPathWithSlash(currentPath); string path= modelNode->getAttribute("path")->getRestrictedValue(currentPath); model= renderer->newModel(rsGame); if(model) { 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 { model= NULL; } //primitive const XmlNode *primitiveNode= particleSystemNode->getChild("primitive"); primitive= primitiveNode->getAttribute("value")->getRestrictedValue(); //offset const XmlNode *offsetNode= particleSystemNode->getChild("offset"); offset.x= offsetNode->getAttribute("x")->getFloatValue(); offset.y= offsetNode->getAttribute("y")->getFloatValue(); offset.z= offsetNode->getAttribute("z")->getFloatValue(); //color const XmlNode *colorNode= particleSystemNode->getChild("color"); color.x= colorNode->getAttribute("red")->getFloatValue(0.f, 1.0f); color.y= colorNode->getAttribute("green")->getFloatValue(0.f, 1.0f); color.z= colorNode->getAttribute("blue")->getFloatValue(0.f, 1.0f); color.w= colorNode->getAttribute("alpha")->getFloatValue(0.f, 1.0f); //color const XmlNode *colorNoEnergyNode= particleSystemNode->getChild("color-no-energy"); colorNoEnergy.x= colorNoEnergyNode->getAttribute("red")->getFloatValue(0.f, 1.0f); colorNoEnergy.y= colorNoEnergyNode->getAttribute("green")->getFloatValue(0.f, 1.0f); colorNoEnergy.z= colorNoEnergyNode->getAttribute("blue")->getFloatValue(0.f, 1.0f); colorNoEnergy.w= colorNoEnergyNode->getAttribute("alpha")->getFloatValue(0.f, 1.0f); //size const XmlNode *sizeNode= particleSystemNode->getChild("size"); size= sizeNode->getAttribute("value")->getFloatValue(); //sizeNoEnergy const XmlNode *sizeNoEnergyNode= particleSystemNode->getChild("size-no-energy"); sizeNoEnergy= sizeNoEnergyNode->getAttribute("value")->getFloatValue(); //speed const XmlNode *speedNode= particleSystemNode->getChild("speed"); speed= speedNode->getAttribute("value")->getFloatValue()/GameConstants::updateFps; //gravity const XmlNode *gravityNode= particleSystemNode->getChild("gravity"); gravity= gravityNode->getAttribute("value")->getFloatValue()/GameConstants::updateFps; //emission rate const XmlNode *emissionRateNode= particleSystemNode->getChild("emission-rate"); emissionRate= emissionRateNode->getAttribute("value")->getFloatValue(); //energy max const XmlNode *energyMaxNode= particleSystemNode->getChild("energy-max"); energyMax= energyMaxNode->getAttribute("value")->getIntValue(); //speed const XmlNode *energyVarNode= particleSystemNode->getChild("energy-var"); energyVar= energyVarNode->getAttribute("value")->getIntValue(); //teamcolorNoEnergy if(particleSystemNode->hasChild("teamcolorNoEnergy")){ const XmlNode *teamcolorNoEnergyNode= particleSystemNode->getChild("teamcolorNoEnergy"); teamcolorNoEnergy= teamcolorNoEnergyNode->getAttribute("value")->getBoolValue(); } //teamcolorEnergy if(particleSystemNode->hasChild("teamcolorEnergy")){ const XmlNode *teamcolorEnergyNode= particleSystemNode->getChild("teamcolorEnergy"); teamcolorEnergy= teamcolorEnergyNode->getAttribute("value")->getBoolValue(); } //alternations if(particleSystemNode->hasChild("alternations")){ const XmlNode *alternatingNode= particleSystemNode->getChild("alternations"); alternations= alternatingNode->getAttribute("value")->getIntValue(); } //mode if(particleSystemNode->hasChild("mode")) { const XmlNode *modeNode= particleSystemNode->getChild("mode"); mode= modeNode->getAttribute("value")->getRestrictedValue(); } 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); ats->setColor(color); ats->setColorNoEnergy(colorNoEnergy); ats->setSpeed(speed); ats->setGravity(gravity); ats->setParticleSize(size); ats->setSizeNoEnergy(sizeNoEnergy); ats->setEmissionRate(emissionRate); ats->setMaxParticleEnergy(energyMax); ats->setVarParticleEnergy(energyVar); ats->setModel(model); ats->setModelCycle(modelCycle); ats->setTeamcolorNoEnergy(teamcolorNoEnergy); ats->setTeamcolorEnergy(teamcolorEnergy); ats->setAlternations(alternations); ats->setBlendMode(ParticleSystem::strToBlendMode(mode)); } // =========================================================== // class ParticleSystemTypeProjectile // =========================================================== ParticleSystemTypeProjectile::ParticleSystemTypeProjectile() : ParticleSystemType() { trajectorySpeed = 0.0f; trajectoryScale = 0.0f; trajectoryFrequency = 0.0f; } void ParticleSystemTypeProjectile::load(const XmlNode* particleFileNode, const string &dir, const string &path, RendererInterface *renderer, std::map > > &loadedFileList, string parentLoader, string techtreePath) { try{ XmlTree xmlTree; std::map mapExtraTagReplacementValues; mapExtraTagReplacementValues["$COMMONDATAPATH"] = techtreePath + "/commondata/"; xmlTree.load(path, Properties::getTagReplacementValues(&mapExtraTagReplacementValues)); 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); //trajectory values const XmlNode *tajectoryNode= particleSystemNode->getChild("trajectory"); trajectory= tajectoryNode->getAttribute("type")->getRestrictedValue(); //trajectory speed const XmlNode *tajectorySpeedNode= tajectoryNode->getChild("speed"); trajectorySpeed= tajectorySpeedNode->getAttribute("value")->getFloatValue()/GameConstants::updateFps; if(trajectory=="parabolic" || trajectory=="spiral"){ //trajectory scale const XmlNode *tajectoryScaleNode= tajectoryNode->getChild("scale"); trajectoryScale= tajectoryScaleNode->getAttribute("value")->getFloatValue(); } else{ trajectoryScale= 1.0f; } if(trajectory=="spiral"){ //trajectory frequency const XmlNode *tajectoryFrequencyNode= tajectoryNode->getChild("frequency"); trajectoryFrequency= tajectoryFrequencyNode->getAttribute("value")->getFloatValue(); } else{ trajectoryFrequency= 1.0f; } } catch(const exception &e){ SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,e.what()); throw runtime_error("Error loading ParticleSystem: "+ path + "\n" +e.what()); } } ProjectileParticleSystem *ParticleSystemTypeProjectile::create() { ProjectileParticleSystem *ps= new ProjectileParticleSystem(); ParticleSystemType::setValues(ps); ps->setTrajectory(ProjectileParticleSystem::strToTrajectory(trajectory)); ps->setTrajectorySpeed(trajectorySpeed); ps->setTrajectoryScale(trajectoryScale); ps->setTrajectoryFrequency(trajectoryFrequency); ps->initParticleSystem(); return ps; } // =========================================================== // class ParticleSystemTypeSplash // =========================================================== ParticleSystemTypeSplash::ParticleSystemTypeSplash() { emissionRateFade = 0.0f; verticalSpreadA = 0.0f; verticalSpreadB = 0.0f; horizontalSpreadA = 0.0f; horizontalSpreadB = 0.0f; } void ParticleSystemTypeSplash::load(const XmlNode* particleFileNode, const string &dir, const string &path, RendererInterface *renderer, std::map > > &loadedFileList, string parentLoader, string techtreePath) { try{ XmlTree xmlTree; std::map mapExtraTagReplacementValues; mapExtraTagReplacementValues["$COMMONDATAPATH"] = techtreePath + "/commondata/"; xmlTree.load(path, Properties::getTagReplacementValues(&mapExtraTagReplacementValues)); 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); //emission rate fade const XmlNode *emissionRateFadeNode= particleSystemNode->getChild("emission-rate-fade"); emissionRateFade= emissionRateFadeNode->getAttribute("value")->getFloatValue(); //spread values const XmlNode *verticalSpreadNode= particleSystemNode->getChild("vertical-spread"); verticalSpreadA= verticalSpreadNode->getAttribute("a")->getFloatValue(0.0f, 1.0f); verticalSpreadB= verticalSpreadNode->getAttribute("b")->getFloatValue(-1.0f, 1.0f); const XmlNode *horizontalSpreadNode= particleSystemNode->getChild("horizontal-spread"); horizontalSpreadA= horizontalSpreadNode->getAttribute("a")->getFloatValue(0.0f, 1.0f); horizontalSpreadB= horizontalSpreadNode->getAttribute("b")->getFloatValue(-1.0f, 1.0f); } catch(const exception &e){ SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,e.what()); throw runtime_error("Error loading ParticleSystem: "+ path + "\n" +e.what()); } } SplashParticleSystem *ParticleSystemTypeSplash::create(){ SplashParticleSystem *ps= new SplashParticleSystem(); ParticleSystemType::setValues(ps); ps->setEmissionRateFade(emissionRateFade); ps->setVerticalSpreadA(verticalSpreadA); ps->setVerticalSpreadB(verticalSpreadB); ps->setHorizontalSpreadA(horizontalSpreadA); ps->setHorizontalSpreadB(horizontalSpreadB); ps->initParticleSystem(); return ps; } }}//end mamespace