![titiger](/assets/img/avatar_default.png)
removed a useless validation call which was pretty expensive for many particle systems alive It checked for existance of particle system in the vector we were curretnly cycling through.
2569 lines
86 KiB
C++
2569 lines
86 KiB
C++
// ==============================================================
|
|
// 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 "math_wrapper.h"
|
|
#include "particle.h"
|
|
|
|
#include <stdexcept>
|
|
#include <cassert>
|
|
#include <algorithm>
|
|
|
|
#include "util.h"
|
|
#include "particle_renderer.h"
|
|
#include "math_util.h"
|
|
#include "platform_common.h"
|
|
#include "conversion.h"
|
|
#include "model.h"
|
|
#include "texture.h"
|
|
#include "platform_util.h"
|
|
#include "leak_dumper.h"
|
|
|
|
using namespace std;
|
|
using namespace Shared::Util;
|
|
using namespace Shared::PlatformCommon;
|
|
|
|
namespace Shared {
|
|
namespace Graphics {
|
|
|
|
// =====================================================
|
|
// class ParticleSystem
|
|
// =====================================================
|
|
|
|
const bool checkMemory = false;
|
|
static map<void *,int> memoryObjectList;
|
|
|
|
void Particle::saveGame(XmlNode *rootNode) {
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *particleNode = rootNode->addChild("Particle");
|
|
|
|
// Vec3f pos;
|
|
particleNode->addAttribute("pos",pos.getString(), mapTagReplacements);
|
|
// Vec3f lastPos;
|
|
particleNode->addAttribute("lastPos",lastPos.getString(), mapTagReplacements);
|
|
// Vec3f speed;
|
|
particleNode->addAttribute("speed",speed.getString(), mapTagReplacements);
|
|
// Vec3f speedUpRelative;
|
|
particleNode->addAttribute("speedUpRelative",floatToStr(speedUpRelative,6), mapTagReplacements);
|
|
// Vec3f speedUpConstant;
|
|
particleNode->addAttribute("speedUpConstant",speedUpConstant.getString(), mapTagReplacements);
|
|
// Vec3f accel;
|
|
particleNode->addAttribute("accel",accel.getString(), mapTagReplacements);
|
|
// Vec4f color;
|
|
particleNode->addAttribute("color",color.getString(), mapTagReplacements);
|
|
// float size;
|
|
particleNode->addAttribute("size",floatToStr(size,6), mapTagReplacements);
|
|
// int energy;
|
|
particleNode->addAttribute("energy",intToStr(energy), mapTagReplacements);
|
|
}
|
|
|
|
void Particle::loadGame(const XmlNode *rootNode) {
|
|
const XmlNode *particleNode = rootNode;
|
|
|
|
//particleNode = aiNode->getAttribute("startLoc")->getIntValue();
|
|
// Vec3f pos;
|
|
pos = Vec3f::strToVec3(particleNode->getAttribute("pos")->getValue());
|
|
// Vec3f lastPos;
|
|
lastPos = Vec3f::strToVec3(particleNode->getAttribute("lastPos")->getValue());
|
|
// Vec3f speed;
|
|
speed = Vec3f::strToVec3(particleNode->getAttribute("speed")->getValue());
|
|
// Vec3f speed;
|
|
speedUpRelative = particleNode->getAttribute("speedUpRelative")->getFloatValue();
|
|
// Vec3f speed;
|
|
speedUpConstant = Vec3f::strToVec3(particleNode->getAttribute("speedUpConstant")->getValue());
|
|
// Vec3f accel;
|
|
accel = Vec3f::strToVec3(particleNode->getAttribute("accel")->getValue());
|
|
// Vec4f color;
|
|
color = Vec4f::strToVec4(particleNode->getAttribute("color")->getValue());
|
|
// float size;
|
|
size = particleNode->getAttribute("size")->getFloatValue();
|
|
// int energy;
|
|
energy = particleNode->getAttribute("energy")->getIntValue();
|
|
}
|
|
|
|
ParticleSystem::ParticleSystem(int particleCount) {
|
|
if(checkMemory) {
|
|
printf("++ Create ParticleSystem [%p]\n",this);
|
|
memoryObjectList[this]++;
|
|
}
|
|
|
|
textureFileLoadDeferred = "";
|
|
textureFileLoadDeferredSystemId = 0;
|
|
textureFileLoadDeferredFormat = Texture::fAuto;
|
|
textureFileLoadDeferredComponents = 0;
|
|
|
|
//init particle vector
|
|
blendMode= bmOne;
|
|
//particles= new Particle[particleCount];
|
|
particles.clear();
|
|
//particles.reserve(particleCount);
|
|
particles.resize(particleCount);
|
|
|
|
state= sPlay;
|
|
aliveParticleCount= 0;
|
|
active= true;
|
|
visible= true;
|
|
|
|
//vars
|
|
texture= NULL;
|
|
particleObserver= NULL;
|
|
|
|
//params
|
|
this->particleCount= particleCount;
|
|
//this->particleCount= particles.size();
|
|
maxParticleEnergy= 250;
|
|
varParticleEnergy= 50;
|
|
pos= Vec3f(0.0f);
|
|
color= Vec4f(1.0f);
|
|
colorNoEnergy= Vec4f(0.0f);
|
|
emissionRate= 15.0f;
|
|
emissionState= 1.0f; // initialized with 1 because we must have at least one particle in the beginning!
|
|
speed= 1.0f;
|
|
speedUpRelative = 0;
|
|
speedUpConstant = 0;
|
|
|
|
teamcolorNoEnergy= false;
|
|
teamcolorEnergy= false;
|
|
alternations= 0;
|
|
particleSystemStartDelay= 0;
|
|
|
|
this->particleOwner = NULL;
|
|
this->particleSize = 0.0f;
|
|
}
|
|
|
|
ParticleSystem::~ParticleSystem() {
|
|
if(checkMemory) {
|
|
printf("-- Delete ParticleSystem [%p]\n",this);
|
|
memoryObjectList[this]--;
|
|
assert(memoryObjectList[this] == 0);
|
|
}
|
|
|
|
//delete [] particles;
|
|
particles.clear();
|
|
|
|
delete particleObserver;
|
|
particleObserver = NULL;
|
|
}
|
|
|
|
void ParticleSystem::callParticleOwnerEnd(ParticleSystem *particleSystem) {
|
|
if(this->particleOwner != NULL) {
|
|
this->particleOwner->end(particleSystem);
|
|
}
|
|
}
|
|
Checksum ParticleSystem::getCRC() {
|
|
Checksum crcForParticleSystem;
|
|
|
|
//std::vector<Particle> particles;
|
|
|
|
crcForParticleSystem.addInt(random.getLastNumber());
|
|
crcForParticleSystem.addInt(blendMode);
|
|
crcForParticleSystem.addInt(state);
|
|
crcForParticleSystem.addInt(active);
|
|
//crcForParticleSystem.addInt(visible);
|
|
crcForParticleSystem.addInt(aliveParticleCount);
|
|
crcForParticleSystem.addInt(particleCount);
|
|
|
|
//string textureFileLoadDeferred;
|
|
//int textureFileLoadDeferredSystemId;
|
|
//Texture::Format textureFileLoadDeferredFormat;
|
|
//int textureFileLoadDeferredComponents;
|
|
|
|
//Texture *texture;
|
|
//Vec3f pos;
|
|
//Vec4f color;
|
|
//Vec4f colorNoEnergy;
|
|
//float emissionRate;
|
|
//float emissionState;
|
|
crcForParticleSystem.addInt(maxParticleEnergy);
|
|
crcForParticleSystem.addInt(varParticleEnergy);
|
|
//float particleSize;
|
|
//float speed;
|
|
//Vec3f factionColor;
|
|
crcForParticleSystem.addInt(teamcolorNoEnergy);
|
|
crcForParticleSystem.addInt(teamcolorEnergy);
|
|
crcForParticleSystem.addInt(alternations);
|
|
crcForParticleSystem.addInt(particleSystemStartDelay);
|
|
//ParticleObserver *particleObserver;
|
|
|
|
return crcForParticleSystem;
|
|
}
|
|
|
|
// =============== VIRTUAL ======================
|
|
|
|
//updates all living particles and creates new ones
|
|
void ParticleSystem::update() {
|
|
if(aliveParticleCount > (int) particles.size()) {
|
|
throw megaglest_runtime_error("aliveParticleCount >= particles.size()");
|
|
}
|
|
if(particleSystemStartDelay > 0) {
|
|
particleSystemStartDelay--;
|
|
}
|
|
else if(state != sPause) {
|
|
for(int i= 0; i < aliveParticleCount; ++i) {
|
|
updateParticle(&particles[i]);
|
|
|
|
if(deathTest(&particles[i])) {
|
|
|
|
//kill the particle
|
|
killParticle(&particles[i]);
|
|
|
|
//maintain alive particles at front of the array
|
|
if(aliveParticleCount > 0) {
|
|
particles[i]= particles[aliveParticleCount];
|
|
}
|
|
}
|
|
}
|
|
|
|
if(state != ParticleSystem::sFade) {
|
|
emissionState= emissionState + emissionRate;
|
|
int emissionIntValue= (int) emissionState;
|
|
for(int i= 0; i < emissionIntValue; i++){
|
|
Particle *p= createParticle();
|
|
initParticle(p, i);
|
|
}
|
|
emissionState = emissionState - (float) emissionIntValue;
|
|
emissionState = truncateDecimal<float>(emissionState,6);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ParticleSystem::render(ParticleRenderer *pr, ModelRenderer *mr){
|
|
if(active) {
|
|
pr->renderSystem(this);
|
|
}
|
|
}
|
|
|
|
ParticleSystem::BlendMode ParticleSystem::strToBlendMode(const string &str){
|
|
if(str == "normal") {
|
|
return bmOne;
|
|
}
|
|
else if(str == "black") {
|
|
return bmOneMinusAlpha;
|
|
}
|
|
else{
|
|
throw megaglest_runtime_error("Unknown particle mode: " + str);
|
|
}
|
|
}
|
|
|
|
// =============== SET ==========================
|
|
|
|
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){
|
|
this->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){
|
|
this->color= color;
|
|
}
|
|
|
|
void ParticleSystem::setColorNoEnergy(Vec4f colorNoEnergy){
|
|
this->colorNoEnergy= colorNoEnergy;
|
|
}
|
|
|
|
void ParticleSystem::setEmissionRate(float emissionRate){
|
|
this->emissionRate= emissionRate;
|
|
this->emissionRate = truncateDecimal<float>(this->emissionRate,6);
|
|
}
|
|
|
|
void ParticleSystem::setMaxParticleEnergy(int maxParticleEnergy){
|
|
this->maxParticleEnergy= maxParticleEnergy;
|
|
}
|
|
|
|
void ParticleSystem::setVarParticleEnergy(int varParticleEnergy){
|
|
this->varParticleEnergy= varParticleEnergy;
|
|
}
|
|
|
|
void ParticleSystem::setParticleSize(float particleSize){
|
|
this->particleSize= particleSize;
|
|
this->particleSize = truncateDecimal<float>(this->particleSize,6);
|
|
}
|
|
|
|
void ParticleSystem::setSpeed(float speed){
|
|
this->speed= speed;
|
|
this->speed = truncateDecimal<float>(this->speed,6);
|
|
}
|
|
|
|
void ParticleSystem::setSpeedUpRelative(float speedUpRelative){
|
|
this->speedUpRelative= speedUpRelative;
|
|
this->speedUpRelative = truncateDecimal<float>(this->speedUpRelative,6);
|
|
}
|
|
|
|
void ParticleSystem::setSpeedUpConstant(float speedUpConstant){
|
|
this->speedUpConstant= speedUpConstant;
|
|
this->speedUpConstant = truncateDecimal<float>(this->speedUpConstant,6);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
string ParticleSystem::toString() const {
|
|
string result = "ParticleSystem ";
|
|
|
|
result += "particles = " + intToStr(particles.size());
|
|
|
|
// for(unsigned int i = 0; i < particles.size(); ++i) {
|
|
// Particle &particle = particles[i];
|
|
//
|
|
// }
|
|
|
|
result += "\nrandom = " + intToStr(random.getLastNumber());
|
|
|
|
result += "\nblendMode = " + intToStr(blendMode);
|
|
result += "\nstate = " + intToStr(state);
|
|
result += "\nactive = " + intToStr(active);
|
|
//result += "\nvisible = " + intToStr(visible);
|
|
result += "\naliveParticleCount = " + intToStr(aliveParticleCount);
|
|
result += "\nparticleCount = " + intToStr(particleCount);
|
|
|
|
result += "\ntextureFileLoadDeferred = " + textureFileLoadDeferred;
|
|
result += "\ntextureFileLoadDeferredFormat = " + intToStr(textureFileLoadDeferredFormat);
|
|
result += "\ntextureFileLoadDeferredComponents = " + intToStr(textureFileLoadDeferredComponents);
|
|
|
|
if(texture != NULL) {
|
|
result += "\ntexture = " + extractFileFromDirectoryPath(texture->getPath());
|
|
}
|
|
result += "\npos = " + pos.getString();
|
|
result += "\ncolor = " + color.getString();
|
|
result += "\ncolorNoEnergy = " + colorNoEnergy.getString();
|
|
result += "\nemissionRate = " + floatToStr(emissionRate,6);
|
|
result += "\nemissionState = " + floatToStr(emissionState,6);
|
|
result += "\nmaxParticleEnergy = " + intToStr(maxParticleEnergy);
|
|
result += "\nvarParticleEnergy = " + intToStr(varParticleEnergy);
|
|
result += "\nparticleSize = " + floatToStr(particleSize,6);
|
|
result += "\nspeed = " + floatToStr(speed,6);
|
|
result += "\nfactionColor = " + factionColor.getString();
|
|
result += "\nteamcolorNoEnergy = " + intToStr(teamcolorNoEnergy);
|
|
result += "\nteamcolorEnergy = " + intToStr(teamcolorEnergy);
|
|
result += "\nalternations = " + intToStr(alternations);
|
|
result += "\nparticleSystemStartDelay = " + intToStr(particleSystemStartDelay);
|
|
//ParticleObserver *particleObserver;
|
|
|
|
return result;
|
|
}
|
|
|
|
void ParticleSystem::saveGame(XmlNode *rootNode) {
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *particleSystemNode = rootNode->addChild("ParticleSystem");
|
|
|
|
// std::vector<Particle> particles;
|
|
// for(unsigned int i = 0; i < particles.size(); ++i) {
|
|
// Particle &particle = particles[i];
|
|
// particle.saveGame(particleSystemNode);
|
|
// }
|
|
// RandomGen random;
|
|
particleSystemNode->addAttribute("random",intToStr(random.getLastNumber()), mapTagReplacements);
|
|
|
|
// BlendMode blendMode;
|
|
particleSystemNode->addAttribute("blendMode",intToStr(blendMode), mapTagReplacements);
|
|
// State state;
|
|
particleSystemNode->addAttribute("state",intToStr(state), mapTagReplacements);
|
|
// bool active;
|
|
particleSystemNode->addAttribute("active",intToStr(active), mapTagReplacements);
|
|
// bool visible;
|
|
particleSystemNode->addAttribute("visible",intToStr(visible), mapTagReplacements);
|
|
// int aliveParticleCount;
|
|
particleSystemNode->addAttribute("aliveParticleCount",intToStr(aliveParticleCount), mapTagReplacements);
|
|
// int particleCount;
|
|
particleSystemNode->addAttribute("particleCount",intToStr(particleCount), mapTagReplacements);
|
|
//
|
|
// Texture *texture;
|
|
if(texture != NULL) {
|
|
particleSystemNode->addAttribute("texture",texture->getPath(), mapTagReplacements);
|
|
particleSystemNode->addAttribute("textureid",intToStr(texture->getTextureSystemId()), mapTagReplacements);
|
|
particleSystemNode->addAttribute("textureFormat",intToStr(texture->getFormat()), mapTagReplacements);
|
|
Texture2D *t2d = dynamic_cast<Texture2D *>(texture);
|
|
if(t2d != NULL && t2d->getPixmapConst() != NULL) {
|
|
particleSystemNode->addAttribute("textureComponents",intToStr(t2d->getPixmapConst()->getComponents()), mapTagReplacements);
|
|
}
|
|
}
|
|
// Vec3f pos;
|
|
particleSystemNode->addAttribute("pos",pos.getString(), mapTagReplacements);
|
|
// Vec4f color;
|
|
particleSystemNode->addAttribute("color",color.getString(), mapTagReplacements);
|
|
// Vec4f colorNoEnergy;
|
|
particleSystemNode->addAttribute("colorNoEnergy",colorNoEnergy.getString(), mapTagReplacements);
|
|
// float emissionRate;
|
|
particleSystemNode->addAttribute("emissionRate",floatToStr(emissionRate,6), mapTagReplacements);
|
|
// float emissionState;
|
|
particleSystemNode->addAttribute("emissionState",floatToStr(emissionState,6), mapTagReplacements);
|
|
// int maxParticleEnergy;
|
|
particleSystemNode->addAttribute("maxParticleEnergy",intToStr(maxParticleEnergy), mapTagReplacements);
|
|
// int varParticleEnergy;
|
|
particleSystemNode->addAttribute("varParticleEnergy",intToStr(varParticleEnergy), mapTagReplacements);
|
|
// float particleSize;
|
|
particleSystemNode->addAttribute("particleSize",floatToStr(particleSize,6), mapTagReplacements);
|
|
// float speed;
|
|
particleSystemNode->addAttribute("speed",floatToStr(speed,6), mapTagReplacements);
|
|
// Vec3f factionColor;
|
|
particleSystemNode->addAttribute("factionColor",factionColor.getString(), mapTagReplacements);
|
|
// bool teamcolorNoEnergy;
|
|
particleSystemNode->addAttribute("teamcolorNoEnergy",intToStr(teamcolorNoEnergy), mapTagReplacements);
|
|
// bool teamcolorEnergy;
|
|
particleSystemNode->addAttribute("teamcolorEnergy",intToStr(teamcolorEnergy), mapTagReplacements);
|
|
// int alternations;
|
|
particleSystemNode->addAttribute("alternations",intToStr(alternations), mapTagReplacements);
|
|
// int particleSystemStartDelay;
|
|
particleSystemNode->addAttribute("particleSystemStartDelay",intToStr(particleSystemStartDelay), mapTagReplacements);
|
|
// ParticleObserver *particleObserver;
|
|
if(particleObserver != NULL) {
|
|
particleObserver->saveGame(particleSystemNode);
|
|
}
|
|
}
|
|
|
|
string ParticleSystem::getTextureFileLoadDeferred() {
|
|
return textureFileLoadDeferred;
|
|
}
|
|
int ParticleSystem::getTextureFileLoadDeferredSystemId() {
|
|
return textureFileLoadDeferredSystemId;
|
|
}
|
|
Texture::Format ParticleSystem::getTextureFileLoadDeferredFormat() {
|
|
return textureFileLoadDeferredFormat;
|
|
}
|
|
int ParticleSystem::getTextureFileLoadDeferredComponents() {
|
|
return textureFileLoadDeferredComponents;
|
|
}
|
|
|
|
void ParticleSystem::loadGame(const XmlNode *rootNode) {
|
|
const XmlNode *particleSystemNode = rootNode->getChild("ParticleSystem");
|
|
|
|
particleCount = particleSystemNode->getAttribute("particleCount")->getIntValue();
|
|
//printf("Load Smoke particle (ParticleSystem)\n");
|
|
// std::vector<Particle> particles;
|
|
// for(unsigned int i = 0; i < particles.size(); ++i) {
|
|
// Particle &particle = particles[i];
|
|
// particle.saveGame(particleSystemNode);
|
|
// }
|
|
|
|
particles.clear();
|
|
particles.resize(particleCount);
|
|
|
|
// vector<XmlNode *> particleNodeList = particleSystemNode->getChildList("Particle");
|
|
// for(unsigned int i = 0; i < particleNodeList.size(); ++i) {
|
|
// XmlNode *node = particleNodeList[i];
|
|
//
|
|
// //printf("Load Smoke particle (Particle = %d)\n",i);
|
|
//
|
|
// Particle particle;
|
|
// particle.loadGame(node);
|
|
// particles.push_back(particle);
|
|
// }
|
|
|
|
// RandomGen random;
|
|
random.setLastNumber(particleSystemNode->getAttribute("random")->getIntValue());
|
|
|
|
// BlendMode blendMode;
|
|
blendMode = static_cast<BlendMode>(particleSystemNode->getAttribute("blendMode")->getIntValue());
|
|
// State state;
|
|
state = static_cast<State>(particleSystemNode->getAttribute("state")->getIntValue());
|
|
// bool active;
|
|
active = particleSystemNode->getAttribute("active")->getIntValue() != 0;
|
|
// bool visible;
|
|
visible = particleSystemNode->getAttribute("visible")->getIntValue() != 0;
|
|
// int aliveParticleCount;
|
|
aliveParticleCount = particleSystemNode->getAttribute("aliveParticleCount")->getIntValue();
|
|
// int particleCount;
|
|
particleCount = particleSystemNode->getAttribute("particleCount")->getIntValue();
|
|
//
|
|
// Texture *texture;
|
|
if(particleSystemNode->hasAttribute("texture") == true) {
|
|
textureFileLoadDeferred = particleSystemNode->getAttribute("texture")->getValue();
|
|
textureFileLoadDeferredSystemId = particleSystemNode->getAttribute("textureid")->getIntValue();
|
|
|
|
textureFileLoadDeferredFormat = static_cast<Texture::Format>(particleSystemNode->getAttribute("textureFormat")->getIntValue());
|
|
if(particleSystemNode->hasAttribute("textureComponents") == true) {
|
|
textureFileLoadDeferredComponents = particleSystemNode->getAttribute("textureComponents")->getIntValue();
|
|
}
|
|
}
|
|
|
|
// Vec3f pos;
|
|
pos = Vec3f::strToVec3(particleSystemNode->getAttribute("pos")->getValue());
|
|
// Vec4f color;
|
|
color = Vec4f::strToVec4(particleSystemNode->getAttribute("color")->getValue());
|
|
// Vec4f colorNoEnergy;
|
|
colorNoEnergy = Vec4f::strToVec4(particleSystemNode->getAttribute("colorNoEnergy")->getValue());
|
|
// float emissionRate;
|
|
emissionRate = particleSystemNode->getAttribute("emissionRate")->getFloatValue();
|
|
// float emissionState;
|
|
emissionState = particleSystemNode->getAttribute("emissionState")->getFloatValue();
|
|
// int maxParticleEnergy;
|
|
maxParticleEnergy = particleSystemNode->getAttribute("maxParticleEnergy")->getIntValue();
|
|
// int varParticleEnergy;
|
|
varParticleEnergy = particleSystemNode->getAttribute("varParticleEnergy")->getIntValue();
|
|
// float particleSize;
|
|
particleSize = particleSystemNode->getAttribute("particleSize")->getFloatValue();
|
|
// float speed;
|
|
speed = particleSystemNode->getAttribute("speed")->getFloatValue();
|
|
// Vec3f factionColor;
|
|
factionColor = Vec3f::strToVec3(particleSystemNode->getAttribute("factionColor")->getValue());
|
|
// bool teamcolorNoEnergy;
|
|
teamcolorNoEnergy = particleSystemNode->getAttribute("teamcolorNoEnergy")->getIntValue() != 0;
|
|
// bool teamcolorEnergy;
|
|
teamcolorEnergy = particleSystemNode->getAttribute("teamcolorEnergy")->getIntValue() != 0;
|
|
// int alternations;
|
|
alternations = particleSystemNode->getAttribute("alternations")->getIntValue();
|
|
// int particleSystemStartDelay;
|
|
particleSystemStartDelay = particleSystemNode->getAttribute("particleSystemStartDelay")->getIntValue();
|
|
|
|
// ParticleObserver *particleObserver;
|
|
//if(particleObserver != NULL) {
|
|
// particleObserver->loadGame(particleSystemNode);
|
|
//}
|
|
}
|
|
|
|
// =============== MISC =========================
|
|
void ParticleSystem::fade(){
|
|
//printf("**************Fading particle System:\n[%s]\n",this->toString().c_str());
|
|
|
|
bool alreadyFading = (state == sFade);
|
|
if(particleObserver != NULL){
|
|
if(state != sPlay) {
|
|
char szBuf[8096]="";
|
|
snprintf(szBuf,8096,"state != sPlay, state = [%d]\n",state);
|
|
//throw megaglest_runtime_error(szBuf);
|
|
//printf(szBuf);
|
|
SystemFlags::OutputDebug(SystemFlags::debugError,"%s",szBuf);
|
|
}
|
|
//assert(state == sPlay);
|
|
}
|
|
|
|
state= sFade;
|
|
if(alreadyFading == false) {
|
|
if(particleObserver != NULL){
|
|
particleObserver->update(this);
|
|
particleObserver=NULL;
|
|
}
|
|
for(int i=getChildCount()-1; i>=0; i--) {
|
|
getChild(i)->fade();
|
|
}
|
|
}
|
|
}
|
|
|
|
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(aliveParticleCount < particleCount) {
|
|
++aliveParticleCount;
|
|
return &particles[aliveParticleCount - 1];
|
|
}
|
|
|
|
//if not
|
|
int minEnergy= particles[0].energy;
|
|
int minEnergyParticle= 0;
|
|
|
|
for(int i= 0; i < particleCount; ++i){
|
|
if(particles[i].energy < minEnergy){
|
|
minEnergy= particles[i].energy;
|
|
minEnergyParticle= i;
|
|
}
|
|
}
|
|
return &particles[minEnergyParticle];
|
|
}
|
|
|
|
void ParticleSystem::initParticle(Particle *p, int particleIndex) {
|
|
p->pos= 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->size = truncateDecimal<float>(p->size,6);
|
|
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);
|
|
}
|
|
for(int i=getChildCount()-1; i>=0; i--)
|
|
getChild(i)->setFactionColor(factionColor);
|
|
}
|
|
|
|
// ===========================================================================
|
|
// 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);
|
|
#ifdef USE_STREFLOP
|
|
float mod= streflop::fabsf(static_cast<streflop::Simple>(random.randRange(-radius, radius)));
|
|
|
|
float x= streflop::sinf(static_cast<streflop::Simple>(ang))*mod;
|
|
float y= streflop::cosf(static_cast<streflop::Simple>(ang))*mod;
|
|
|
|
float radRatio= streflop::sqrtf(static_cast<streflop::Simple>(mod/radius));
|
|
#else
|
|
float mod= fabsf(random.randRange(-radius, radius));
|
|
|
|
float x= sinf(ang) * mod;
|
|
float y= cosf(ang) * mod;
|
|
|
|
float radRatio= sqrtf((mod / radius));
|
|
#endif
|
|
|
|
p->color= colorNoEnergy * 0.5f + colorNoEnergy * 0.5f * radRatio;
|
|
p->energy= static_cast<int> (maxParticleEnergy * radRatio)
|
|
+ random.randRange(-varParticleEnergy, varParticleEnergy);
|
|
p->pos= Vec3f(pos.x + x, pos.y + random.randRange(-radius / 2, radius / 2), pos.z + y);
|
|
p->pos.x = truncateDecimal<float>(p->pos.x,6);
|
|
p->pos.y = truncateDecimal<float>(p->pos.y,6);
|
|
p->pos.z = truncateDecimal<float>(p->pos.z,6);
|
|
|
|
p->lastPos= pos;
|
|
p->size= particleSize;
|
|
p->speed= Vec3f(0, speed + speed * random.randRange(-0.5f, 0.5f), 0) + windSpeed;
|
|
p->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
|
|
}
|
|
|
|
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;
|
|
p->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
|
|
}
|
|
|
|
string FireParticleSystem::toString() const {
|
|
string result = ParticleSystem::toString();
|
|
|
|
result += "\nFireParticleSystem ";
|
|
result += "\nradius = " + floatToStr(radius);
|
|
result += "\nwindSpeed = " + windSpeed.getString();
|
|
|
|
return result;
|
|
}
|
|
// ================= SET PARAMS ====================
|
|
|
|
void FireParticleSystem::setRadius(float radius){
|
|
this->radius= radius;
|
|
}
|
|
|
|
void FireParticleSystem::setWind(float windAngle, float windSpeed) {
|
|
#ifdef USE_STREFLOP
|
|
this->windSpeed.x= streflop::sinf(static_cast<streflop::Simple>(degToRad(windAngle)))*windSpeed;
|
|
this->windSpeed.y= 0.0f;
|
|
this->windSpeed.z= streflop::cosf(static_cast<streflop::Simple>(degToRad(windAngle)))*windSpeed;
|
|
#else
|
|
this->windSpeed.x= sinf(degToRad(windAngle)) * windSpeed;
|
|
this->windSpeed.y= 0.0f;
|
|
this->windSpeed.z= cosf(degToRad(windAngle)) * windSpeed;
|
|
#endif
|
|
|
|
this->windSpeed.x = truncateDecimal<float>(this->windSpeed.x,6);
|
|
this->windSpeed.y = truncateDecimal<float>(this->windSpeed.y,6);
|
|
this->windSpeed.z = truncateDecimal<float>(this->windSpeed.z,6);
|
|
}
|
|
|
|
void FireParticleSystem::saveGame(XmlNode *rootNode) {
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *fireParticleSystemNode = rootNode->addChild("FireParticleSystem");
|
|
|
|
ParticleSystem::saveGame(fireParticleSystemNode);
|
|
|
|
// float radius;
|
|
fireParticleSystemNode->addAttribute("radius",floatToStr(radius,6), mapTagReplacements);
|
|
// Vec3f windSpeed;
|
|
fireParticleSystemNode->addAttribute("windSpeed",windSpeed.getString(), mapTagReplacements);
|
|
}
|
|
void FireParticleSystem::loadGame(const XmlNode *rootNode) {
|
|
const XmlNode *fireParticleSystemNode = rootNode;
|
|
|
|
ParticleSystem::loadGame(fireParticleSystemNode);
|
|
|
|
// float radius;
|
|
radius = fireParticleSystemNode->getAttribute("radius")->getFloatValue();
|
|
// Vec3f windSpeed;
|
|
windSpeed = Vec3f::strToVec3(fireParticleSystemNode->getAttribute("windSpeed")->getValue());
|
|
}
|
|
|
|
Checksum FireParticleSystem::getCRC() {
|
|
Checksum crcForParticleSystem = ParticleSystem::getCRC();
|
|
|
|
//float radius;
|
|
//Vec3f windSpeed;
|
|
|
|
return crcForParticleSystem;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// GameParticleSystem
|
|
// ===========================================================================
|
|
|
|
GameParticleSystem::GameParticleSystem(int particleCount):
|
|
ParticleSystem(particleCount),
|
|
primitive(pQuad),
|
|
model(NULL),
|
|
modelCycle(0.0f),
|
|
offset(0.0f),
|
|
direction(0.0f, 1.0f, 0.0f),
|
|
tween(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 megaglest_runtime_error("Unknown particle primitive: " + str);
|
|
}
|
|
}
|
|
|
|
int GameParticleSystem::getChildCount(){
|
|
return (int)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);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameParticleSystem::setTween(float relative,float absolute) {
|
|
if(model) {
|
|
// animation?
|
|
//printf("#1 Particle model meshcount [%d] modelCycle = %f, relative = %f, absolute = %f\n",model->getMeshCount(),modelCycle,relative,absolute);
|
|
if(modelCycle == 0.0f) {
|
|
tween= relative;
|
|
}
|
|
else {
|
|
#ifdef USE_STREFLOP
|
|
if(streflop::fabs(static_cast<streflop::Simple>(absolute)) <= 0.00001f){
|
|
#else
|
|
if(fabs(absolute) <= 0.00001f) {
|
|
#endif
|
|
tween = 0.0f;
|
|
}
|
|
else {
|
|
#ifdef USE_STREFLOP
|
|
tween= streflop::fmod(static_cast<streflop::Simple>(absolute), static_cast<streflop::Simple>(modelCycle));
|
|
#else
|
|
tween= fmod(absolute, modelCycle);
|
|
#endif
|
|
tween /= modelCycle;
|
|
}
|
|
}
|
|
|
|
tween = truncateDecimal<float>(tween,6);
|
|
if(tween < 0.0f || tween > 1.0f) {
|
|
//printf("In [%s::%s Line: %d] WARNING setting tween to [%f] clamping tween, modelCycle [%f] absolute [%f] relative [%f]\n",__FILE__,__FUNCTION__,__LINE__,tween,modelCycle,absolute,relative);
|
|
//assert(tween >= 0.0f && tween <= 1.0f);
|
|
}
|
|
|
|
tween= clamp(tween, 0.0f, 1.0f);
|
|
|
|
//printf("#2 Particle model meshcount [%d] modelCycle = %f, relative = %f, absolute = %f\n",model->getMeshCount(),modelCycle,relative,absolute);
|
|
}
|
|
for(Children::iterator it= children.begin(); it != children.end(); ++it) {
|
|
(*it)->setTween(relative,absolute);
|
|
}
|
|
}
|
|
|
|
string GameParticleSystem::getModelFileLoadDeferred() {
|
|
return modelFileLoadDeferred;
|
|
}
|
|
|
|
void GameParticleSystem::saveGame(XmlNode *rootNode) {
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *gameParticleSystemNode = rootNode->addChild("GameParticleSystem");
|
|
|
|
ParticleSystem::saveGame(gameParticleSystemNode);
|
|
|
|
// Children children;
|
|
for(unsigned int i = 0; i < children.size(); ++i) {
|
|
if(children[i] != NULL) {
|
|
children[i]->saveGame(gameParticleSystemNode);
|
|
}
|
|
}
|
|
// Primitive primitive;
|
|
gameParticleSystemNode->addAttribute("primitive",intToStr(primitive), mapTagReplacements);
|
|
// Model *model;
|
|
if(model != NULL) {
|
|
gameParticleSystemNode->addAttribute("model",model->getFileName(), mapTagReplacements);
|
|
}
|
|
// float modelCycle;
|
|
gameParticleSystemNode->addAttribute("modelCycle",floatToStr(modelCycle,6), mapTagReplacements);
|
|
// Vec3f offset;
|
|
gameParticleSystemNode->addAttribute("offset",offset.getString(), mapTagReplacements);
|
|
// Vec3f direction;
|
|
gameParticleSystemNode->addAttribute("direction",direction.getString(), mapTagReplacements);
|
|
// float tween;
|
|
gameParticleSystemNode->addAttribute("tween",floatToStr(tween,6), mapTagReplacements);
|
|
}
|
|
void GameParticleSystem::loadGame(const XmlNode *rootNode) {
|
|
const XmlNode *gameParticleSystemNode = rootNode->getChild("GameParticleSystem");
|
|
|
|
//printf("Load Smoke particle (GameParticleSystem)\n");
|
|
ParticleSystem::loadGame(gameParticleSystemNode);
|
|
|
|
// Children children;
|
|
// for(unsigned int i = 0; i < children.size(); ++i) {
|
|
// children[i]->saveGame(gameParticleSystemNode);
|
|
// }
|
|
vector<XmlNode *> childrenNodeList = gameParticleSystemNode->getChildList("UnitParticleSystem");
|
|
for(unsigned int i = 0; i < childrenNodeList.size(); ++i) {
|
|
XmlNode *node = childrenNodeList[i];
|
|
|
|
UnitParticleSystem *ups = new UnitParticleSystem();
|
|
//ups->setParticleOwner(!!!);
|
|
ups->loadGame(node);
|
|
|
|
//children.push_back(ups);
|
|
addChild(ups);
|
|
}
|
|
|
|
// Primitive primitive;
|
|
primitive = static_cast<Primitive>(gameParticleSystemNode->getAttribute("primitive")->getIntValue());
|
|
// Model *model;
|
|
//if(model != NULL) {
|
|
// gameParticleSystemNode->addAttribute("model",model->getFileName(), mapTagReplacements);
|
|
//}
|
|
if(gameParticleSystemNode->hasAttribute("model") == true) {
|
|
modelFileLoadDeferred = gameParticleSystemNode->getAttribute("model")->getValue();
|
|
}
|
|
|
|
// float modelCycle;
|
|
//gameParticleSystemNode->addAttribute("modelCycle",floatToStr(modelCycle), mapTagReplacements);
|
|
modelCycle = gameParticleSystemNode->getAttribute("modelCycle")->getFloatValue();
|
|
// Vec3f offset;
|
|
offset = Vec3f::strToVec3(gameParticleSystemNode->getAttribute("offset")->getValue());
|
|
// Vec3f direction;
|
|
direction = Vec3f::strToVec3(gameParticleSystemNode->getAttribute("direction")->getValue());
|
|
// float tween;
|
|
tween = gameParticleSystemNode->getAttribute("tween")->getFloatValue();
|
|
}
|
|
|
|
Checksum GameParticleSystem::getCRC() {
|
|
Checksum crcForParticleSystem = ParticleSystem::getCRC();
|
|
|
|
return crcForParticleSystem;
|
|
}
|
|
|
|
string GameParticleSystem::toString() const {
|
|
string result = ParticleSystem::toString();
|
|
|
|
result += "\nGameParticleSystem ";
|
|
result += "\nchildren = " + intToStr(children.size());
|
|
result += "\nprimitive = " + intToStr(primitive);
|
|
|
|
//string modelFileLoadDeferred;
|
|
//Model *model;
|
|
result += "\nmodelCycle = " + floatToStr(modelCycle);
|
|
result += "\noffset = " + offset.getString();
|
|
result += "\ndirection = " + direction.getString();
|
|
result += "\ntween = " + floatToStr(tween);
|
|
|
|
return result;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// UnitParticleSystem
|
|
// ===========================================================================
|
|
bool UnitParticleSystem::isNight= false;
|
|
Vec3f UnitParticleSystem::lightColor=Vec3f(1.0f,1.0f,1.0f);
|
|
|
|
UnitParticleSystem::UnitParticleSystem(int particleCount) :
|
|
GameParticleSystem(particleCount), parent(NULL) {
|
|
|
|
particleSystemType = NULL;
|
|
radius= 0.5f;
|
|
speed= 0.01f;
|
|
windSpeed= Vec3f(0.0f);
|
|
minRadius = 0.0;
|
|
|
|
setParticleSize(0.6f);
|
|
setColorNoEnergy(Vec4f(1.0f, 0.5f, 0.0f, 1.0f));
|
|
sizeNoEnergy=1.0f;
|
|
|
|
primitive= pQuad;
|
|
gravity= 0.0f;
|
|
|
|
fixed= false;
|
|
shape = UnitParticleSystem::sLinear;
|
|
angle= 0.0f;
|
|
rotation= 0.0f;
|
|
relativeDirection= true;
|
|
relative= false;
|
|
staticParticleCount= 0;
|
|
|
|
isVisibleAtNight= true;
|
|
isVisibleAtDay= true;
|
|
isDaylightAffected= false;
|
|
|
|
cRotation= Vec3f(1.0f, 1.0f, 1.0f);
|
|
fixedAddition= Vec3f(0.0f, 0.0f, 0.0f);
|
|
//prepare system for given staticParticleCount
|
|
if(staticParticleCount > 0){
|
|
emissionState= (float) staticParticleCount;
|
|
}
|
|
energyUp= false;
|
|
|
|
delay = 0; // none
|
|
lifetime = -1; // forever
|
|
emissionRateFade=0.0f;
|
|
|
|
startTime = 0;
|
|
endTime = 1;
|
|
unitModel=NULL;
|
|
meshName="";
|
|
meshPos=Vec3f(0,0,0);
|
|
|
|
radiusBasedStartenergy = false;
|
|
}
|
|
|
|
UnitParticleSystem::~UnitParticleSystem(){
|
|
if(parent){
|
|
parent->removeChild(this);
|
|
}
|
|
}
|
|
|
|
bool UnitParticleSystem::getVisible() const{
|
|
if((isNight==true) && (isVisibleAtNight==true)){
|
|
return visible;
|
|
}
|
|
else if((isNight==false) && (isVisibleAtDay==true)){
|
|
return visible;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void UnitParticleSystem::render(ParticleRenderer *pr, ModelRenderer *mr) {
|
|
GameParticleSystem::render(pr,mr);
|
|
}
|
|
|
|
void UnitParticleSystem::setRotation(float rotation){
|
|
this->rotation= rotation;
|
|
for(Children::iterator it= children.begin(); it != children.end(); ++it)
|
|
(*it)->setRotation(rotation);
|
|
}
|
|
|
|
void UnitParticleSystem::fade(){
|
|
if(!parent || (lifetime<=0 && !(emissionRateFade && emissionRate > 0))){ // particle has its own lifetime?
|
|
unitModel=NULL;
|
|
GameParticleSystem::fade();
|
|
}
|
|
}
|
|
|
|
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 megaglest_runtime_error("Unknown particle shape: " + str);
|
|
}
|
|
}
|
|
|
|
void UnitParticleSystem::initParticle(Particle *p, int particleIndex){
|
|
ParticleSystem::initParticle(p, particleIndex);
|
|
|
|
const float ang= random.randRange(-2.0f * pi, 2.0f * pi);
|
|
#ifdef USE_STREFLOP
|
|
const float mod= streflop::fabsf(static_cast<streflop::Simple>(random.randRange(-radius, radius)));
|
|
const float radRatio= streflop::sqrtf(static_cast<streflop::Simple>(mod/radius));
|
|
#else
|
|
const float mod= fabsf(random.randRange(-radius, radius));
|
|
const float radRatio= sqrtf(mod / radius);
|
|
#endif
|
|
p->color= color;
|
|
|
|
if(isDaylightAffected==true) {
|
|
p->color.x=p->color.x*lightColor.x;
|
|
p->color.y=p->color.y*lightColor.y;
|
|
p->color.z=p->color.z*lightColor.z;
|
|
}
|
|
if(radiusBasedStartenergy == true) {
|
|
p->energy= static_cast<int> (maxParticleEnergy * radRatio) +
|
|
random.randRange(-varParticleEnergy,varParticleEnergy);
|
|
}
|
|
else {
|
|
p->energy= static_cast<int> (maxParticleEnergy) +
|
|
random.randRange(-varParticleEnergy, varParticleEnergy);
|
|
}
|
|
|
|
p->lastPos= pos;
|
|
oldPosition= pos;
|
|
p->size= particleSize;
|
|
p->speedUpRelative= speedUpRelative;
|
|
p->accel= Vec3f(0.0f, -gravity, 0.0f);
|
|
p->accel.x = truncateDecimal<float>(p->accel.x,6);
|
|
p->accel.y = truncateDecimal<float>(p->accel.y,6);
|
|
p->accel.z = truncateDecimal<float>(p->accel.z,6);
|
|
|
|
// work out where we start for our shape (set speed and pos)
|
|
switch(shape){
|
|
case sSpherical:
|
|
angle = (float)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;
|
|
p->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
|
|
start = start * random.randRange(minRadius,radius);
|
|
p->pos = pos + offset + start;
|
|
p->pos.x = truncateDecimal<float>(p->pos.x,6);
|
|
p->pos.y = truncateDecimal<float>(p->pos.y,6);
|
|
p->pos.z = truncateDecimal<float>(p->pos.z,6);
|
|
|
|
} break;
|
|
case sLinear:{
|
|
#ifdef USE_STREFLOP
|
|
float x= streflop::sinf(static_cast<streflop::Simple>(ang))*mod;
|
|
float y= streflop::cosf(static_cast<streflop::Simple>(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);
|
|
p->pos.x = truncateDecimal<float>(p->pos.x,6);
|
|
p->pos.y = truncateDecimal<float>(p->pos.y,6);
|
|
p->pos.z = truncateDecimal<float>(p->pos.z,6);
|
|
|
|
}
|
|
else {
|
|
Vec3f combinedOffset=Vec3f(offset);
|
|
if(meshName!=""){
|
|
combinedOffset.x+=meshPos.x;
|
|
combinedOffset.y+=meshPos.y;
|
|
combinedOffset.z+=meshPos.z;
|
|
if(meshPos.x==0 && meshPos.y==0 && meshPos.z==0) {
|
|
printf("meshPosFail\n");
|
|
}
|
|
}
|
|
// rotate it according to rotation
|
|
#ifdef USE_STREFLOP
|
|
p->pos= Vec3f(pos.x+x+combinedOffset.z*streflop::sinf(static_cast<streflop::Simple>(rad))+combinedOffset.x*streflop::cosf(static_cast<streflop::Simple>(rad)), pos.y+random.randRange(-radius/2, radius/2)+combinedOffset.y, pos.z+y+(combinedOffset.z*streflop::cosf(static_cast<streflop::Simple>(rad))-combinedOffset.x*streflop::sinf(static_cast<streflop::Simple>(rad))));
|
|
#else
|
|
p->pos= Vec3f(pos.x + x + combinedOffset.z * sinf(rad) + combinedOffset.x * cosf(rad), pos.y + random.randRange(-radius / 2,
|
|
radius / 2) + combinedOffset.y, pos.z + y + (combinedOffset.z * cosf(rad) - combinedOffset.x * sinf(rad)));
|
|
#endif
|
|
|
|
p->pos.x = truncateDecimal<float>(p->pos.x,6);
|
|
p->pos.y = truncateDecimal<float>(p->pos.y,6);
|
|
p->pos.z = truncateDecimal<float>(p->pos.z,6);
|
|
|
|
}
|
|
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->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
|
|
if(relative && relativeDirection) {
|
|
#ifdef USE_STREFLOP
|
|
p->speed=Vec3f(p->speed.z*streflop::sinf(
|
|
static_cast<streflop::Simple>(rad)) + p->speed.x *
|
|
streflop::cosf(static_cast<streflop::Simple>(rad)),
|
|
p->speed.y, (p->speed.z * streflop::cosf(
|
|
static_cast<streflop::Simple>(rad)) - p->speed.x *
|
|
streflop::sinf(static_cast<streflop::Simple>(rad))));
|
|
#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)));
|
|
#endif
|
|
|
|
p->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
}
|
|
} break;
|
|
default: throw megaglest_runtime_error("bad shape");
|
|
}
|
|
//need to do that down here because we need p->speed for it.
|
|
p->speedUpConstant= Vec3f(speedUpConstant)*p->speed;
|
|
}
|
|
|
|
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;
|
|
emissionRate = truncateDecimal<float>(emissionRate,6);
|
|
|
|
if(parent && emissionRate < 0.0f) {
|
|
fade();
|
|
}
|
|
}
|
|
if(fixed) {
|
|
fixedAddition= Vec3f(pos.x - oldPosition.x, pos.y - oldPosition.y, pos.z - oldPosition.z);
|
|
fixedAddition.x = truncateDecimal<float>(fixedAddition.x,6);
|
|
fixedAddition.y = truncateDecimal<float>(fixedAddition.y,6);
|
|
fixedAddition.z = truncateDecimal<float>(fixedAddition.z,6);
|
|
|
|
oldPosition= pos;
|
|
}
|
|
ParticleSystem::update();
|
|
}
|
|
|
|
void UnitParticleSystem::updateParticle(Particle *p){
|
|
float energyRatio;
|
|
if(alternations > 0){
|
|
int interval= (maxParticleEnergy / alternations);
|
|
float moduloValue= (float)((int)(static_cast<float> (p->energy)) % interval);
|
|
float floatInterval=static_cast<float> (interval);
|
|
|
|
if(moduloValue < floatInterval / 2.0f){
|
|
energyRatio= (floatInterval - moduloValue) / floatInterval;
|
|
}
|
|
else{
|
|
energyRatio= moduloValue / floatInterval;
|
|
}
|
|
energyRatio= clamp(energyRatio, 0.f, 1.f);
|
|
}
|
|
else{
|
|
energyRatio= clamp(static_cast<float> (p->energy) / static_cast<float> (maxParticleEnergy), 0.f, 1.f);
|
|
}
|
|
|
|
energyRatio = truncateDecimal<float>(energyRatio,6);
|
|
|
|
p->lastPos += p->speed;
|
|
p->lastPos.x = truncateDecimal<float>(p->lastPos.x,6);
|
|
p->lastPos.y = truncateDecimal<float>(p->lastPos.y,6);
|
|
p->lastPos.z = truncateDecimal<float>(p->lastPos.z,6);
|
|
|
|
p->pos += p->speed;
|
|
p->pos.x = truncateDecimal<float>(p->pos.x,6);
|
|
p->pos.y = truncateDecimal<float>(p->pos.y,6);
|
|
p->pos.z = truncateDecimal<float>(p->pos.z,6);
|
|
|
|
if(fixed) {
|
|
p->lastPos += fixedAddition;
|
|
p->lastPos.x = truncateDecimal<float>(p->lastPos.x,6);
|
|
p->lastPos.y = truncateDecimal<float>(p->lastPos.y,6);
|
|
p->lastPos.z = truncateDecimal<float>(p->lastPos.z,6);
|
|
|
|
p->pos += fixedAddition;
|
|
p->pos.x = truncateDecimal<float>(p->pos.x,6);
|
|
p->pos.y = truncateDecimal<float>(p->pos.y,6);
|
|
p->pos.z = truncateDecimal<float>(p->pos.z,6);
|
|
}
|
|
p->speed += p->accel;
|
|
p->speed += p->speedUpConstant;
|
|
p->speed=p->speed*(1+p->speedUpRelative);
|
|
p->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
|
|
p->color= color * energyRatio + colorNoEnergy * (1.0f - energyRatio);
|
|
if(isDaylightAffected==true) {
|
|
p->color.x=p->color.x*lightColor.x;
|
|
p->color.y=p->color.y*lightColor.y;
|
|
p->color.z=p->color.z*lightColor.z;
|
|
}
|
|
p->size= particleSize * energyRatio + sizeNoEnergy * (1.0f - energyRatio);
|
|
p->size = truncateDecimal<float>(p->size,6);
|
|
|
|
if(state == ParticleSystem::sFade || staticParticleCount < 1){
|
|
p->energy--;
|
|
}
|
|
else{
|
|
if(maxParticleEnergy > 2){
|
|
if(energyUp){
|
|
p->energy++;
|
|
}
|
|
else{
|
|
p->energy--;
|
|
}
|
|
|
|
if(p->energy == 1){
|
|
energyUp= true;
|
|
}
|
|
if(p->energy == maxParticleEnergy){
|
|
energyUp= false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ================= SET PARAMS ====================
|
|
|
|
void UnitParticleSystem::setWind(float windAngle, float windSpeed){
|
|
#ifdef USE_STREFLOP
|
|
this->windSpeed.x= streflop::sinf(static_cast<streflop::Simple>(degToRad(windAngle)))*windSpeed;
|
|
this->windSpeed.y= 0.0f;
|
|
this->windSpeed.z= streflop::cosf(static_cast<streflop::Simple>(degToRad(windAngle)))*windSpeed;
|
|
#else
|
|
this->windSpeed.x= sinf(degToRad(windAngle)) * windSpeed;
|
|
this->windSpeed.y= 0.0f;
|
|
this->windSpeed.z= cosf(degToRad(windAngle)) * windSpeed;
|
|
#endif
|
|
|
|
this->windSpeed.x = truncateDecimal<float>(this->windSpeed.x,6);
|
|
this->windSpeed.y = truncateDecimal<float>(this->windSpeed.y,6);
|
|
this->windSpeed.z = truncateDecimal<float>(this->windSpeed.z,6);
|
|
}
|
|
|
|
void UnitParticleSystem::saveGame(XmlNode *rootNode) {
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *unitParticleSystemNode = rootNode->addChild("UnitParticleSystem");
|
|
|
|
GameParticleSystem::saveGame(unitParticleSystemNode);
|
|
|
|
// float radius;
|
|
unitParticleSystemNode->addAttribute("radius",floatToStr(radius,6), mapTagReplacements);
|
|
// float minRadius;
|
|
unitParticleSystemNode->addAttribute("minRadius",floatToStr(minRadius,6), mapTagReplacements);
|
|
// Vec3f windSpeed;
|
|
unitParticleSystemNode->addAttribute("windSpeed",windSpeed.getString(), mapTagReplacements);
|
|
// Vec3f cRotation;
|
|
unitParticleSystemNode->addAttribute("cRotation",cRotation.getString(), mapTagReplacements);
|
|
// Vec3f fixedAddition;
|
|
unitParticleSystemNode->addAttribute("fixedAddition",fixedAddition.getString(), mapTagReplacements);
|
|
// Vec3f oldPosition;
|
|
unitParticleSystemNode->addAttribute("oldPosition",oldPosition.getString(), mapTagReplacements);
|
|
// Vec3f meshPos;
|
|
unitParticleSystemNode->addAttribute("meshPos",meshPos.getString(), mapTagReplacements);
|
|
// string meshName;
|
|
unitParticleSystemNode->addAttribute("meshName",meshName, mapTagReplacements);
|
|
// bool energyUp;
|
|
unitParticleSystemNode->addAttribute("energyUp",intToStr(energyUp), mapTagReplacements);
|
|
// float startTime;
|
|
unitParticleSystemNode->addAttribute("startTime",floatToStr(startTime,6), mapTagReplacements);
|
|
// float endTime;
|
|
unitParticleSystemNode->addAttribute("endTime",floatToStr(endTime,6), mapTagReplacements);
|
|
// bool relative;
|
|
unitParticleSystemNode->addAttribute("relative",intToStr(relative), mapTagReplacements);
|
|
// bool relativeDirection;
|
|
unitParticleSystemNode->addAttribute("relativeDirection",intToStr(relativeDirection), mapTagReplacements);
|
|
// bool fixed;
|
|
unitParticleSystemNode->addAttribute("fixed",intToStr(fixed), mapTagReplacements);
|
|
// Shape shape;
|
|
unitParticleSystemNode->addAttribute("shape",intToStr(shape), mapTagReplacements);
|
|
// float angle;
|
|
unitParticleSystemNode->addAttribute("angle",floatToStr(angle,6), mapTagReplacements);
|
|
// float sizeNoEnergy;
|
|
unitParticleSystemNode->addAttribute("sizeNoEnergy",floatToStr(sizeNoEnergy,6), mapTagReplacements);
|
|
// float gravity;
|
|
unitParticleSystemNode->addAttribute("gravity",floatToStr(gravity,6), mapTagReplacements);
|
|
// float rotation;
|
|
unitParticleSystemNode->addAttribute("rotation",floatToStr(rotation,6), mapTagReplacements);
|
|
// bool isVisibleAtNight;
|
|
unitParticleSystemNode->addAttribute("isVisibleAtNight",intToStr(isVisibleAtNight), mapTagReplacements);
|
|
// bool isVisibleAtDay;
|
|
unitParticleSystemNode->addAttribute("isVisibleAtDay",intToStr(isVisibleAtDay), mapTagReplacements);
|
|
// bool isDaylightAffected;
|
|
unitParticleSystemNode->addAttribute("isDaylightAffected",intToStr(isDaylightAffected), mapTagReplacements);
|
|
// bool radiusBasedStartenergy;
|
|
unitParticleSystemNode->addAttribute("radiusBasedStartenergy",intToStr(radiusBasedStartenergy), mapTagReplacements);
|
|
// int staticParticleCount;
|
|
unitParticleSystemNode->addAttribute("staticParticleCount",intToStr(staticParticleCount), mapTagReplacements);
|
|
// int delay;
|
|
unitParticleSystemNode->addAttribute("delay",intToStr(delay), mapTagReplacements);
|
|
// int lifetime;
|
|
unitParticleSystemNode->addAttribute("lifetime",intToStr(lifetime), mapTagReplacements);
|
|
// float emissionRateFade;
|
|
unitParticleSystemNode->addAttribute("emissionRateFade",floatToStr(emissionRateFade,6), mapTagReplacements);
|
|
// GameParticleSystem* parent;
|
|
//if(parent != NULL) {
|
|
// parent->saveGame(unitParticleSystemNode);
|
|
//}
|
|
}
|
|
|
|
void UnitParticleSystem::loadGame(const XmlNode *rootNode) {
|
|
const XmlNode *unitParticleSystemNode = rootNode;
|
|
|
|
//printf("Load Smoke particle (UnitParticleSystem)\n");
|
|
GameParticleSystem::loadGame(unitParticleSystemNode);
|
|
|
|
// float radius;
|
|
radius = unitParticleSystemNode->getAttribute("radius")->getFloatValue();
|
|
// float minRadius;
|
|
minRadius = unitParticleSystemNode->getAttribute("minRadius")->getFloatValue();
|
|
// Vec3f windSpeed;
|
|
windSpeed = Vec3f::strToVec3(unitParticleSystemNode->getAttribute("windSpeed")->getValue());
|
|
// Vec3f cRotation;
|
|
cRotation = Vec3f::strToVec3(unitParticleSystemNode->getAttribute("cRotation")->getValue());
|
|
// Vec3f fixedAddition;
|
|
fixedAddition = Vec3f::strToVec3(unitParticleSystemNode->getAttribute("fixedAddition")->getValue());
|
|
// Vec3f oldPosition;
|
|
oldPosition = Vec3f::strToVec3(unitParticleSystemNode->getAttribute("oldPosition")->getValue());
|
|
// Vec3f meshPos;
|
|
if(unitParticleSystemNode->hasAttribute("meshPos")){
|
|
meshPos = Vec3f::strToVec3(unitParticleSystemNode->getAttribute("meshPos")->getValue());
|
|
}
|
|
// Vec3f meshName;
|
|
if(unitParticleSystemNode->hasAttribute("meshName")){
|
|
meshName = unitParticleSystemNode->getAttribute("meshName")->getValue();
|
|
}
|
|
// bool energyUp;
|
|
energyUp = unitParticleSystemNode->getAttribute("energyUp")->getIntValue() != 0;
|
|
// float startTime;
|
|
startTime = unitParticleSystemNode->getAttribute("startTime")->getFloatValue();
|
|
// float endTime;
|
|
endTime = unitParticleSystemNode->getAttribute("endTime")->getFloatValue();
|
|
// bool relative;
|
|
relative = unitParticleSystemNode->getAttribute("relative")->getIntValue() != 0;
|
|
// bool relativeDirection;
|
|
relativeDirection = unitParticleSystemNode->getAttribute("relativeDirection")->getIntValue() != 0;
|
|
// bool fixed;
|
|
fixed = unitParticleSystemNode->getAttribute("fixed")->getIntValue() != 0;
|
|
// Shape shape;
|
|
shape = static_cast<Shape>(unitParticleSystemNode->getAttribute("shape")->getIntValue());
|
|
// float angle;
|
|
angle = unitParticleSystemNode->getAttribute("angle")->getFloatValue();
|
|
// float sizeNoEnergy;
|
|
sizeNoEnergy = unitParticleSystemNode->getAttribute("sizeNoEnergy")->getFloatValue();
|
|
// float gravity;
|
|
gravity = unitParticleSystemNode->getAttribute("gravity")->getFloatValue();
|
|
// float rotation;
|
|
rotation = unitParticleSystemNode->getAttribute("rotation")->getFloatValue();
|
|
// bool isVisibleAtNight;
|
|
isVisibleAtNight = unitParticleSystemNode->getAttribute("isVisibleAtNight")->getIntValue() != 0;
|
|
// bool isVisibleAtDay;
|
|
isVisibleAtDay = unitParticleSystemNode->getAttribute("isVisibleAtDay")->getIntValue() != 0;
|
|
// bool isDaylightAffected;
|
|
isDaylightAffected = unitParticleSystemNode->getAttribute("isDaylightAffected")->getIntValue() != 0;
|
|
// bool radiusBasedStartenergy;
|
|
radiusBasedStartenergy = unitParticleSystemNode->getAttribute("radiusBasedStartenergy")->getIntValue() != 0;
|
|
// int staticParticleCount;
|
|
staticParticleCount = unitParticleSystemNode->getAttribute("staticParticleCount")->getIntValue();
|
|
// int delay;
|
|
delay = unitParticleSystemNode->getAttribute("delay")->getIntValue();
|
|
// int lifetime;
|
|
lifetime = unitParticleSystemNode->getAttribute("lifetime")->getIntValue();
|
|
// float emissionRateFade;
|
|
emissionRateFade = unitParticleSystemNode->getAttribute("emissionRateFade")->getFloatValue();
|
|
// GameParticleSystem* parent;
|
|
parent = NULL;
|
|
//if(parent != NULL) {
|
|
// parent->saveGame(unitParticleSystemNode);
|
|
//}
|
|
|
|
//if(unitParticleSystemNode->hasChild("GameParticleSystem") == true) {
|
|
// void GameParticleSystem::saveGame(XmlNode *rootNode)
|
|
// std::map<string,string> mapTagReplacements;
|
|
// XmlNode *gameParticleSystemNode = rootNode->addChild("GameParticleSystem");
|
|
//XmlNode *gameParticleSystemNode = unitParticleSystemNode->getChild("GameParticleSystem");
|
|
//!!!
|
|
//}
|
|
}
|
|
|
|
Checksum UnitParticleSystem::getCRC() {
|
|
Checksum crcForParticleSystem = GameParticleSystem::getCRC();
|
|
|
|
return crcForParticleSystem;
|
|
}
|
|
|
|
string UnitParticleSystem::toString() const {
|
|
string result = GameParticleSystem::toString();
|
|
|
|
result += "\nUnitParticleSystem ";
|
|
result += "\nradius = " + floatToStr(radius);
|
|
result += "\nminRadius = " + floatToStr(minRadius);
|
|
result += "\nwindSpeed = " + windSpeed.getString();
|
|
result += "\ncRotation = " + cRotation.getString();
|
|
result += "\nfixedAddition = " + fixedAddition.getString();
|
|
result += "\noldPosition = " + oldPosition.getString();
|
|
result += "\nenergyUp = " + intToStr(energyUp);
|
|
result += "\nstartTime = " + floatToStr(startTime);
|
|
result += "\nendTime = " + floatToStr(endTime);
|
|
result += "\nrelative = " + intToStr(relative);
|
|
result += "\nrelativeDirection = " + intToStr(relativeDirection);
|
|
result += "\nfixed = " + intToStr(fixed);
|
|
result += "\nshape = " + intToStr(shape);
|
|
|
|
result += "\nangle = " + floatToStr(angle);
|
|
result += "\nsizeNoEnergy = " + floatToStr(sizeNoEnergy);
|
|
result += "\ngravity = " + floatToStr(gravity);
|
|
result += "\nrotation = " + floatToStr(rotation);
|
|
result += "\nisVisibleAtNight = " + intToStr(isVisibleAtNight);
|
|
result += "\nisVisibleAtDay = " + intToStr(isVisibleAtDay);
|
|
result += "\nisDaylightAffected = " + intToStr(isDaylightAffected);
|
|
result += "\nradiusBasedStartenergy = " + intToStr(radiusBasedStartenergy);
|
|
result += "\nstaticParticleCount = " + intToStr(staticParticleCount);
|
|
result += "\ndelay = " + intToStr(delay);
|
|
result += "\nlifetime = " + intToStr(lifetime);
|
|
result += "\nemissionRateFade = " + floatToStr(emissionRateFade);
|
|
//GameParticleSystem* parent;
|
|
|
|
return result;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// RainParticleSystem
|
|
// ===========================================================================
|
|
RainParticleSystem::RainParticleSystem(int particleCount) :
|
|
ParticleSystem(particleCount){
|
|
setWind(0.0f, 0.0f);
|
|
setRadius(20.0f);
|
|
|
|
setEmissionRate(25.0f);
|
|
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->pos.x = truncateDecimal<float>(p->pos.x,6);
|
|
p->pos.y = truncateDecimal<float>(p->pos.y,6);
|
|
p->pos.z = truncateDecimal<float>(p->pos.z,6);
|
|
|
|
p->lastPos= p->pos;
|
|
p->speed= Vec3f(random.randRange(-speed / 10, speed / 10), -speed,
|
|
random.randRange(-speed / 10, speed / 10)) + windSpeed;
|
|
p->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
}
|
|
|
|
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){
|
|
#ifdef USE_STREFLOP
|
|
this->windSpeed.x= streflop::sinf(static_cast<streflop::Simple>(degToRad(windAngle)))*windSpeed;
|
|
this->windSpeed.y= 0.0f;
|
|
this->windSpeed.z= streflop::cosf(static_cast<streflop::Simple>(degToRad(windAngle)))*windSpeed;
|
|
#else
|
|
this->windSpeed.x= sinf(degToRad(windAngle)) * windSpeed;
|
|
this->windSpeed.y= 0.0f;
|
|
this->windSpeed.z= cosf(degToRad(windAngle)) * windSpeed;
|
|
#endif
|
|
|
|
this->windSpeed.x = truncateDecimal<float>(this->windSpeed.x,6);
|
|
this->windSpeed.y = truncateDecimal<float>(this->windSpeed.y,6);
|
|
this->windSpeed.z = truncateDecimal<float>(this->windSpeed.z,6);
|
|
}
|
|
|
|
Checksum RainParticleSystem::getCRC() {
|
|
Checksum crcForParticleSystem = ParticleSystem::getCRC();
|
|
|
|
return crcForParticleSystem;
|
|
}
|
|
|
|
string RainParticleSystem::toString() const {
|
|
string result = ParticleSystem::toString();
|
|
|
|
result += "\nRainParticleSystem ";
|
|
result += "\nwindSpeed = " + windSpeed.getString();
|
|
result += "\nradius = " + floatToStr(radius);
|
|
|
|
return result;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// SnowParticleSystem
|
|
// ===========================================================================
|
|
|
|
SnowParticleSystem::SnowParticleSystem(int particleCount) :
|
|
ParticleSystem(particleCount){
|
|
setWind(0.0f, 0.0f);
|
|
setRadius(30.0f);
|
|
|
|
setEmissionRate(2.0f);
|
|
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->pos.x = truncateDecimal<float>(p->pos.x,6);
|
|
p->pos.y = truncateDecimal<float>(p->pos.y,6);
|
|
p->pos.z = truncateDecimal<float>(p->pos.z,6);
|
|
|
|
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);
|
|
|
|
p->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
}
|
|
|
|
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){
|
|
#ifdef USE_STREFLOP
|
|
this->windSpeed.x= streflop::sinf(static_cast<streflop::Simple>(degToRad(windAngle)))*windSpeed;
|
|
this->windSpeed.y= 0.0f;
|
|
this->windSpeed.z= streflop::cosf(static_cast<streflop::Simple>(degToRad(windAngle)))*windSpeed;
|
|
#else
|
|
this->windSpeed.x= sinf(degToRad(windAngle)) * windSpeed;
|
|
this->windSpeed.y= 0.0f;
|
|
this->windSpeed.z= cosf(degToRad(windAngle)) * windSpeed;
|
|
#endif
|
|
|
|
this->windSpeed.x = truncateDecimal<float>(this->windSpeed.x,6);
|
|
this->windSpeed.y = truncateDecimal<float>(this->windSpeed.y,6);
|
|
this->windSpeed.z = truncateDecimal<float>(this->windSpeed.z,6);
|
|
|
|
}
|
|
|
|
Checksum SnowParticleSystem::getCRC() {
|
|
Checksum crcForParticleSystem = ParticleSystem::getCRC();
|
|
|
|
return crcForParticleSystem;
|
|
}
|
|
|
|
string SnowParticleSystem::toString() const {
|
|
string result = ParticleSystem::toString();
|
|
|
|
result += "\nSnowParticleSystem ";
|
|
result += "\nwindSpeed = " + windSpeed.getString();
|
|
result += "\nradius = " + floatToStr(radius);
|
|
|
|
return result;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// AttackParticleSystem
|
|
// ===========================================================================
|
|
|
|
AttackParticleSystem::AttackParticleSystem(int particleCount) :
|
|
GameParticleSystem(particleCount){
|
|
primitive= pQuad;
|
|
gravity= 0.0f;
|
|
sizeNoEnergy = 0.0;
|
|
}
|
|
|
|
void AttackParticleSystem::saveGame(XmlNode *rootNode) {
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *attackParticleSystemNode = rootNode->addChild("AttackParticleSystem");
|
|
|
|
GameParticleSystem::saveGame(attackParticleSystemNode);
|
|
|
|
// float sizeNoEnergy;
|
|
attackParticleSystemNode->addAttribute("sizeNoEnergy",floatToStr(sizeNoEnergy,6), mapTagReplacements);
|
|
// float gravity;
|
|
attackParticleSystemNode->addAttribute("gravity",floatToStr(gravity,6), mapTagReplacements);
|
|
|
|
}
|
|
void AttackParticleSystem::loadGame(const XmlNode *rootNode) {
|
|
const XmlNode *attackParticleSystemNode = rootNode;
|
|
|
|
GameParticleSystem::loadGame(attackParticleSystemNode);
|
|
|
|
// float sizeNoEnergy;
|
|
sizeNoEnergy = attackParticleSystemNode->getAttribute("sizeNoEnergy")->getFloatValue();
|
|
// float gravity;
|
|
gravity = attackParticleSystemNode->getAttribute("gravity")->getFloatValue();
|
|
}
|
|
|
|
Checksum AttackParticleSystem::getCRC() {
|
|
Checksum crcForParticleSystem = GameParticleSystem::getCRC();
|
|
|
|
return crcForParticleSystem;
|
|
}
|
|
|
|
string AttackParticleSystem::toString() const {
|
|
string result = GameParticleSystem::toString();
|
|
|
|
result += "\nAttackParticleSystem ";
|
|
result += "\nsizeNoEnergy = " + floatToStr(sizeNoEnergy);
|
|
result += "\ngravity = " + floatToStr(gravity);
|
|
|
|
return result;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// ProjectileParticleSystem
|
|
// ===========================================================================
|
|
|
|
ProjectileParticleSystem::ProjectileParticleSystem(int particleCount) :
|
|
AttackParticleSystem(particleCount){
|
|
setEmissionRate(20.0f);
|
|
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;
|
|
modelCycle=0.0f;
|
|
|
|
nextParticleSystem= NULL;
|
|
arriveDestinationDistance = 0.0f;
|
|
//printf("#aXX trajectorySpeed = %f\n",trajectorySpeed);
|
|
}
|
|
|
|
ProjectileParticleSystem::~ProjectileParticleSystem(){
|
|
if(nextParticleSystem != NULL){
|
|
nextParticleSystem->prevParticleSystem= NULL;
|
|
}
|
|
}
|
|
|
|
void ProjectileParticleSystem::link(SplashParticleSystem *particleSystem){
|
|
nextParticleSystem= particleSystem;
|
|
nextParticleSystem->setVisible(false);
|
|
nextParticleSystem->setState(sPause);
|
|
nextParticleSystem->prevParticleSystem= this;
|
|
}
|
|
|
|
void ProjectileParticleSystem::update(){
|
|
//printf("Projectile particle system updating...\n");
|
|
if(state == sPlay){
|
|
|
|
lastPos = pos;
|
|
flatPos += zVector * truncateDecimal<float>(trajectorySpeed,6);
|
|
flatPos.x = truncateDecimal<float>(flatPos.x,6);
|
|
flatPos.y = truncateDecimal<float>(flatPos.y,6);
|
|
flatPos.z = truncateDecimal<float>(flatPos.z,6);
|
|
|
|
Vec3f targetVector = endPos - startPos;
|
|
targetVector.x = truncateDecimal<float>(targetVector.x,6);
|
|
targetVector.y = truncateDecimal<float>(targetVector.y,6);
|
|
targetVector.z = truncateDecimal<float>(targetVector.z,6);
|
|
|
|
Vec3f currentVector = flatPos - startPos;
|
|
currentVector.x = truncateDecimal<float>(currentVector.x,6);
|
|
currentVector.y = truncateDecimal<float>(currentVector.y,6);
|
|
currentVector.z = truncateDecimal<float>(currentVector.z,6);
|
|
|
|
// ratio
|
|
float relative= clamp(currentVector.length() / targetVector.length(), 0.0f, 1.0f);
|
|
relative = truncateDecimal<float>(relative,6);
|
|
|
|
float absolute = relative;
|
|
setTween(relative,absolute);
|
|
|
|
// trajectory
|
|
switch(trajectory) {
|
|
case tLinear: {
|
|
pos= flatPos;
|
|
}
|
|
break;
|
|
|
|
case tParabolic: {
|
|
float scaledT = truncateDecimal<float>(2.0f * (relative - 0.5f),6);
|
|
float paraboleY = truncateDecimal<float>((1.0f - scaledT * scaledT) * trajectoryScale,6);
|
|
|
|
pos= flatPos;
|
|
pos.y += paraboleY;
|
|
pos.y = truncateDecimal<float>(pos.y,6);
|
|
}
|
|
break;
|
|
|
|
case tSpiral: {
|
|
pos= flatPos;
|
|
#ifdef USE_STREFLOP
|
|
pos+= xVector * streflop::cos(static_cast<streflop::Simple>(relative * trajectoryFrequency * targetVector.length())) * trajectoryScale;
|
|
pos.x = truncateDecimal<float>(pos.x,6);
|
|
pos.y = truncateDecimal<float>(pos.y,6);
|
|
pos.z = truncateDecimal<float>(pos.z,6);
|
|
|
|
pos+= yVector * streflop::sin(static_cast<streflop::Simple>(relative * trajectoryFrequency * targetVector.length())) * trajectoryScale;
|
|
#else
|
|
pos+= xVector * cos(relative * trajectoryFrequency * targetVector.length()) * trajectoryScale;
|
|
pos.x = truncateDecimal<float>(pos.x,6);
|
|
pos.y = truncateDecimal<float>(pos.y,6);
|
|
pos.z = truncateDecimal<float>(pos.z,6);
|
|
|
|
pos+= yVector * sin(relative * trajectoryFrequency * targetVector.length()) * trajectoryScale;
|
|
#endif
|
|
pos.x = truncateDecimal<float>(pos.x,6);
|
|
pos.y = truncateDecimal<float>(pos.y,6);
|
|
pos.z = truncateDecimal<float>(pos.z,6);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
|
|
direction= (pos - lastPos);
|
|
direction.x = truncateDecimal<float>(direction.x,6);
|
|
direction.y = truncateDecimal<float>(direction.y,6);
|
|
direction.z = truncateDecimal<float>(direction.z,6);
|
|
|
|
direction.normalize();
|
|
direction.x = truncateDecimal<float>(direction.x,6);
|
|
direction.y = truncateDecimal<float>(direction.y,6);
|
|
direction.z = truncateDecimal<float>(direction.z,6);
|
|
|
|
// trigger update of child particles
|
|
positionChildren();
|
|
rotateChildren();
|
|
|
|
//arrive destination
|
|
arriveDestinationDistance = truncateDecimal<float>(flatPos.dist(endPos),6);
|
|
|
|
if(this->particleOwner != NULL) {
|
|
char szBuf[8096]="";
|
|
snprintf(szBuf,8095,"LINE: %d arriveDestinationDistance = %f",__LINE__,arriveDestinationDistance);
|
|
this->particleOwner->logParticleInfo(szBuf);
|
|
}
|
|
|
|
if(arriveDestinationDistance < 0.5f) {
|
|
fade();
|
|
model= NULL;
|
|
|
|
if(particleObserver != NULL){
|
|
particleObserver->update(this);
|
|
particleObserver=NULL;
|
|
}
|
|
|
|
if(nextParticleSystem != NULL){
|
|
nextParticleSystem->setVisible(getVisible());
|
|
nextParticleSystem->setState(sPlay);
|
|
nextParticleSystem->setPos(endPos);
|
|
}
|
|
}
|
|
}
|
|
|
|
ParticleSystem::update();
|
|
}
|
|
|
|
void ProjectileParticleSystem::rotateChildren() {
|
|
//### only on horizontal plane :(
|
|
#ifdef USE_STREFLOP
|
|
float rotation = truncateDecimal<float>(streflop::atan2(static_cast<streflop::Simple>(direction.x), static_cast<streflop::Simple>(direction.z)),6);
|
|
#else
|
|
float rotation = truncateDecimal<float>(atan2(direction.x, direction.z),6);
|
|
#endif
|
|
rotation = truncateDecimal<float>(radToDeg(rotation),6);
|
|
for(Children::iterator it = children.begin(); it != children.end(); ++it)
|
|
(*it)->setRotation(rotation);
|
|
}
|
|
|
|
void ProjectileParticleSystem::initParticle(Particle *p, int particleIndex){
|
|
|
|
ParticleSystem::initParticle(p, particleIndex);
|
|
|
|
float t= static_cast<float> (particleIndex) / emissionRate;
|
|
t = truncateDecimal<float>(t,6);
|
|
|
|
p->pos= pos + (lastPos - pos) * t;
|
|
p->pos.x = truncateDecimal<float>(p->pos.x,6);
|
|
p->pos.y = truncateDecimal<float>(p->pos.y,6);
|
|
p->pos.z = truncateDecimal<float>(p->pos.z,6);
|
|
|
|
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->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
|
|
p->accel= Vec3f(0.0f, -gravity, 0.0f);
|
|
p->accel.x = truncateDecimal<float>(p->accel.x,6);
|
|
p->accel.y = truncateDecimal<float>(p->accel.y,6);
|
|
p->accel.z = truncateDecimal<float>(p->accel.z,6);
|
|
|
|
updateParticle(p);
|
|
}
|
|
|
|
void ProjectileParticleSystem::updateParticle(Particle *p){
|
|
float energyRatio= clamp(static_cast<float> (p->energy) / maxParticleEnergy, 0.f, 1.f);
|
|
energyRatio = truncateDecimal<float>(energyRatio,6);
|
|
|
|
p->lastPos += p->speed;
|
|
p->lastPos.x = truncateDecimal<float>(p->lastPos.x,6);
|
|
p->lastPos.y = truncateDecimal<float>(p->lastPos.y,6);
|
|
p->lastPos.z = truncateDecimal<float>(p->lastPos.z,6);
|
|
|
|
p->pos += p->speed;
|
|
p->pos.x = truncateDecimal<float>(p->pos.x,6);
|
|
p->pos.y = truncateDecimal<float>(p->pos.y,6);
|
|
p->pos.z = truncateDecimal<float>(p->pos.z,6);
|
|
|
|
p->speed += p->accel;
|
|
p->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
|
|
p->color= color * energyRatio + colorNoEnergy * (1.0f - energyRatio);
|
|
p->size = particleSize * energyRatio + sizeNoEnergy * (1.0f - energyRatio);
|
|
p->size = truncateDecimal<float>(p->size,6);
|
|
p->energy--;
|
|
}
|
|
|
|
void ProjectileParticleSystem::setPath(Vec3f startPos, Vec3f endPos) {
|
|
startPos.x = truncateDecimal<float>(startPos.x,6);
|
|
startPos.y = truncateDecimal<float>(startPos.y,6);
|
|
startPos.z = truncateDecimal<float>(startPos.z,6);
|
|
|
|
endPos.x = truncateDecimal<float>(endPos.x,6);
|
|
endPos.y = truncateDecimal<float>(endPos.y,6);
|
|
endPos.z = truncateDecimal<float>(endPos.z,6);
|
|
|
|
//compute axis
|
|
zVector= endPos - startPos;
|
|
zVector.x = truncateDecimal<float>(zVector.x,6);
|
|
zVector.y = truncateDecimal<float>(zVector.y,6);
|
|
zVector.z = truncateDecimal<float>(zVector.z,6);
|
|
|
|
zVector.normalize();
|
|
zVector.x = truncateDecimal<float>(zVector.x,6);
|
|
zVector.y = truncateDecimal<float>(zVector.y,6);
|
|
zVector.z = truncateDecimal<float>(zVector.z,6);
|
|
|
|
yVector= Vec3f(0.0f, 1.0f, 0.0f);
|
|
xVector= zVector.cross(yVector);
|
|
xVector.x = truncateDecimal<float>(xVector.x,6);
|
|
xVector.y = truncateDecimal<float>(xVector.y,6);
|
|
xVector.z = truncateDecimal<float>(xVector.z,6);
|
|
|
|
//apply offset
|
|
startPos += xVector * offset.x;
|
|
startPos.x = truncateDecimal<float>(startPos.x,6);
|
|
startPos.y = truncateDecimal<float>(startPos.y,6);
|
|
startPos.z = truncateDecimal<float>(startPos.z,6);
|
|
|
|
startPos+= yVector * offset.y;
|
|
startPos.x = truncateDecimal<float>(startPos.x,6);
|
|
startPos.y = truncateDecimal<float>(startPos.y,6);
|
|
startPos.z = truncateDecimal<float>(startPos.z,6);
|
|
|
|
startPos+= zVector * offset.z;
|
|
startPos.x = truncateDecimal<float>(startPos.x,6);
|
|
startPos.y = truncateDecimal<float>(startPos.y,6);
|
|
startPos.z = truncateDecimal<float>(startPos.z,6);
|
|
|
|
pos= startPos;
|
|
lastPos= startPos;
|
|
flatPos= startPos;
|
|
|
|
//recompute axis
|
|
zVector= endPos - startPos;
|
|
zVector.x = truncateDecimal<float>(zVector.x,6);
|
|
zVector.y = truncateDecimal<float>(zVector.y,6);
|
|
zVector.z = truncateDecimal<float>(zVector.z,6);
|
|
|
|
zVector.normalize();
|
|
zVector.x = truncateDecimal<float>(zVector.x,6);
|
|
zVector.y = truncateDecimal<float>(zVector.y,6);
|
|
zVector.z = truncateDecimal<float>(zVector.z,6);
|
|
|
|
yVector= Vec3f(0.0f, 1.0f, 0.0f);
|
|
xVector= zVector.cross(yVector);
|
|
xVector.x = truncateDecimal<float>(xVector.x,6);
|
|
xVector.y = truncateDecimal<float>(xVector.y,6);
|
|
xVector.z = truncateDecimal<float>(xVector.z,6);
|
|
|
|
// set members
|
|
this->startPos= startPos;
|
|
this->endPos= endPos;
|
|
|
|
// direction
|
|
direction = (endPos - lastPos);
|
|
direction.x = truncateDecimal<float>(direction.x,6);
|
|
direction.y = truncateDecimal<float>(direction.y,6);
|
|
direction.z = truncateDecimal<float>(direction.z,6);
|
|
|
|
direction.normalize();
|
|
direction.x = truncateDecimal<float>(direction.x,6);
|
|
direction.y = truncateDecimal<float>(direction.y,6);
|
|
direction.z = truncateDecimal<float>(direction.z,6);
|
|
|
|
rotateChildren();
|
|
}
|
|
|
|
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 megaglest_runtime_error("Unknown particle system trajectory: " + str);
|
|
}
|
|
}
|
|
|
|
void ProjectileParticleSystem::saveGame(XmlNode *rootNode) {
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *projectileParticleSystemNode = rootNode->addChild("ProjectileParticleSystem");
|
|
|
|
AttackParticleSystem::saveGame(projectileParticleSystemNode);
|
|
|
|
// SplashParticleSystem *nextParticleSystem;
|
|
if(nextParticleSystem != NULL) {
|
|
nextParticleSystem->saveGame(projectileParticleSystemNode);
|
|
}
|
|
// Vec3f lastPos;
|
|
projectileParticleSystemNode->addAttribute("lastPos",lastPos.getString(), mapTagReplacements);
|
|
// Vec3f startPos;
|
|
projectileParticleSystemNode->addAttribute("startPos",startPos.getString(), mapTagReplacements);
|
|
// Vec3f endPos;
|
|
projectileParticleSystemNode->addAttribute("endPos",endPos.getString(), mapTagReplacements);
|
|
// Vec3f flatPos;
|
|
projectileParticleSystemNode->addAttribute("flatPos",flatPos.getString(), mapTagReplacements);
|
|
//
|
|
// Vec3f xVector;
|
|
projectileParticleSystemNode->addAttribute("xVector",xVector.getString(), mapTagReplacements);
|
|
// Vec3f yVector;
|
|
projectileParticleSystemNode->addAttribute("yVector",yVector.getString(), mapTagReplacements);
|
|
// Vec3f zVector;
|
|
projectileParticleSystemNode->addAttribute("zVector",zVector.getString(), mapTagReplacements);
|
|
// Trajectory trajectory;
|
|
projectileParticleSystemNode->addAttribute("trajectory",intToStr(trajectory), mapTagReplacements);
|
|
// float trajectorySpeed;
|
|
projectileParticleSystemNode->addAttribute("trajectorySpeed",floatToStr(trajectorySpeed,6), mapTagReplacements);
|
|
// //parabolic
|
|
// float trajectoryScale;
|
|
projectileParticleSystemNode->addAttribute("trajectoryScale",floatToStr(trajectoryScale,6), mapTagReplacements);
|
|
// float trajectoryFrequency;
|
|
projectileParticleSystemNode->addAttribute("trajectoryFrequency",floatToStr(trajectoryFrequency,6), mapTagReplacements);
|
|
}
|
|
|
|
void ProjectileParticleSystem::loadGame(const XmlNode *rootNode) {
|
|
const XmlNode *projectileParticleSystemNode = rootNode;
|
|
|
|
AttackParticleSystem::loadGame(projectileParticleSystemNode);
|
|
|
|
// SplashParticleSystem *nextParticleSystem;
|
|
// if(nextParticleSystem != NULL) {
|
|
// nextParticleSystem->saveGame(projectileParticleSystemNode);
|
|
// }
|
|
if(projectileParticleSystemNode->hasChild("SplashParticleSystem") == true) {
|
|
XmlNode *splashParticleSystemNode = projectileParticleSystemNode->getChild("SplashParticleSystem");
|
|
nextParticleSystem = new SplashParticleSystem();
|
|
nextParticleSystem->setParticleOwner(this->getParticleOwner());
|
|
nextParticleSystem->loadGame(splashParticleSystemNode);
|
|
}
|
|
// Vec3f lastPos;
|
|
lastPos = Vec3f::strToVec3(projectileParticleSystemNode->getAttribute("lastPos")->getValue());
|
|
// Vec3f startPos;
|
|
startPos = Vec3f::strToVec3(projectileParticleSystemNode->getAttribute("startPos")->getValue());
|
|
// Vec3f endPos;
|
|
endPos = Vec3f::strToVec3(projectileParticleSystemNode->getAttribute("endPos")->getValue());
|
|
// Vec3f flatPos;
|
|
flatPos = Vec3f::strToVec3(projectileParticleSystemNode->getAttribute("flatPos")->getValue());
|
|
//
|
|
// Vec3f xVector;
|
|
xVector = Vec3f::strToVec3(projectileParticleSystemNode->getAttribute("xVector")->getValue());
|
|
// Vec3f yVector;
|
|
yVector = Vec3f::strToVec3(projectileParticleSystemNode->getAttribute("yVector")->getValue());
|
|
// Vec3f zVector;
|
|
zVector = Vec3f::strToVec3(projectileParticleSystemNode->getAttribute("zVector")->getValue());
|
|
// Trajectory trajectory;
|
|
trajectory = static_cast<Trajectory>(projectileParticleSystemNode->getAttribute("trajectory")->getIntValue());
|
|
// float trajectorySpeed;
|
|
trajectorySpeed = projectileParticleSystemNode->getAttribute("trajectorySpeed")->getFloatValue();
|
|
// //parabolic
|
|
// float trajectoryScale;
|
|
trajectoryScale = projectileParticleSystemNode->getAttribute("trajectoryScale")->getFloatValue();
|
|
// float trajectoryFrequency;
|
|
trajectoryFrequency = projectileParticleSystemNode->getAttribute("trajectoryFrequency")->getFloatValue();
|
|
}
|
|
|
|
Checksum ProjectileParticleSystem::getCRC() {
|
|
Checksum crcForParticleSystem = AttackParticleSystem::getCRC();
|
|
|
|
return crcForParticleSystem;
|
|
}
|
|
|
|
string ProjectileParticleSystem::toString() const {
|
|
string result = AttackParticleSystem::toString();
|
|
|
|
result += "\nProjectileParticleSystem ";
|
|
if(nextParticleSystem != NULL) {
|
|
//result += "\nnextParticleSystem = " + nextParticleSystem->toString() + "\n";
|
|
result += "\nnextParticleSystem = NOT NULL\n";
|
|
}
|
|
result += "\nlastPos = " + lastPos.getString();
|
|
result += "\nstartPos = " + startPos.getString();
|
|
result += "\nendPos = " + endPos.getString();
|
|
result += "\nflatPos = " + flatPos.getString();
|
|
|
|
result += "\nxVector = " + xVector.getString();
|
|
result += "\nyVector = " + yVector.getString();
|
|
result += "\nzVector = " + zVector.getString();
|
|
|
|
result += "\ntrajectory = " + intToStr(trajectory);
|
|
result += "\ntrajectorySpeed = " + floatToStr(trajectorySpeed);
|
|
result += "\ntrajectoryScale = " + floatToStr(trajectoryScale);
|
|
result += "\ntrajectoryFrequency = " + floatToStr(trajectoryFrequency);
|
|
|
|
result += "\narriveDestinationDistance = " + floatToStr(arriveDestinationDistance);
|
|
|
|
return result;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// 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.0f;
|
|
verticalSpreadA= 1.0f;
|
|
verticalSpreadB= 0.0f;
|
|
horizontalSpreadA= 1.0f;
|
|
horizontalSpreadB= 0.0f;
|
|
startEmissionRate= 0.0f;
|
|
}
|
|
|
|
SplashParticleSystem::~SplashParticleSystem(){
|
|
if(prevParticleSystem != NULL){
|
|
prevParticleSystem->nextParticleSystem= NULL;
|
|
}
|
|
}
|
|
|
|
void SplashParticleSystem::initParticleSystem() {
|
|
startEmissionRate = emissionRate;
|
|
}
|
|
|
|
void SplashParticleSystem::update() {
|
|
ParticleSystem::update();
|
|
if(state != sPause) {
|
|
emissionRate -= emissionRateFade;
|
|
emissionRate = truncateDecimal<float>(emissionRate,6);
|
|
|
|
float t = 1.0f - ((emissionRate + startEmissionRate) / (startEmissionRate * 2.0f));
|
|
t = truncateDecimal<float>(t,6);
|
|
|
|
t= clamp(t, 0.0f, 1.0f);
|
|
setTween(t,t);
|
|
|
|
if(this->particleOwner != NULL) {
|
|
char szBuf[8096]="";
|
|
snprintf(szBuf,8095,"LINE: %d emissionRate = %f",__LINE__,emissionRate);
|
|
this->particleOwner->logParticleInfo(szBuf);
|
|
}
|
|
|
|
if(emissionRate < 0.0f) {//otherwise this system lives forever!
|
|
fade();
|
|
}
|
|
}
|
|
}
|
|
|
|
void SplashParticleSystem::initParticle(Particle *p, int particleIndex){
|
|
p->pos= pos;
|
|
p->lastPos= p->pos;
|
|
p->energy= maxParticleEnergy;
|
|
p->size= particleSize;
|
|
p->color= color;
|
|
p->speedUpRelative= speedUpRelative;
|
|
|
|
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.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
|
|
p->speed.normalize();
|
|
p->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
|
|
p->speed= p->speed * speed;
|
|
p->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
|
|
p->accel= Vec3f(0.0f, -gravity, 0.0f);
|
|
p->accel.x = truncateDecimal<float>(p->accel.x,6);
|
|
p->accel.y = truncateDecimal<float>(p->accel.y,6);
|
|
p->accel.z = truncateDecimal<float>(p->accel.z,6);
|
|
|
|
p->speedUpConstant= Vec3f(speedUpConstant)*p->speed;
|
|
}
|
|
|
|
void SplashParticleSystem::updateParticle(Particle *p){
|
|
float energyRatio= clamp(static_cast<float> (p->energy) / maxParticleEnergy, 0.f, 1.f);
|
|
|
|
p->lastPos= p->pos;
|
|
p->pos= p->pos + p->speed;
|
|
p->pos.x = truncateDecimal<float>(p->pos.x,6);
|
|
p->pos.y = truncateDecimal<float>(p->pos.y,6);
|
|
p->pos.z = truncateDecimal<float>(p->pos.z,6);
|
|
|
|
p->speed += p->speedUpConstant;
|
|
p->speed=p->speed*(1+p->speedUpRelative);
|
|
p->speed= p->speed + p->accel;
|
|
p->speed.x = truncateDecimal<float>(p->speed.x,6);
|
|
p->speed.y = truncateDecimal<float>(p->speed.y,6);
|
|
p->speed.z = truncateDecimal<float>(p->speed.z,6);
|
|
|
|
p->energy--;
|
|
p->color= color * energyRatio + colorNoEnergy * (1.0f - energyRatio);
|
|
p->size= particleSize * energyRatio + sizeNoEnergy * (1.0f - energyRatio);
|
|
p->size = truncateDecimal<float>(p->size,6);
|
|
}
|
|
|
|
void SplashParticleSystem::saveGame(XmlNode *rootNode) {
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *splashParticleSystemNode = rootNode->addChild("SplashParticleSystem");
|
|
|
|
AttackParticleSystem::saveGame(splashParticleSystemNode);
|
|
|
|
// ProjectileParticleSystem *prevParticleSystem;
|
|
if(prevParticleSystem != NULL) {
|
|
prevParticleSystem->saveGame(splashParticleSystemNode);
|
|
}
|
|
|
|
// float emissionRateFade;
|
|
splashParticleSystemNode->addAttribute("emissionRateFade",floatToStr(emissionRateFade,6), mapTagReplacements);
|
|
// float verticalSpreadA;
|
|
splashParticleSystemNode->addAttribute("verticalSpreadA",floatToStr(verticalSpreadA,6), mapTagReplacements);
|
|
// float verticalSpreadB;
|
|
splashParticleSystemNode->addAttribute("verticalSpreadB",floatToStr(verticalSpreadB,6), mapTagReplacements);
|
|
// float horizontalSpreadA;
|
|
splashParticleSystemNode->addAttribute("horizontalSpreadA",floatToStr(horizontalSpreadA,6), mapTagReplacements);
|
|
// float horizontalSpreadB;
|
|
splashParticleSystemNode->addAttribute("horizontalSpreadB",floatToStr(horizontalSpreadB,6), mapTagReplacements);
|
|
//
|
|
// float startEmissionRate;
|
|
splashParticleSystemNode->addAttribute("startEmissionRate",floatToStr(startEmissionRate,6), mapTagReplacements);
|
|
}
|
|
|
|
void SplashParticleSystem::loadGame(const XmlNode *rootNode) {
|
|
const XmlNode *splashParticleSystemNode = rootNode;
|
|
|
|
AttackParticleSystem::loadGame(splashParticleSystemNode);
|
|
|
|
// ProjectileParticleSystem *prevParticleSystem;
|
|
// if(nextParticleSystem != NULL) {
|
|
// nextParticleSystem->saveGame(projectileParticleSystemNode);
|
|
// }
|
|
if(splashParticleSystemNode->hasChild("ProjectileParticleSystem") == true) {
|
|
XmlNode *projectileParticleSystemNode = splashParticleSystemNode->getChild("ProjectileParticleSystem");
|
|
prevParticleSystem = new ProjectileParticleSystem();
|
|
prevParticleSystem->setParticleOwner(this->getParticleOwner());
|
|
prevParticleSystem->loadGame(projectileParticleSystemNode);
|
|
}
|
|
|
|
// float emissionRateFade;
|
|
emissionRateFade = splashParticleSystemNode->getAttribute("emissionRateFade")->getFloatValue();
|
|
// float verticalSpreadA;
|
|
verticalSpreadA = splashParticleSystemNode->getAttribute("verticalSpreadA")->getFloatValue();
|
|
// float verticalSpreadB;
|
|
verticalSpreadB = splashParticleSystemNode->getAttribute("verticalSpreadB")->getFloatValue();
|
|
// float horizontalSpreadA;
|
|
horizontalSpreadA = splashParticleSystemNode->getAttribute("horizontalSpreadA")->getFloatValue();
|
|
// float horizontalSpreadB;
|
|
horizontalSpreadB = splashParticleSystemNode->getAttribute("horizontalSpreadB")->getFloatValue();
|
|
// float startEmissionRate;
|
|
startEmissionRate = splashParticleSystemNode->getAttribute("startEmissionRate")->getFloatValue();
|
|
}
|
|
|
|
Checksum SplashParticleSystem::getCRC() {
|
|
Checksum crcForParticleSystem = AttackParticleSystem::getCRC();
|
|
|
|
return crcForParticleSystem;
|
|
}
|
|
|
|
string SplashParticleSystem::toString() const {
|
|
string result = AttackParticleSystem::toString();
|
|
|
|
result += "\nSplashParticleSystem ";
|
|
if(prevParticleSystem != NULL) {
|
|
//result += "\nprevParticleSystem = " + prevParticleSystem->toString() + "\n";
|
|
result += "\nprevParticleSystem = NOT NULL\n";
|
|
}
|
|
|
|
result += "\nemissionRateFade = " + floatToStr(emissionRateFade);
|
|
result += "\nverticalSpreadA = " + floatToStr(verticalSpreadA);
|
|
result += "\nverticalSpreadB = " + floatToStr(verticalSpreadB);
|
|
result += "\nhorizontalSpreadA = " + floatToStr(horizontalSpreadA);
|
|
result += "\nhorizontalSpreadB = " + floatToStr(horizontalSpreadB);
|
|
result += "\nstartEmissionRate = " + floatToStr(startEmissionRate);
|
|
|
|
return result;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// ParticleManager
|
|
// ===========================================================================
|
|
|
|
ParticleManager::ParticleManager() {
|
|
}
|
|
|
|
ParticleManager::~ParticleManager() {
|
|
end();
|
|
}
|
|
|
|
void ParticleManager::render(ParticleRenderer *pr, ModelRenderer *mr) const{
|
|
for(unsigned int i= 0; i < particleSystems.size(); i++){
|
|
ParticleSystem *ps= particleSystems[i];
|
|
if(ps != NULL && ps->getVisible()){
|
|
ps->render(pr, mr);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ParticleManager::hasActiveParticleSystem(ParticleSystem::ParticleSystemType type) const{
|
|
bool result= false;
|
|
|
|
//size_t particleSystemCount= particleSystems.size();
|
|
//int currentParticleCount= 0;
|
|
|
|
//vector<ParticleSystem *> cleanupParticleSystemsList;
|
|
for(unsigned int i= 0; i < particleSystems.size(); i++){
|
|
ParticleSystem *ps= particleSystems[i];
|
|
if(ps != NULL){
|
|
//currentParticleCount+= ps->getAliveParticleCount();
|
|
|
|
bool showParticle= true;
|
|
if(dynamic_cast<UnitParticleSystem *> (ps) != NULL ||
|
|
dynamic_cast<FireParticleSystem *> (ps) != NULL) {
|
|
showParticle= ps->getVisible() || (ps->getState() == ParticleSystem::sFade);
|
|
}
|
|
if(showParticle == true){
|
|
//printf("Looking for [%d] current id [%d] i = %d\n",type,ps->getParticleSystemType(),i);
|
|
|
|
if(type == ParticleSystem::pst_All || type == ps->getParticleSystemType()){
|
|
//printf("FOUND particle system type match for [%d] current id [%d] i = %d\n",type,ps->getParticleSystemType(),i);
|
|
result= true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void ParticleManager::update(int renderFps){
|
|
Chrono chrono;
|
|
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
|
|
|
|
size_t particleSystemCount= particleSystems.size();
|
|
int currentParticleCount= 0;
|
|
|
|
vector<ParticleSystem *> cleanupParticleSystemsList;
|
|
for(unsigned int i= 0; i < particleSystems.size(); i++){
|
|
ParticleSystem *ps= particleSystems[i];
|
|
if(ps != NULL) {
|
|
currentParticleCount+= ps->getAliveParticleCount();
|
|
|
|
bool showParticle= true;
|
|
if( dynamic_cast<UnitParticleSystem *> (ps) != NULL ||
|
|
dynamic_cast<FireParticleSystem *> (ps) != NULL) {
|
|
showParticle = ps->getVisible() || (ps->getState() == ParticleSystem::sFade);
|
|
}
|
|
if(showParticle == true){
|
|
ps->update();
|
|
if(ps->isEmpty() && ps->getState() == ParticleSystem::sFade) {
|
|
cleanupParticleSystemsList.push_back(ps);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//particleSystems.remove(NULL);
|
|
cleanupParticleSystems(cleanupParticleSystemsList);
|
|
|
|
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0)
|
|
SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld, particleSystemCount = %d, currentParticleCount = %d\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis(),particleSystemCount,currentParticleCount);
|
|
}
|
|
|
|
bool ParticleManager::validateParticleSystemStillExists(ParticleSystem * particleSystem) const{
|
|
int index= findParticleSystems(particleSystem, this->particleSystems);
|
|
return (index >= 0);
|
|
}
|
|
|
|
void ParticleManager::removeParticleSystemsForParticleOwner(ParticleOwner *particleOwner) {
|
|
if(particleOwner != NULL && particleSystems.empty() == false) {
|
|
vector<ParticleSystem *> cleanupParticleSystemsList;
|
|
|
|
for(unsigned int index = 0; index < particleSystems.size(); ++index) {
|
|
ParticleSystem *ps= particleSystems[index];
|
|
if(ps != NULL && ps->getParticleOwner() == particleOwner) {
|
|
cleanupParticleSystemsList.push_back(ps);
|
|
}
|
|
}
|
|
if(cleanupParticleSystemsList.empty() == false) {
|
|
cleanupParticleSystems(cleanupParticleSystemsList);
|
|
}
|
|
}
|
|
}
|
|
|
|
int ParticleManager::findParticleSystems(ParticleSystem *psFind, const vector<ParticleSystem *> &particleSystems) const{
|
|
int result= -1;
|
|
for(unsigned int i= 0; i < particleSystems.size(); i++){
|
|
ParticleSystem *ps= particleSystems[i];
|
|
if(ps != NULL && psFind != NULL && psFind == ps){
|
|
result= i;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void ParticleManager::cleanupParticleSystems(ParticleSystem *ps) {
|
|
|
|
int index= findParticleSystems(ps, this->particleSystems);
|
|
if(ps != NULL && index >= 0) {
|
|
// printf("-- Delete cleanupParticleSystems [%p]\n",ps);
|
|
// static map<void *,int> deleteList;
|
|
// if(deleteList.find(ps) != deleteList.end()) {
|
|
// assert(deleteList.find(ps) == deleteList.end());
|
|
// }
|
|
// deleteList[ps]++;
|
|
|
|
// This code causes segfault on game end, no need to fade, just delete
|
|
//if(ps->getState() != ParticleSystem::sFade) {
|
|
// ps->fade();
|
|
//}
|
|
|
|
if(ps != NULL) {
|
|
ps->callParticleOwnerEnd(ps);
|
|
}
|
|
|
|
delete ps;
|
|
this->particleSystems.erase(this->particleSystems.begin() + index);
|
|
}
|
|
}
|
|
|
|
void ParticleManager::cleanupParticleSystems(vector<ParticleSystem *> &cleanupParticleSystemsList){
|
|
if(cleanupParticleSystemsList.empty() == false) {
|
|
for(int i= (int)cleanupParticleSystemsList.size()-1; i >= 0; i--) {
|
|
ParticleSystem *ps= cleanupParticleSystemsList[i];
|
|
cleanupParticleSystems(ps);
|
|
}
|
|
|
|
cleanupParticleSystemsList.clear();
|
|
}
|
|
}
|
|
|
|
void ParticleManager::cleanupUnitParticleSystems(vector<UnitParticleSystem *> &cleanupParticleSystemsList){
|
|
if(cleanupParticleSystemsList.empty() == false) {
|
|
for(int i= (int)cleanupParticleSystemsList.size()-1; i >= 0; i--) {
|
|
ParticleSystem *ps= cleanupParticleSystemsList[i];
|
|
cleanupParticleSystems(ps);
|
|
}
|
|
cleanupParticleSystemsList.clear();
|
|
}
|
|
}
|
|
|
|
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(){
|
|
while(particleSystems.empty() == false){
|
|
ParticleSystem *ps = particleSystems.back();
|
|
|
|
// printf("-- Delete end() [%p]\n",ps);
|
|
// static map<void *,int> deleteList;
|
|
// if(deleteList.find(ps) != deleteList.end()) {
|
|
// assert(deleteList.find(ps) == deleteList.end());
|
|
// }
|
|
// deleteList[ps]++;
|
|
|
|
if(ps != NULL) {
|
|
ps->callParticleOwnerEnd(ps);
|
|
}
|
|
delete ps;
|
|
particleSystems.pop_back();
|
|
}
|
|
}
|
|
|
|
}
|
|
}//end namespace
|