diff --git a/source/glest_game/graphics/unit_particle_type.cpp b/source/glest_game/graphics/unit_particle_type.cpp new file mode 100644 index 00000000..1b2456e5 --- /dev/null +++ b/source/glest_game/graphics/unit_particle_type.cpp @@ -0,0 +1,204 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Marti�o Figueroa +// +// 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 "unit_particle_type.h" + +#include "util.h" +#include "core_data.h" +#include "xml_parser.h" +#include "renderer.h" +#include "config.h" +#include "game_constants.h" + +#include "leak_dumper.h" + +using namespace Shared::Xml; +using namespace Shared::Graphics; + +namespace Glest{ namespace Game{ + +// ===================================================== +// class UnitParticleSystemType +// ===================================================== + +UnitParticleSystemType::UnitParticleSystemType(){ +} + +void UnitParticleSystemType::load(const XmlNode *particleSystemNode, const string &dir){ + + Renderer &renderer= Renderer::getInstance(); + + //texture + const XmlNode *textureNode= particleSystemNode->getChild("texture"); + bool textureEnabled= textureNode->getAttribute("value")->getBoolValue(); + if(textureEnabled){ + texture= renderer.newTexture2D(rsGame); + if(textureNode->getAttribute("luminance")->getBoolValue()){ + texture->setFormat(Texture::fAlpha); + texture->getPixmap()->init(1); + } + else{ + texture->getPixmap()->init(4); + } + texture->load(dir + "/" + textureNode->getAttribute("path")->getRestrictedValue()); + } + else{ + texture= 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(); + + //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(); + + //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); + + //radius + const XmlNode *radiusNode= particleSystemNode->getChild("radius"); + radius= radiusNode->getAttribute("value")->getFloatValue(); + + //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")->getIntValue(); + + //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(); + + //relative + const XmlNode *relativeNode= particleSystemNode->getChild("relative"); + relative= relativeNode->getAttribute("value")->getBoolValue(); + + //relativeDirection + if(particleSystemNode->hasChild("relativeDirection")){ + const XmlNode *relativeDirectionNode= particleSystemNode->getChild("relativeDirection"); + relativeDirection= relativeDirectionNode->getAttribute("value")->getBoolValue(); + } + else{ + relativeDirection=true; + } + + //fixed + const XmlNode *fixedNode= particleSystemNode->getChild("fixed"); + fixed= fixedNode->getAttribute("value")->getBoolValue(); + + //teamcolorNoEnergy + if(particleSystemNode->hasChild("teamcolorNoEnergy")){ + const XmlNode *teamcolorNoEnergyNode= particleSystemNode->getChild("teamcolorNoEnergy"); + teamcolorNoEnergy= teamcolorNoEnergyNode->getAttribute("value")->getBoolValue(); + } + else{ + teamcolorNoEnergy=false; + } + + + //teamcolorEnergy + if(particleSystemNode->hasChild("teamcolorEnergy")){ + const XmlNode *teamcolorEnergyNode= particleSystemNode->getChild("teamcolorEnergy"); + teamcolorEnergy= teamcolorEnergyNode->getAttribute("value")->getBoolValue(); + } + else{ + teamcolorEnergy=false; + } + + //mode + if(particleSystemNode->hasChild("mode")){ + const XmlNode *modeNode= particleSystemNode->getChild("mode"); + mode= modeNode->getAttribute("value")->getRestrictedValue(); + } + else + { + mode="normal"; + } +} + +void UnitParticleSystemType::setValues(UnitParticleSystem *ups){ + ups->setTexture(texture); + ups->setPrimitive(UnitParticleSystem::strToPrimitive(primitive)); + ups->setOffset(offset); + ups->setDirection(direction); + ups->setColor(color); + ups->setColorNoEnergy(colorNoEnergy); + ups->setSpeed(speed); + ups->setGravity(gravity); + ups->setParticleSize(size); + ups->setSizeNoEnergy(sizeNoEnergy); + ups->setEmissionRate(emissionRate); + ups->setMaxParticleEnergy(energyMax); + ups->setVarParticleEnergy(energyVar); + ups->setFixed(fixed); + ups->setRelative(relative); + ups->setRelativeDirection(relativeDirection); + ups->setTeamcolorNoEnergy(teamcolorNoEnergy); + ups->setTeamcolorEnergy(teamcolorEnergy); + ups->setRadius(radius); + ups->setBlendMode(ParticleSystem::strToBlendMode(mode)); +} + +void UnitParticleSystemType::load(const string &dir, const string &path){ + + try{ + XmlTree xmlTree; + xmlTree.load(path); + const XmlNode *particleSystemNode= xmlTree.getRootNode(); + + UnitParticleSystemType::load(particleSystemNode, dir); + } + catch(const exception &e){ + throw runtime_error("Error loading ParticleSystem: "+ path + "\n" +e.what()); + } +} + + +}}//end mamespace diff --git a/source/glest_game/graphics/unit_particle_type.h b/source/glest_game/graphics/unit_particle_type.h new file mode 100644 index 00000000..c2da33e2 --- /dev/null +++ b/source/glest_game/graphics/unit_particle_type.h @@ -0,0 +1,74 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Marti�o Figueroa +// +// 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 +// ============================================================== + +#ifndef _GLEST_GAME_UNITPARTICLETYPE_H_ +#define _GLEST_GAME_UNITPARTICLETYPE_H_ + +#include + +#include "particle.h" +#include "factory.h" +#include "texture.h" +#include "vec.h" +#include "xml_parser.h" + +using std::string; + +namespace Glest{ namespace Game{ + +using Shared::Graphics::ParticleSystem; +using Shared::Graphics::UnitParticleSystem; +using Shared::Graphics::Texture2D; +using Shared::Graphics::Vec3f; +using Shared::Graphics::Vec4f; +using Shared::Util::MultiFactory; +using Shared::Xml::XmlNode; + +// =========================================================== +// class ParticleSystemType +// +/// A type of particle system +// =========================================================== + +class UnitParticleSystemType{ +protected: + string type; + Texture2D *texture; + string primitive; + Vec3f offset; + Vec3f direction; + Vec4f color; + Vec4f colorNoEnergy; + float radius; + float size; + float sizeNoEnergy; + float speed; + float gravity; + int emissionRate; + int energyMax; + int energyVar; + bool relative; + bool relativeDirection; + bool fixed; + bool teamcolorNoEnergy; + bool teamcolorEnergy; + string mode; + +public: + UnitParticleSystemType(); + void load(const XmlNode *particleSystemNode, const string &dir); + void load(const string &dir, const string &path); + void setValues(UnitParticleSystem *uts); +}; + +}}//end namespace + +#endif diff --git a/source/glest_game/gui/gui.cpp b/source/glest_game/gui/gui.cpp index eb466114..ec96a87c 100644 --- a/source/glest_game/gui/gui.cpp +++ b/source/glest_game/gui/gui.cpp @@ -2,7 +2,7 @@ // ============================================================== // This file is part of Glest (www.glest.org) // -// Copyright (C) 2001-2008 Martiño Figueroa +// Copyright (C) 2001-2008 Marti�o Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published @@ -333,7 +333,9 @@ void Gui::hotKey(char key){ else if(key=='R'){ // Here the user triggers a unit rotation while placing a unit if(allowRotateUnits == true && isPlacingBuilding()) { - ++selectedBuildingFacing; + if(getBuilding()->getRotationAllowed()){ + ++selectedBuildingFacing; + } } else { selectInterestingUnit(iutProducer); diff --git a/source/glest_game/types/unit_type.cpp b/source/glest_game/types/unit_type.cpp index 1c3c504c..9af20761 100644 --- a/source/glest_game/types/unit_type.cpp +++ b/source/glest_game/types/unit_type.cpp @@ -244,6 +244,17 @@ void UnitType::load(int id,const string &dir, const TechTree *techTree, const Fa lightColor.z= lightNode->getAttribute("blue")->getFloatValue(0.f, 1.f); } + //rotationAllowed + if(parametersNode->hasChild("rotationAllowed")){ + const XmlNode *rotationAllowedNode= parametersNode->getChild("rotationAllowed"); + rotationAllowed= rotationAllowedNode->getAttribute("value")->getBoolValue(); + } + else + { + rotationAllowed=true; + } + + //unit requirements const XmlNode *unitRequirementsNode= parametersNode->getChild("unit-requirements"); for(int i=0; igetChildCount(); ++i){ diff --git a/source/glest_game/types/unit_type.h b/source/glest_game/types/unit_type.h index ebd092c1..7d69415e 100644 --- a/source/glest_game/types/unit_type.h +++ b/source/glest_game/types/unit_type.h @@ -97,6 +97,7 @@ private: int size; //size in cells int height; float rotatedBuildPos; + bool rotationAllowed; //cellmap bool *cellMap; @@ -143,6 +144,7 @@ public: int getCommandTypeCount() const {return commandTypes.size();} int getLevelCount() const {return levels.size();} bool getLight() const {return light;} + bool getRotationAllowed() const {return rotationAllowed;} Vec3f getLightColor() const {return lightColor;} bool getMultiSelect() const {return multiSelect;} int getSight() const {return sight;} diff --git a/source/shared_lib/include/graphics/particle.h b/source/shared_lib/include/graphics/particle.h new file mode 100644 index 00000000..f68b6a0c --- /dev/null +++ b/source/shared_lib/include/graphics/particle.h @@ -0,0 +1,437 @@ +// ============================================================== +// This file is part of Glest Shared Library (www.glest.org) +// +// Copyright (C) 2001-2008 Marti�o Figueroa +// +// 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 +// ============================================================== + +#ifndef _SHARED_GRAPHICS_PARTICLE_H_ +#define _SHARED_GRAPHICS_PARTICLE_H_ + +#include +#include + +#include "vec.h" +#include "pixmap.h" +#include "texture_manager.h" +#include "random.h" + +using std::list; +using Shared::Util::Random; + +namespace Shared{ namespace Graphics{ + +class ParticleSystem; +class FireParticleSystem; +class UnitParticleSystem; +class RainParticleSystem; +class SnowParticleSystem; +class ProjectileParticleSystem; +class SplashParticleSystem; +class ParticleRenderer; +class ModelRenderer; +class Model; + +// ===================================================== +// class Particle +// ===================================================== + +class Particle{ +public: + //attributes + Vec3f pos; + Vec3f lastPos; + Vec3f speed; + Vec3f accel; + Vec4f color; + float size; + int energy; + +public: + //get + Vec3f getPos() const {return pos;} + Vec3f getLastPos() const {return lastPos;} + Vec3f getSpeed() const {return speed;} + Vec3f getAccel() const {return accel;} + Vec4f getColor() const {return color;} + float getSize() const {return size;} + int getEnergy() const {return energy;} +}; + +class ParticleSystem; + +// ===================================================== +// class ParticleObserver +// ===================================================== + +class ParticleObserver{ +public: + virtual ~ParticleObserver(){}; + virtual void update(ParticleSystem *particleSystem)= 0; +}; + +// ===================================================== +// class ParticleSystem +// ===================================================== + +class ParticleSystem{ +public: + enum BlendMode{ + bmOne, + bmOneMinusAlpha + }; + +protected: + enum State{ + sPause, // No updates + sPlay, + sFade // No new particles + }; + +protected: + + Particle *particles; + Random random; + + BlendMode blendMode; + State state; + bool active; + bool visible; + int aliveParticleCount; + int particleCount; + + + Texture *texture; + Vec3f pos; + Vec4f color; + Vec4f colorNoEnergy; + int emissionRate; + int maxParticleEnergy; + int varParticleEnergy; + float particleSize; + float speed; + Vec3f factionColor; + bool teamcolorNoEnergy; + bool teamcolorEnergy; + + ParticleObserver *particleObserver; + +public: + //conmstructor and destructor + ParticleSystem(int particleCount); + virtual ~ParticleSystem(); + + //public + virtual void update(); + virtual void render(ParticleRenderer *pr, ModelRenderer *mr); + + //get + State getState() const {return state;} + BlendMode getBlendMode() const {return blendMode;} + Texture *getTexture() const {return texture;} + Vec3f getPos() const {return pos;} + Particle *getParticle(int i) {return &particles[i];} + const Particle *getParticle(int i) const {return &particles[i];} + int getAliveParticleCount() const {return aliveParticleCount;} + bool getActive() const {return active;} + bool getVisible() const {return visible;} + + //set + void setState(State state); + void setTexture(Texture *texture); + void setPos(Vec3f pos); + void setColor(Vec4f color); + void setColorNoEnergy(Vec4f color); + void setEmissionRate(int emissionRate); + void setMaxParticleEnergy(int maxParticleEnergy); + void setVarParticleEnergy(int varParticleEnergy); + void setParticleSize(float particleSize); + void setSpeed(float speed); + void setActive(bool active); + void setObserver(ParticleObserver *particleObserver); + 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;} + virtual void setFactionColor(Vec3f factionColor); + + static BlendMode strToBlendMode(const string &str); + //misc + void fade(); + int isEmpty() const; + +protected: + //protected + Particle *createParticle(); + void killParticle(Particle *p); + + //virtual protected + virtual void initParticle(Particle *p, int particleIndex); + virtual void updateParticle(Particle *p); + virtual bool deathTest(Particle *p); +}; + +// ===================================================== +// class FireParticleSystem +// ===================================================== + +class FireParticleSystem: public ParticleSystem{ +private: + float radius; + Vec3f windSpeed; + +public: + FireParticleSystem(int particleCount= 2000); + + //virtual + virtual void initParticle(Particle *p, int particleIndex); + virtual void updateParticle(Particle *p); + + //set params + void setRadius(float radius); + void setWind(float windAngle, float windSpeed); +}; + +// ===================================================== +// class UnitParticleSystem +// ===================================================== + +class UnitParticleSystem: public ParticleSystem{ +private: + float radius; + Vec3f windSpeed; + Vec3f cRotation; + Vec3f fixedAddition; + Vec3f oldPosition; +public: + enum Primitive{ + pQuad, + pLine, + pLineAlpha + }; + bool relative; + bool relativeDirection; + bool fixed; + Model *model; + Primitive primitive; + Vec3f offset; + Vec3f direction; + float sizeNoEnergy; + float gravity; + float rotation; + +public: + UnitParticleSystem(int particleCount= 2000); + + //virtual + virtual void initParticle(Particle *p, int particleIndex); + virtual void updateParticle(Particle *p); + virtual void update(); + virtual void render(ParticleRenderer *pr, ModelRenderer *mr); + + //set params + void setRadius(float radius); + void setWind(float windAngle, float windSpeed); + + void setOffset(Vec3f offset) {this->offset= offset;} + 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 setRelative(bool relative) {this->relative= relative;} + void setRelativeDirection(bool relativeDirection) {this->relativeDirection= relativeDirection;} + void setFixed(bool fixed) {this->fixed= fixed;} + void setPrimitive(Primitive primitive) {this->primitive= primitive;} + + static Primitive strToPrimitive(const string &str); + +}; + +// ===================================================== +// class RainParticleSystem +// ===================================================== + +class RainParticleSystem: public ParticleSystem{ +private: + Vec3f windSpeed; + float radius; + +public: + RainParticleSystem(int particleCount= 4000); + + virtual void render(ParticleRenderer *pr, ModelRenderer *mr); + + virtual void initParticle(Particle *p, int particleIndex); + virtual bool deathTest(Particle *p); + + void setRadius(float radius); + void setWind(float windAngle, float windSpeed); +}; + +// ===================================================== +// class SnowParticleSystem +// ===================================================== + +class SnowParticleSystem: public ParticleSystem{ +private: + Vec3f windSpeed; + float radius; + +public: + SnowParticleSystem(int particleCount= 4000); + + virtual void initParticle(Particle *p, int particleIndex); + virtual bool deathTest(Particle *p); + + void setRadius(float radius); + void setWind(float windAngle, float windSpeed); +}; + +// =========================================================================== +// AttackParticleSystem +// +/// Base class for Projectiles and Splashes +// =========================================================================== + +class AttackParticleSystem: public ParticleSystem{ +public: + enum Primitive{ + pQuad, + pLine, + pLineAlpha + }; + +protected: + Model *model; + Primitive primitive; + Vec3f offset; + float sizeNoEnergy; + float gravity; + + Vec3f direction; + +public: + AttackParticleSystem(int particleCount); + + 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;} + + static Primitive strToPrimitive(const string &str); +}; + +// ===================================================== +// class ProjectileParticleSystem +// ===================================================== + +class ProjectileParticleSystem: public AttackParticleSystem{ +public: + friend class SplashParticleSystem; + + enum Trajectory{ + tLinear, + tParabolic, + tSpiral + }; + +private: + SplashParticleSystem *nextParticleSystem; + + Vec3f lastPos; + Vec3f startPos; + Vec3f endPos; + Vec3f flatPos; + + Vec3f xVector; + Vec3f yVector; + Vec3f zVector; + + Trajectory trajectory; + float trajectorySpeed; + + //parabolic + float trajectoryScale; + float trajectoryFrequency; + +public: + ProjectileParticleSystem(int particleCount= 1000); + virtual ~ProjectileParticleSystem(); + + void link(SplashParticleSystem *particleSystem); + + virtual void update(); + virtual void initParticle(Particle *p, int particleIndex); + virtual void updateParticle(Particle *p); + + void setTrajectory(Trajectory trajectory) {this->trajectory= trajectory;} + void setTrajectorySpeed(float trajectorySpeed) {this->trajectorySpeed= trajectorySpeed;} + void setTrajectoryScale(float trajectoryScale) {this->trajectoryScale= trajectoryScale;} + void setTrajectoryFrequency(float trajectoryFrequency) {this->trajectoryFrequency= trajectoryFrequency;} + void setPath(Vec3f startPos, Vec3f endPos); + + static Trajectory strToTrajectory(const string &str); +}; + +// ===================================================== +// class SplashParticleSystem +// ===================================================== + +class SplashParticleSystem: public AttackParticleSystem{ +public: + friend class ProjectileParticleSystem; + +private: + ProjectileParticleSystem *prevParticleSystem; + + int emissionRateFade; + float verticalSpreadA; + float verticalSpreadB; + float horizontalSpreadA; + float horizontalSpreadB; + +public: + SplashParticleSystem(int particleCount= 1000); + virtual ~SplashParticleSystem(); + + virtual void update(); + virtual void initParticle(Particle *p, int particleIndex); + virtual void updateParticle(Particle *p); + + void setEmissionRateFade(int emissionRateFade) {this->emissionRateFade= emissionRateFade;} + void setVerticalSpreadA(float verticalSpreadA) {this->verticalSpreadA= verticalSpreadA;} + void setVerticalSpreadB(float verticalSpreadB) {this->verticalSpreadB= verticalSpreadB;} + void setHorizontalSpreadA(float horizontalSpreadA) {this->horizontalSpreadA= horizontalSpreadA;} + void setHorizontalSpreadB(float horizontalSpreadB) {this->horizontalSpreadB= horizontalSpreadB;} + +}; + +// ===================================================== +// class ParticleManager +// ===================================================== + +class ParticleManager{ +private: + list particleSystems; + +public: + ~ParticleManager(); + void update(); + void render(ParticleRenderer *pr, ModelRenderer *mr) const; + void manage(ParticleSystem *ps); + void end(); +}; + +}}//end namespace + +#endif diff --git a/source/shared_lib/sources/graphics/particle.cpp b/source/shared_lib/sources/graphics/particle.cpp new file mode 100644 index 00000000..d78a1818 --- /dev/null +++ b/source/shared_lib/sources/graphics/particle.cpp @@ -0,0 +1,859 @@ +// ============================================================== +// This file is part of Glest Shared Library (www.glest.org) +// +// Copyright (C) 2001-2008 Marti�o Figueroa +// +// 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.h" + +#include +#include + +#include "util.h" +#include "particle_renderer.h" +#include "math_util.h" +#include "leak_dumper.h" + +using namespace Shared::Util; + +namespace Shared{ namespace Graphics{ + +// ===================================================== +// class ParticleSystem +// ===================================================== + +ParticleSystem::ParticleSystem(int particleCount){ + + //init particle vector + blendMode = bmOne; + particles= new Particle[particleCount]; + state= sPlay; + aliveParticleCount=0; + active= true; + visible= true; + + //vars + texture= NULL; + particleObserver= NULL; + + //params + this->particleCount= particleCount; + maxParticleEnergy= 250; + varParticleEnergy= 50; + pos= Vec3f(0.0f); + color= Vec4f(1.0f); + colorNoEnergy= Vec4f(0.0f); + emissionRate= 15; + speed= 1.0f; + teamcolorNoEnergy=false; + teamcolorEnergy=false; +} + +ParticleSystem::~ParticleSystem(){ + delete [] particles; +} + + +// =============== VIRTUAL ====================== + +//updates all living particles and creates new ones +void ParticleSystem::update(){ + + if(state!=sPause){ + for(int i=0; i0){ + particles[i]= particles[aliveParticleCount]; + } + + } + } + + if(state!=sFade){ + for(int i=0; irenderSystem(this); + } +} + +ParticleSystem::BlendMode ParticleSystem::strToBlendMode(const string &str){ + if(str=="normal"){ + return bmOne; + } + else if(str=="black"){ + return bmOneMinusAlpha; + } + else{ + throw "Unknown particle mode: " + str; + } +} + + +// =============== SET ========================== + +void ParticleSystem::setState(State state){ + this->state= state; +} + +void ParticleSystem::setTexture(Texture *texture){ + this->texture= texture; +} + +void ParticleSystem::setPos(Vec3f pos){ + this->pos= pos; +} + +void ParticleSystem::setColor(Vec4f color){ + this->color= color; +} + +void ParticleSystem::setColorNoEnergy(Vec4f colorNoEnergy){ + this->colorNoEnergy= colorNoEnergy; +} + +void ParticleSystem::setEmissionRate(int emissionRate){ + this->emissionRate= emissionRate; +} + +void ParticleSystem::setMaxParticleEnergy(int maxParticleEnergy){ + this->maxParticleEnergy= maxParticleEnergy; +} + +void ParticleSystem::setVarParticleEnergy(int varParticleEnergy){ + this->varParticleEnergy= varParticleEnergy; +} + +void ParticleSystem::setParticleSize(float particleSize){ + this->particleSize= particleSize; +} + +void ParticleSystem::setSpeed(float speed){ + this->speed= speed; +} + +void ParticleSystem::setActive(bool active){ + this->active= active; +} + +void ParticleSystem::setObserver(ParticleObserver *particleObserver){ + this->particleObserver= particleObserver; +} + +void ParticleSystem::setVisible(bool visible){ + this->visible= visible; +} + +// =============== MISC ========================= +void ParticleSystem::fade(){ + assert(state==sPlay); + state= sFade; + if(particleObserver!=NULL){ + particleObserver->update(this); + } +} + +int ParticleSystem::isEmpty() const{ + assert(aliveParticleCount>=0); + return aliveParticleCount==0 && state!=sPause; +} + +// =============== PROTECTED ========================= + +// if there is one dead particle it returns it else, return the particle with +// less energy +Particle * ParticleSystem::createParticle(){ + + //if any dead particles + if(aliveParticleCountpos= pos; + p->lastPos= p->pos; + p->speed= Vec3f(0.0f); + p->accel= Vec3f(0.0f); + p->color= Vec4f(1.0f, 1.0f, 1.0f, 1.0); + p->size= particleSize; + p->energy= maxParticleEnergy + random.randRange(-varParticleEnergy, varParticleEnergy); +} + +void ParticleSystem::updateParticle(Particle *p){ + p->lastPos= p->pos; + p->pos= p->pos + p->speed; + p->speed= p->speed + p->accel; + p->energy--; +} + +bool ParticleSystem::deathTest(Particle *p){ + return p->energy <= 0; +} + +void ParticleSystem::killParticle(Particle *p){ + aliveParticleCount--; +} + +void ParticleSystem::setFactionColor(Vec3f factionColor){ + this->factionColor=factionColor; + Vec3f tmpCol; + + if(teamcolorEnergy) + { + this->color=Vec4f(factionColor.x,factionColor.y,factionColor.z,this->color.w); + } + if(teamcolorNoEnergy) + { + this->colorNoEnergy=Vec4f(factionColor.x,factionColor.y,factionColor.z,this->colorNoEnergy.w); + } +} + + +// =========================================================================== +// FireParticleSystem +// =========================================================================== + + +FireParticleSystem::FireParticleSystem(int particleCount): ParticleSystem(particleCount){ + + radius= 0.5f; + speed= 0.01f; + windSpeed= Vec3f(0.0f); + + setParticleSize(0.6f); + setColorNoEnergy(Vec4f(1.0f, 0.5f, 0.0f, 1.0f)); +} + +void FireParticleSystem::initParticle(Particle *p, int particleIndex){ + ParticleSystem::initParticle(p, particleIndex); + + float ang= random.randRange(-2.0f*pi, 2.0f*pi); + float mod= fabsf(random.randRange(-radius, radius)); + + float x= sinf(ang)*mod; + float y= cosf(ang)*mod; + + float radRatio= sqrtf(sqrtf(mod/radius)); + + p->color= colorNoEnergy*0.5f + colorNoEnergy*0.5f*radRatio; + p->energy= static_cast(maxParticleEnergy*radRatio) + random.randRange(-varParticleEnergy, varParticleEnergy); + p->pos= Vec3f(pos.x+x, pos.y+random.randRange(-radius/2, radius/2), pos.z+y); + p->lastPos= pos; + p->size= particleSize; + p->speed= Vec3f(0, speed+speed*random.randRange(-0.5f, 0.5f), 0) + windSpeed; +} + +void FireParticleSystem::updateParticle(Particle *p){ + p->lastPos= p->pos; + p->pos= p->pos+p->speed; + p->energy--; + + if(p->color.x>0.0f) + p->color.x*= 0.98f; + if(p->color.y>0.0f) + p->color.y*= 0.98f; + if(p->color.w>0.0f) + p->color.w*= 0.98f; + + p->speed.x*=1.001f; + +} + +// ================= SET PARAMS ==================== + +void FireParticleSystem::setRadius(float radius){ + this->radius= radius; +} + +void FireParticleSystem::setWind(float windAngle, float windSpeed){ + this->windSpeed.x= sinf(degToRad(windAngle))*windSpeed; + this->windSpeed.y= 0.0f; + this->windSpeed.z= cosf(degToRad(windAngle))*windSpeed; +} + + +// =========================================================================== +// UnitParticleSystem +// =========================================================================== + +UnitParticleSystem::UnitParticleSystem(int particleCount): ParticleSystem(particleCount){ + + radius= 0.5f; + speed= 0.01f; + windSpeed= Vec3f(0.0f); + + setParticleSize(0.6f); + 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; + rotation=0.0f; + relativeDirection=true; + + cRotation= Vec3f(1.0f,1.0f,1.0f); + fixedAddition = Vec3f(0.0f,0.0f,0.0f); + +} + +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); + } + //} +} + +UnitParticleSystem::Primitive UnitParticleSystem::strToPrimitive(const string &str){ + if(str=="quad"){ + return pQuad; + } + else if(str=="line"){ + return pLine; + } + else{ + throw "Unknown particle primitive: " + str; + } +} + + +void UnitParticleSystem::initParticle(Particle *p, int particleIndex){ + ParticleSystem::initParticle(p, particleIndex); + + float ang= random.randRange(-2.0f*pi, 2.0f*pi); + float mod= fabsf(random.randRange(-radius, radius)); + + float x= sinf(ang)*mod; + float y= cosf(ang)*mod; + + float radRatio= sqrtf(sqrtf(mod/radius)); + + //p->color= color*0.5f + color*0.5f*radRatio; + p->color=color; + p->energy= static_cast(maxParticleEnergy*radRatio) + random.randRange(-varParticleEnergy, varParticleEnergy); + + 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){ + 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); + 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){ + 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))); + } + } +} + +void UnitParticleSystem::update(){ + if(fixed) + { + fixedAddition= Vec3f(pos.x-oldPosition.x,pos.y-oldPosition.y,pos.z-oldPosition.z); + oldPosition=pos; + } + ParticleSystem::update(); +} + +void UnitParticleSystem::updateParticle(Particle *p){ + + float energyRatio= clamp(static_cast(p->energy)/maxParticleEnergy, 0.f, 1.f); + + p->lastPos+= p->speed; + p->pos+= p->speed; + if(fixed) + { + p->lastPos+= fixedAddition; + p->pos+= fixedAddition; + } + p->speed+= p->accel; + p->color = color * energyRatio + colorNoEnergy * (1.0f-energyRatio); + p->size = particleSize * energyRatio + sizeNoEnergy * (1.0f-energyRatio); + p->energy--; + + /* + p->lastPos= p->pos; + p->pos= p->pos+p->speed; + p->energy--; + + if(p->color.x>0.0f) + p->color.x*= 0.98f; + if(p->color.y>0.0f) + p->color.y*= 0.98f; + if(p->color.w>0.0f) + p->color.w*= 0.98f; + + p->speed.x*=1.001f; + */ + +} + +// ================= SET PARAMS ==================== + +void UnitParticleSystem::setRadius(float radius){ + this->radius= radius; +} + +void UnitParticleSystem::setWind(float windAngle, float windSpeed){ + this->windSpeed.x= sinf(degToRad(windAngle))*windSpeed; + this->windSpeed.y= 0.0f; + this->windSpeed.z= cosf(degToRad(windAngle))*windSpeed; +} + + + + +// =========================================================================== +// RainParticleSystem +// =========================================================================== + + +RainParticleSystem::RainParticleSystem(int particleCount):ParticleSystem(particleCount){ + setWind(0.0f, 0.0f); + setRadius(20.0f); + + setEmissionRate(25); + setParticleSize(3.0f); + setColor(Vec4f(0.5f, 0.5f, 0.5f, 0.3f)); + setSpeed(0.2f); +} + +void RainParticleSystem::render(ParticleRenderer *pr, ModelRenderer *mr){ + pr->renderSystemLineAlpha(this); +} + +void RainParticleSystem::initParticle(Particle *p, int particleIndex){ + ParticleSystem::initParticle(p, particleIndex); + + float x= random.randRange(-radius, radius); + float y= random.randRange(-radius, radius); + + p->color= color; + p->energy= 10000; + p->pos= Vec3f(pos.x+x, pos.y, pos.z+y); + p->lastPos= p->pos; + p->speed= Vec3f(random.randRange(-speed/10, speed/10), -speed, random.randRange(-speed/10, speed/10)) + windSpeed; +} + +bool RainParticleSystem::deathTest(Particle *p){ + return p->pos.y<0; +} + +void RainParticleSystem::setRadius(float radius){ + this->radius= radius; + +} + +void RainParticleSystem::setWind(float windAngle, float windSpeed){ + this->windSpeed.x= sinf(degToRad(windAngle))*windSpeed; + this->windSpeed.y= 0.0f; + this->windSpeed.z= cosf(degToRad(windAngle))*windSpeed; +} + +// =========================================================================== +// SnowParticleSystem +// =========================================================================== + +SnowParticleSystem::SnowParticleSystem(int particleCount):ParticleSystem(particleCount){ + setWind(0.0f, 0.0f); + setRadius(30.0f); + + setEmissionRate(2); + setParticleSize(0.2f); + setColor(Vec4f(0.8f, 0.8f, 0.8f, 0.8f)); + setSpeed(0.05f); +} + +void SnowParticleSystem::initParticle(Particle *p, int particleIndex){ + + ParticleSystem::initParticle(p, particleIndex); + + float x= random.randRange(-radius, radius); + float y= random.randRange(-radius, radius); + + p->color= color; + p->energy= 10000; + p->pos= Vec3f(pos.x+x, pos.y, pos.z+y); + p->lastPos= p->pos; + p->speed= Vec3f(0.0f, -speed, 0.0f) + windSpeed; + p->speed.x+= random.randRange(-0.005f, 0.005f); + p->speed.y+= random.randRange(-0.005f, 0.005f); +} + +bool SnowParticleSystem::deathTest(Particle *p){ + return p->pos.y<0; +} + +void SnowParticleSystem::setRadius(float radius){ + this->radius= radius; +} + +void SnowParticleSystem::setWind(float windAngle, float windSpeed){ + this->windSpeed.x= sinf(degToRad(windAngle))*windSpeed; + this->windSpeed.y= 0.0f; + this->windSpeed.z= cosf(degToRad(windAngle))*windSpeed; +} + +// =========================================================================== +// AttackParticleSystem +// =========================================================================== + +AttackParticleSystem::AttackParticleSystem(int particleCount): ParticleSystem(particleCount){ + model= NULL; + primitive= pQuad; + offset= Vec3f(0.0f); + gravity= 0.0f; + direction= Vec3f(1.0f, 0.0f, 0.0f); +} + +void AttackParticleSystem::render(ParticleRenderer *pr, ModelRenderer *mr){ + if(active){ + if(model!=NULL){ + pr->renderSingleModel(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; + } +} + +// =========================================================================== +// ProjectileParticleSystem +// =========================================================================== + +ProjectileParticleSystem::ProjectileParticleSystem(int particleCount): AttackParticleSystem(particleCount){ + setEmissionRate(20); + setColor(Vec4f(1.0f, 0.3f, 0.0f, 0.5f)); + setMaxParticleEnergy(100); + setVarParticleEnergy(50); + setParticleSize(0.4f); + setSpeed(0.14f); + + trajectory= tLinear; + trajectorySpeed= 1.0f; + trajectoryScale= 1.0f; + trajectoryFrequency = 1.0f; + + nextParticleSystem= NULL; +} + +ProjectileParticleSystem::~ProjectileParticleSystem(){ + if(nextParticleSystem!=NULL){ + nextParticleSystem->prevParticleSystem= NULL; + } +} + +void ProjectileParticleSystem::link(SplashParticleSystem *particleSystem){ + nextParticleSystem= particleSystem; + nextParticleSystem->setState(sPause); + nextParticleSystem->prevParticleSystem= this; +} + +void ProjectileParticleSystem::update(){ + + if(state==sPlay){ + + lastPos= pos; + flatPos+= zVector * trajectorySpeed; + Vec3f targetVector= endPos - startPos; + Vec3f currentVector= flatPos - startPos; + + // ratio + float t= clamp(currentVector.length() / targetVector.length(), 0.0f, 1.0f); + + // trajectory + switch(trajectory){ + case tLinear: + { + pos= flatPos; + } + break; + + case tParabolic: + { + float scaledT= 2.0f * (t-0.5f); + float paraboleY= (1.0f-scaledT*scaledT) * trajectoryScale; + + pos = flatPos; + pos.y+= paraboleY; + } + break; + + case tSpiral: + { + pos= flatPos; + pos+= xVector * cos(t*trajectoryFrequency*targetVector.length())*trajectoryScale; + pos+= yVector * sin(t*trajectoryFrequency*targetVector.length())*trajectoryScale; + } + break; + + default: + assert(false); + } + + direction= pos - lastPos; + direction.normalize(); + + //arrive destination + if( flatPos.dist(endPos)<0.5f ){ + state= sFade; + model= NULL; + + if(particleObserver!=NULL){ + particleObserver->update(this); + } + + if(nextParticleSystem!=NULL){ + nextParticleSystem->setState(sPlay); + nextParticleSystem->setPos(endPos); + } + } + } + + ParticleSystem::update(); +} + +void ProjectileParticleSystem::initParticle(Particle *p, int particleIndex){ + + ParticleSystem::initParticle(p, particleIndex); + + float t= static_cast(particleIndex)/emissionRate; + + p->pos= pos + (lastPos - pos) * t; + p->lastPos= lastPos; + p->speed= Vec3f(random.randRange(-0.1f, 0.1f), random.randRange(-0.1f, 0.1f), random.randRange(-0.1f, 0.1f)) * speed; + p->accel= Vec3f(0.0f, -gravity, 0.0f); + + updateParticle(p); +} + +void ProjectileParticleSystem::updateParticle(Particle *p){ + float energyRatio= clamp(static_cast(p->energy)/maxParticleEnergy, 0.f, 1.f); + + p->lastPos+= p->speed; + p->pos+= p->speed; + p->speed+= p->accel; + p->color = color * energyRatio + colorNoEnergy * (1.0f-energyRatio); + p->size = particleSize * energyRatio + sizeNoEnergy * (1.0f-energyRatio); + p->energy--; +} + +void ProjectileParticleSystem::setPath(Vec3f startPos, Vec3f endPos){ + + //compute axis + zVector= endPos - startPos; + zVector.normalize(); + yVector= Vec3f(0.0f, 1.0f, 0.0f); + xVector= zVector.cross(yVector); + + //apply offset + startPos+= xVector * offset.x; + startPos+= yVector * offset.y; + startPos+= zVector * offset.z; + + pos= startPos; + lastPos= startPos; + flatPos= startPos; + + //recompute axis + zVector= endPos - startPos; + zVector.normalize(); + yVector= Vec3f(0.0f, 1.0f, 0.0f); + xVector= zVector.cross(yVector); + + // set members + this->startPos= startPos; + this->endPos= endPos; +} + +ProjectileParticleSystem::Trajectory ProjectileParticleSystem::strToTrajectory(const string &str){ + if(str=="linear"){ + return tLinear; + } + else if(str=="parabolic"){ + return tParabolic; + } + else if(str=="spiral"){ + return tSpiral; + } + else{ + throw "Unknown particle system trajectory: " + str; + } +} + +// =========================================================================== +// SplashParticleSystem +// =========================================================================== + +SplashParticleSystem::SplashParticleSystem(int particleCount): AttackParticleSystem(particleCount){ + setColor(Vec4f(1.0f, 0.3f, 0.0f, 0.8f)); + setMaxParticleEnergy(100); + setVarParticleEnergy(50); + setParticleSize(1.0f); + setSpeed(0.003f); + + prevParticleSystem= NULL; + + emissionRateFade= 1; + verticalSpreadA= 1.0f; + verticalSpreadB= 0.0f; + horizontalSpreadA= 1.0f; + horizontalSpreadB= 0.0f; +} + +SplashParticleSystem::~SplashParticleSystem(){ + if(prevParticleSystem!=NULL){ + prevParticleSystem->nextParticleSystem= NULL; + } +} + +void SplashParticleSystem::update(){ + ParticleSystem::update(); + if(state!=sPause){ + emissionRate-= emissionRateFade; + } +} + +void SplashParticleSystem::initParticle(Particle *p, int particleIndex){ + p->pos= pos; + p->lastPos= p->pos; + p->energy= maxParticleEnergy; + p->size= particleSize; + p->color= color; + + p->speed= Vec3f( + horizontalSpreadA * random.randRange(-1.0f, 1.0f) + horizontalSpreadB, + verticalSpreadA * random.randRange(-1.0f, 1.0f) + verticalSpreadB, + horizontalSpreadA * random.randRange(-1.0f, 1.0f) + horizontalSpreadB); + p->speed.normalize(); + p->speed= p->speed * speed; + + p->accel= Vec3f(0.0f, -gravity, 0.0f); +} + +void SplashParticleSystem::updateParticle(Particle *p){ + float energyRatio= clamp(static_cast(p->energy)/maxParticleEnergy, 0.f, 1.f); + + p->lastPos= p->pos; + p->pos= p->pos + p->speed; + p->speed= p->speed + p->accel; + p->energy--; + p->color = color * energyRatio + colorNoEnergy * (1.0f-energyRatio); + p->size = particleSize * energyRatio + sizeNoEnergy * (1.0f-energyRatio); +} + +// =========================================================================== +// ParticleManager +// =========================================================================== + +ParticleManager::~ParticleManager(){ + end(); +} + +void ParticleManager::render(ParticleRenderer *pr, ModelRenderer *mr) const{ + list::const_iterator it; + + for (it=particleSystems.begin(); it!=particleSystems.end(); it++){ + if((*it)->getVisible()){ + (*it)->render(pr, mr); + } + } +} + +void ParticleManager::update(){ + list::iterator it; + + for (it=particleSystems.begin(); it!=particleSystems.end(); it++){ + (*it)->update(); + if((*it)->isEmpty()){ + delete *it; + *it= NULL; + } + } + particleSystems.remove(NULL); +} + +void ParticleManager::manage(ParticleSystem *ps){ + particleSystems.push_back(ps); +} + +void ParticleManager::end(){ + while(!particleSystems.empty()){ + delete particleSystems.front(); + particleSystems.pop_front(); + } +} + +}}//end namespace