/* 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_GRAPHICS #include "particle_engine.h" #include "class_list.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 () { /// @todo we must not do this, because PNoe does it for us /// or we do this with help from ClassList, which essentially makes much more sense // delete all remaining systems // tIterator* sysIt = this->systemList->getIterator(); // ParticleSystem* tmpSys = sysIt->firstElement(); // while(tmpSys) // { // delete tmpSys; // tmpSys = sysIt->nextElement(); // } // delete sysIt; delete this->systemList; // // delete all remaining emitters tIterator* emitIt = this->emitterList->getIterator(); ParticleEmitter* tmpEmit = emitIt->firstElement(); 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) { LOAD_PARAM_START_CYCLE(root, element); { LoadParam_CYCLE(element, "connect", this, ParticleEngine, addConnection) .describe("connects an Emitter to a System (emitterName, systemName)"); } LOAD_PARAM_END_CYCLE(element); } /** * 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 = dynamic_cast(ClassList::getObject(emitter, CL_PARTICLE_EMITTER));//this->getEmitterByName(emitter); ParticleSystem* tmpSys = dynamic_cast(ClassList::getObject(system, CL_PARTICLE_SYSTEM));//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->firstElement(); while(tmpConnection) { if (tmpConnection->emitter == emitter && tmpConnection->system == system) { PRINTF(2)("Connection between Emitter and System already exists.\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->firstElement(); while(tmpConnection != NULL) { 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->firstElement(); while(tmpConnection != NULL) { 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 connection the connection to remove * * \see bool ParticleEngine::breakConnection(ParticleEmitter* emitter, ParticleSystem* system) */ bool ParticleEngine::breakConnection(ParticleConnection* connection) { this->connectionList->remove(connection); return true; } /** * 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->firstElement(); 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 emitter The emitter of the connections to remove * @returns the count of connections that were broken, 0 if no conntection was not found */ unsigned int ParticleEngine::breakConnections(ParticleEmitter* emitter) { unsigned int retVal = 0; // look, if we have already added this connection tIterator* tmpConIt = connectionList->getIterator(); ParticleConnection* tmpConnection = tmpConIt->firstElement(); while(tmpConnection) { if (tmpConnection->emitter == emitter) { this->breakConnection(tmpConnection); retVal++; } tmpConnection = tmpConIt->nextElement(); } delete tmpConIt; return retVal; } /** * removes a Connection between an Emitter and a System * @param system The system of the connections to remove * @returns the count of connections that were broken, 0 if no conntection was not found */ unsigned int ParticleEngine::breakConnections(ParticleSystem* system) { unsigned int retVal = 0; // look, if we have already added this connection tIterator* tmpConIt = connectionList->getIterator(); ParticleConnection* tmpConnection = tmpConIt->firstElement(); while(tmpConnection) { if (tmpConnection->system == system) { this->breakConnection(tmpConnection); retVal++; } tmpConnection = tmpConIt->nextElement(); } delete tmpConIt; return retVal; } /** * 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->firstElement(); // 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->firstElement(); 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->firstElement(); while(tmpSys) { tmpSys->draw(); tmpSys = tmpIt->nextElement(); } delete tmpIt;*/ } /** * @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->firstElement(); while(tmpSys) { count++; if ( count == number) { delete tmpIt; return tmpSys; } tmpSys = 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->firstElement(); 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->firstElement(); 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->firstElement(); 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->firstElement(); while(tmpEmit) { tmpEmit->debug(); tmpEmit = tmpIt->nextElement(); } delete tmpIt; } else { PRINTF(0)("NO EMITTERS\n"); } PRINT(0)("+--------------------------------PE-+\n"); }