/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: ... co-programmer: ... */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_PARTICLE #include "particle_engine.h" #include "particle_system.h" #include "particle_emitter.h" #include "list.h" #include "debug.h" #include "stdlibincl.h" #include "load_param.h" using namespace std; /** * standard constructor */ ParticleEngine::ParticleEngine () { this->setClassID(CL_PARTICLE_ENGINE, "ParticleEngine"); this->setName("ParticleEngine"); this->systemList = new tList; this->emitterList = new tList; this->connectionList = new tList; } /** * the singleton reference to this class */ ParticleEngine* ParticleEngine::singletonRef = NULL; /** * deletes all the system, emitters, connections and Lists */ ParticleEngine::~ParticleEngine () { // delete all remaining systems tIterator* sysIt = this->systemList->getIterator(); ParticleSystem* tmpSys = sysIt->nextElement(); while(tmpSys) { delete tmpSys; tmpSys = sysIt->nextElement(); } delete sysIt; delete this->systemList; // delete all remaining emitters tIterator* emitIt = this->emitterList->getIterator(); ParticleEmitter* tmpEmit = emitIt->nextElement(); while(tmpEmit) { delete tmpEmit; tmpEmit = emitIt->nextElement(); } delete emitIt; delete this->emitterList; // there should be no more Connections if (this->connectionList->getSize() == 0) delete this->connectionList; else PRINTF(2)("The Connection List is not empty. This should not happen.\n"); ParticleEngine::singletonRef = NULL; } /** \brief loads the ParticleEngines settings and connections between particles and emitters * @param root the XML-element to load this from. */ void ParticleEngine::loadParams(const TiXmlElement* root) { const TiXmlElement* element = root->FirstChildElement(); while( element != NULL) { LoadParam(element, "connect", this, &ParticleEngine::addConnection, true) .describe("connects an Emitter to a System (emitterName, systemName)"); element = element->NextSiblingElement(); } } /** * Adds a System to the System list. this is done automatically when creating a ParticleSystem */ void ParticleEngine::addSystem(ParticleSystem* system) { this->systemList->add(system); } /** * Adds an emitter to the emitterList this is done automatically when creating a ParticleEmitter */ void ParticleEngine::addEmitter(ParticleEmitter* emitter) { this->emitterList->add(emitter); } /** \brief Connects a ParticleSystem to a ParticleSystem thus emitting Particles. * @param emitter the Emitter to connect to the System * @param system the System to connect to the Emitter */ void ParticleEngine::addConnection(const char* emitter, const char* system) { ParticleEmitter* tmpEmit = this->getEmitterByName(emitter); ParticleSystem* tmpSys = this->getSystemByName(system); if (tmpEmit != NULL && tmpSys != NULL) this->addConnection(tmpEmit, tmpSys); else { if (tmpEmit == NULL) PRINTF(2)("Emitter %s not found in the List of emitters, not connecting to %s\n", emitter, system); if (tmpEmit == NULL) PRINTF(2)("System %s not found in the List of emitters, not connecting to %s\n", system, emitter); } } /** * Connects a ParticleSystem to a ParticleSystem thus emitting Particles. * @param emitter the Emitter to connect to the System * @param system the System to connect to the Emitter */ void ParticleEngine::addConnection(ParticleEmitter* emitter, ParticleSystem* system) { // look, if we have already added this connection tIterator* tmpConIt = connectionList->getIterator(); ParticleConnection* tmpConnection = tmpConIt->nextElement(); while(tmpConnection) { if (tmpConnection->emitter == emitter && tmpConnection->system == system) { PRINTF(2)("Connection between Emitter and System already added\n"); delete tmpConIt; return; } tmpConnection = tmpConIt->nextElement(); } delete tmpConIt; ParticleConnection* tmpCon = new ParticleConnection; tmpCon->emitter = emitter; tmpCon->system = system; this->connectionList->add(tmpCon); } /** * Removes a system from the systemList and also removes all Connections to the System * @param system The ParticleSystem to delete */ bool ParticleEngine::removeSystem(ParticleSystem* system) { // remove any connections, that have this system within tIterator* tmpConIt = connectionList->getIterator(); ParticleConnection* tmpConnection = tmpConIt->nextElement(); while(tmpConnection) { if (tmpConnection->system == system) this->breakConnection(tmpConnection); tmpConnection = tmpConIt->nextElement(); } delete tmpConIt; // remove the System from the systemList. this->systemList->remove(system); } /** * removes an emitter from the emitterList and also from all Connections it is attached to. * @param emitter the ParticleEmitter to remove. */ bool ParticleEngine::removeEmitter(ParticleEmitter* emitter) { // remove any connections, that have this emitter within tIterator* tmpConIt = connectionList->getIterator(); ParticleConnection* tmpConnection = tmpConIt->nextElement(); while(tmpConnection) { if (tmpConnection->emitter == emitter) this->breakConnection(tmpConnection); tmpConnection = tmpConIt->nextElement(); } delete tmpConIt; // remove the emitter from the emitterList this->emitterList->remove(emitter); } /** * removes a Connection between an Emitter and a System * @param emitter The emitter of the connection to remove * @param system The system of the connection to remove * @returns true, if the connection was broken, false if the conntection was not found only if both system and emitter are in the connection the Connection will be broken */ bool ParticleEngine::breakConnection(ParticleEmitter* emitter, ParticleSystem* system) { // look, if we have already added this connection tIterator* tmpConIt = connectionList->getIterator(); ParticleConnection* tmpConnection = tmpConIt->nextElement(); while(tmpConnection) { if (tmpConnection->emitter == emitter && tmpConnection->system == system) { this->breakConnection(tmpConnection); delete tmpConIt; return true; } tmpConnection = tmpConIt->nextElement(); } delete tmpConIt; return false; } /** * removes a Connection between an Emitter and a System * @param connection the connection to remove \see bool ParticleEngine::breakConnection(ParticleEmitter* emitter, ParticleSystem* system) */ bool ParticleEngine::breakConnection(ParticleConnection* connection) { this->connectionList->remove(connection); return true; } /** * this function ticks all the ParticleSystems, so an animation will flow * @param dt passed since last tick */ void ParticleEngine::tick(float dt) { // ticks all the ParticleSystems tIterator* tmpIt = systemList->getIterator(); ParticleSystem* tmpSys = tmpIt->nextElement(); while(tmpSys) { tmpSys->tick(dt); tmpSys = tmpIt->nextElement(); } delete tmpIt; // add new Particles to each System connected to an Emitter. tIterator* tmpConIt = connectionList->getIterator(); ParticleConnection* tmpConnection = tmpConIt->nextElement(); while(tmpConnection) { tmpConnection->emitter->tick(dt, tmpConnection->system); tmpConnection = tmpConIt->nextElement(); } delete tmpConIt; } /** * draws all the systems and their Particles. */ void ParticleEngine::draw() const { tIterator* tmpIt = systemList->getIterator(); ParticleSystem* tmpSys = tmpIt->nextElement(); while(tmpSys) { tmpSys->draw(); tmpSys = tmpIt->nextElement(); } delete tmpIt; } /** * @param systemName the name of the system to search for * @returns the system called by systemName or NULL if not found */ ParticleSystem* ParticleEngine::getSystemByName(const char* systemName) const { tIterator* tmpIt = systemList->getIterator(); ParticleSystem* tmpSys = tmpIt->nextElement(); while(tmpSys) { if (!strcmp(systemName, tmpSys->getName())) { delete tmpIt; return tmpSys; } tmpSys = tmpIt->nextElement(); } delete tmpIt; return NULL; } /** * @param number the n-th system to return * @returns the system called by number or NULL if not found */ ParticleSystem* ParticleEngine::getSystemByNumber(unsigned int number) const { int count = 0; tIterator* tmpIt = systemList->getIterator(); ParticleSystem* tmpSys = tmpIt->nextElement(); while(tmpSys) { count++; if ( count == number) { delete tmpIt; return tmpSys; } tmpSys = tmpIt->nextElement(); } delete tmpIt; return NULL; } /** * @param emitterName the name of the emitter to search for * @returns the emitter called by emitterName or NULL if not found */ ParticleEmitter* ParticleEngine::getEmitterByName(const char* emitterName) const { tIterator* tmpIt = emitterList->getIterator(); ParticleEmitter* tmpEmit = tmpIt->nextElement(); while(tmpEmit) { if (!strcmp(emitterName, tmpEmit->getName())) { delete tmpIt; return tmpEmit; } tmpEmit = tmpIt->nextElement(); } delete tmpIt; return NULL; } /** * @param number the n-th emitter to return * @returns the emitter called by number or NULL if not found */ ParticleEmitter* ParticleEngine::getEmitterByNumber(unsigned int number) const { int count = 0; tIterator* tmpIt = emitterList->getIterator(); ParticleEmitter* tmpEmit = tmpIt->nextElement(); while(tmpEmit) { count++; if ( count == number) { delete tmpIt; return tmpEmit; } tmpEmit = tmpIt->nextElement(); } delete tmpIt; return NULL; } /** * outputs some nice debug information */ void ParticleEngine::debug() { PRINT(0)("+-----------------------------------+\n"); PRINT(0)("+ PARTICLE-ENGINE DEBUG INFORMATION +\n"); PRINT(0)("+-----------------------------------+\n"); PRINT(0)(" Reference: %p\n", ParticleEngine::singletonRef); PRINT(0)(" Count: Emitters: %d; Systems: %d, Connections: %d\n", this->emitterList->getSize(), this->systemList->getSize(), this->connectionList->getSize()); if (this->connectionList->getSize() > 0) { PRINT(0)(" Connections:\n"); PRINT(0)(" -----------------------------------\n"); tIterator* tmpConIt = connectionList->getIterator(); ParticleConnection* tmpConnection = tmpConIt->nextElement(); while(tmpConnection) { PRINT(0)(" Emitter '%s' emitts into System '%s'\n", tmpConnection->emitter->getName(), tmpConnection->system->getName()); tmpConnection = tmpConIt->nextElement(); } delete tmpConIt; } if (this->systemList->getSize() > 0) { tIterator* tmpIt = systemList->getIterator(); ParticleSystem* tmpSys = tmpIt->nextElement(); while(tmpSys) { tmpSys->debug(); tmpSys = tmpIt->nextElement(); } delete tmpIt; } else { PRINT(0)("NO SYSTEMS\n"); } if (this->emitterList->getSize() > 0) { tIterator* tmpIt = emitterList->getIterator(); ParticleEmitter* tmpEmit = tmpIt->nextElement(); while(tmpEmit) { tmpEmit->debug(); tmpEmit = tmpIt->nextElement(); } delete tmpIt; } else { PRINTF(0)("NO EMITTERS\n"); } PRINT(0)("+--------------------------------PE-+\n"); }