/* ----------------------------------------------------------------------------- This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ Copyright (c) 2000-2006 Torus Knot Software Ltd Also see acknowledgements in Readme.html This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt. You may alternatively use this source under the terms of a specific version of the OGRE Unrestricted License provided you have obtained such a license from Torus Knot Software Ltd. ----------------------------------------------------------------------------- */ #include "OgreStableHeaders.h" #include "OgreParticleEmitter.h" #include "OgreParticleEmitterFactory.h" namespace Ogre { // Define static members EmitterCommands::CmdAngle ParticleEmitter::msAngleCmd; EmitterCommands::CmdColour ParticleEmitter::msColourCmd; EmitterCommands::CmdColourRangeStart ParticleEmitter::msColourRangeStartCmd; EmitterCommands::CmdColourRangeEnd ParticleEmitter::msColourRangeEndCmd; EmitterCommands::CmdDirection ParticleEmitter::msDirectionCmd; EmitterCommands::CmdEmissionRate ParticleEmitter::msEmissionRateCmd; EmitterCommands::CmdMaxTTL ParticleEmitter::msMaxTTLCmd; EmitterCommands::CmdMaxVelocity ParticleEmitter::msMaxVelocityCmd; EmitterCommands::CmdMinTTL ParticleEmitter::msMinTTLCmd; EmitterCommands::CmdMinVelocity ParticleEmitter::msMinVelocityCmd; EmitterCommands::CmdPosition ParticleEmitter::msPositionCmd; EmitterCommands::CmdTTL ParticleEmitter::msTTLCmd; EmitterCommands::CmdVelocity ParticleEmitter::msVelocityCmd; EmitterCommands::CmdDuration ParticleEmitter::msDurationCmd; EmitterCommands::CmdMinDuration ParticleEmitter::msMinDurationCmd; EmitterCommands::CmdMaxDuration ParticleEmitter::msMaxDurationCmd; EmitterCommands::CmdRepeatDelay ParticleEmitter::msRepeatDelayCmd; EmitterCommands::CmdMinRepeatDelay ParticleEmitter::msMinRepeatDelayCmd; EmitterCommands::CmdMaxRepeatDelay ParticleEmitter::msMaxRepeatDelayCmd; EmitterCommands::CmdName ParticleEmitter::msNameCmd; EmitterCommands::CmdEmittedEmitter ParticleEmitter::msEmittedEmitterCmd; //----------------------------------------------------------------------- ParticleEmitter::ParticleEmitter(ParticleSystem* psys) : mParent(psys), mStartTime(0), mDurationMin(0), mDurationMax(0), mDurationRemain(0), mRepeatDelayMin(0), mRepeatDelayMax(0), mRepeatDelayRemain(0) { // Reasonable defaults mAngle = 0; setDirection(Vector3::UNIT_X); mEmissionRate = 10; mMaxSpeed = mMinSpeed = 1; mMaxTTL = mMinTTL = 5; mPosition = Vector3::ZERO; mColourRangeStart = mColourRangeEnd = ColourValue::White; mEnabled = true; mRemainder = 0; mName = StringUtil::BLANK; mEmittedEmitter = StringUtil::BLANK; mEmitted = false; } //----------------------------------------------------------------------- ParticleEmitter::~ParticleEmitter() { } //----------------------------------------------------------------------- void ParticleEmitter::setPosition(const Vector3& pos) { mPosition = pos; } //----------------------------------------------------------------------- const Vector3& ParticleEmitter::getPosition(void) const { return mPosition; } //----------------------------------------------------------------------- void ParticleEmitter::setDirection(const Vector3& direction) { mDirection = direction; mDirection.normalise(); // Generate an up vector (any will do) mUp = mDirection.perpendicular(); mUp.normalise(); } //----------------------------------------------------------------------- const Vector3& ParticleEmitter::getDirection(void) const { return mDirection; } //----------------------------------------------------------------------- void ParticleEmitter::setAngle(const Radian& angle) { // Store as radians for efficiency mAngle = angle; } //----------------------------------------------------------------------- const Radian& ParticleEmitter::getAngle(void) const { return mAngle; } //----------------------------------------------------------------------- void ParticleEmitter::setParticleVelocity(Real speed) { mMinSpeed = mMaxSpeed = speed; } //----------------------------------------------------------------------- void ParticleEmitter::setParticleVelocity(Real min, Real max) { mMinSpeed = min; mMaxSpeed = max; } //----------------------------------------------------------------------- void ParticleEmitter::setEmissionRate(Real particlesPerSecond) { mEmissionRate = particlesPerSecond; } //----------------------------------------------------------------------- Real ParticleEmitter::getEmissionRate(void) const { return mEmissionRate; } //----------------------------------------------------------------------- void ParticleEmitter::setTimeToLive(Real ttl) { mMinTTL = mMaxTTL = ttl; } //----------------------------------------------------------------------- void ParticleEmitter::setTimeToLive(Real minTtl, Real maxTtl) { mMinTTL = minTtl; mMaxTTL = maxTtl; } //----------------------------------------------------------------------- void ParticleEmitter::setColour(const ColourValue& colour) { mColourRangeStart = mColourRangeEnd = colour; } //----------------------------------------------------------------------- void ParticleEmitter::setColour(const ColourValue& colourStart, const ColourValue& colourEnd) { mColourRangeStart = colourStart; mColourRangeEnd = colourEnd; } //----------------------------------------------------------------------- const String& ParticleEmitter::getName(void) const { return mName; } //----------------------------------------------------------------------- void ParticleEmitter::setName(const String& newName) { mName = newName; } //----------------------------------------------------------------------- const String& ParticleEmitter::getEmittedEmitter(void) const { return mEmittedEmitter; } //----------------------------------------------------------------------- void ParticleEmitter::setEmittedEmitter(const String& emittedEmitter) { mEmittedEmitter = emittedEmitter; } //----------------------------------------------------------------------- bool ParticleEmitter::isEmitted(void) const { return mEmitted; } //----------------------------------------------------------------------- void ParticleEmitter::setEmitted(bool emitted) { mEmitted = emitted; } //----------------------------------------------------------------------- void ParticleEmitter::genEmissionDirection(Vector3& destVector) { if (mAngle != Radian(0)) { // Randomise angle Radian angle = Math::UnitRandom() * mAngle; // Randomise direction destVector = mDirection.randomDeviant(angle, mUp); } else { // Constant angle destVector = mDirection; } // Don't normalise, we can assume that it will still be a unit vector since // both direction and 'up' are. } //----------------------------------------------------------------------- void ParticleEmitter::genEmissionVelocity(Vector3& destVector) { Real scalar; if (mMinSpeed != mMaxSpeed) { scalar = mMinSpeed + (Math::UnitRandom() * (mMaxSpeed - mMinSpeed)); } else { scalar = mMinSpeed; } destVector *= scalar; } //----------------------------------------------------------------------- Real ParticleEmitter::genEmissionTTL(void) { if (mMaxTTL != mMinTTL) { return mMinTTL + (Math::UnitRandom() * (mMaxTTL - mMinTTL)); } else { return mMinTTL; } } //----------------------------------------------------------------------- unsigned short ParticleEmitter::genConstantEmissionCount(Real timeElapsed) { unsigned short intRequest; if (mEnabled) { // Keep fractions, otherwise a high frame rate will result in zero emissions! mRemainder += mEmissionRate * timeElapsed; intRequest = (unsigned short)mRemainder; mRemainder -= intRequest; // Check duration if (mDurationMax) { mDurationRemain -= timeElapsed; if (mDurationRemain <= 0) { // Disable, duration is out (takes effect next time) setEnabled(false); } } return intRequest; } else { // Check repeat if (mRepeatDelayMax) { mRepeatDelayRemain -= timeElapsed; if (mRepeatDelayRemain <= 0) { // Enable, repeat delay is out (takes effect next time) setEnabled(true); } } if(mStartTime) { mStartTime -= timeElapsed; if(mStartTime <= 0) { setEnabled(true); mStartTime = 0; } } return 0; } } //----------------------------------------------------------------------- void ParticleEmitter::genEmissionColour(ColourValue& destColour) { if (mColourRangeStart != mColourRangeEnd) { // Randomise //Real t = Math::UnitRandom(); destColour.r = mColourRangeStart.r + (Math::UnitRandom() * (mColourRangeEnd.r - mColourRangeStart.r)); destColour.g = mColourRangeStart.g + (Math::UnitRandom() * (mColourRangeEnd.g - mColourRangeStart.g)); destColour.b = mColourRangeStart.b + (Math::UnitRandom() * (mColourRangeEnd.b - mColourRangeStart.b)); destColour.a = mColourRangeStart.a + (Math::UnitRandom() * (mColourRangeEnd.a - mColourRangeStart.a)); } else { destColour = mColourRangeStart; } } //----------------------------------------------------------------------- void ParticleEmitter::addBaseParameters(void) { ParamDictionary* dict = getParamDictionary(); dict->addParameter(ParameterDef("angle", "The angle up to which particles may vary in their initial direction " "from the emitters direction, in degrees." , PT_REAL), &msAngleCmd); dict->addParameter(ParameterDef("colour", "The colour of emitted particles.", PT_COLOURVALUE), &msColourCmd); dict->addParameter(ParameterDef("colour_range_start", "The start of a range of colours to be assigned to emitted particles.", PT_COLOURVALUE), &msColourRangeStartCmd); dict->addParameter(ParameterDef("colour_range_end", "The end of a range of colours to be assigned to emitted particles.", PT_COLOURVALUE), &msColourRangeEndCmd); dict->addParameter(ParameterDef("direction", "The base direction of the emitter." , PT_VECTOR3), &msDirectionCmd); dict->addParameter(ParameterDef("emission_rate", "The number of particles emitted per second." , PT_REAL), &msEmissionRateCmd); dict->addParameter(ParameterDef("position", "The position of the emitter relative to the particle system center." , PT_VECTOR3), &msPositionCmd); dict->addParameter(ParameterDef("velocity", "The initial velocity to be assigned to every particle, in world units per second." , PT_REAL), &msVelocityCmd); dict->addParameter(ParameterDef("velocity_min", "The minimum initial velocity to be assigned to each particle." , PT_REAL), &msMinVelocityCmd); dict->addParameter(ParameterDef("velocity_max", "The maximum initial velocity to be assigned to each particle." , PT_REAL), &msMaxVelocityCmd); dict->addParameter(ParameterDef("time_to_live", "The lifetime of each particle in seconds." , PT_REAL), &msTTLCmd); dict->addParameter(ParameterDef("time_to_live_min", "The minimum lifetime of each particle in seconds." , PT_REAL), &msMinTTLCmd); dict->addParameter(ParameterDef("time_to_live_max", "The maximum lifetime of each particle in seconds." , PT_REAL), &msMaxTTLCmd); dict->addParameter(ParameterDef("duration", "The length of time in seconds which an emitter stays enabled for." , PT_REAL), &msDurationCmd); dict->addParameter(ParameterDef("duration_min", "The minimum length of time in seconds which an emitter stays enabled for." , PT_REAL), &msMinDurationCmd); dict->addParameter(ParameterDef("duration_max", "The maximum length of time in seconds which an emitter stays enabled for." , PT_REAL), &msMaxDurationCmd); dict->addParameter(ParameterDef("repeat_delay", "If set, after disabling an emitter will repeat (reenable) after this many seconds." , PT_REAL), &msRepeatDelayCmd); dict->addParameter(ParameterDef("repeat_delay_min", "If set, after disabling an emitter will repeat (reenable) after this minimum number of seconds." , PT_REAL), &msMinRepeatDelayCmd); dict->addParameter(ParameterDef("repeat_delay_max", "If set, after disabling an emitter will repeat (reenable) after this maximum number of seconds." , PT_REAL), &msMaxRepeatDelayCmd); dict->addParameter(ParameterDef("name", "This is the name of the emitter" , PT_STRING), &msNameCmd); dict->addParameter(ParameterDef("emit_emitter", "If set, this emitter will emit other emitters instead of visual particles" , PT_STRING), &msEmittedEmitterCmd); } //----------------------------------------------------------------------- Real ParticleEmitter::getParticleVelocity(void) const { return mMinSpeed; } //----------------------------------------------------------------------- Real ParticleEmitter::getMinParticleVelocity(void) const { return mMinSpeed; } //----------------------------------------------------------------------- Real ParticleEmitter::getMaxParticleVelocity(void) const { return mMaxSpeed; } //----------------------------------------------------------------------- void ParticleEmitter::setMinParticleVelocity(Real min) { mMinSpeed = min; } //----------------------------------------------------------------------- void ParticleEmitter::setMaxParticleVelocity(Real max) { mMaxSpeed = max; } //----------------------------------------------------------------------- Real ParticleEmitter::getTimeToLive(void) const { return mMinTTL; } //----------------------------------------------------------------------- Real ParticleEmitter::getMinTimeToLive(void) const { return mMinTTL; } //----------------------------------------------------------------------- Real ParticleEmitter::getMaxTimeToLive(void) const { return mMaxTTL; } //----------------------------------------------------------------------- void ParticleEmitter::setMinTimeToLive(Real min) { mMinTTL = min; } //----------------------------------------------------------------------- void ParticleEmitter::setMaxTimeToLive(Real max) { mMaxTTL = max; } //----------------------------------------------------------------------- const ColourValue& ParticleEmitter::getColour(void) const { return mColourRangeStart; } //----------------------------------------------------------------------- const ColourValue& ParticleEmitter::getColourRangeStart(void) const { return mColourRangeStart; } //----------------------------------------------------------------------- const ColourValue& ParticleEmitter::getColourRangeEnd(void) const { return mColourRangeEnd; } //----------------------------------------------------------------------- void ParticleEmitter::setColourRangeStart(const ColourValue& val) { mColourRangeStart = val; } //----------------------------------------------------------------------- void ParticleEmitter::setColourRangeEnd(const ColourValue& val ) { mColourRangeEnd = val; } //----------------------------------------------------------------------- void ParticleEmitter::setEnabled(bool enabled) { mEnabled = enabled; // Reset duration & repeat initDurationRepeat(); } //----------------------------------------------------------------------- bool ParticleEmitter::getEnabled(void) const { return mEnabled; } //----------------------------------------------------------------------- void ParticleEmitter::setStartTime(Real startTime) { setEnabled(false); mStartTime = startTime; } //----------------------------------------------------------------------- Real ParticleEmitter::getStartTime(void) const { return mStartTime; } //----------------------------------------------------------------------- void ParticleEmitter::setDuration(Real duration) { setDuration(duration, duration); } //----------------------------------------------------------------------- Real ParticleEmitter::getDuration(void) const { return mDurationMin; } //----------------------------------------------------------------------- void ParticleEmitter::setDuration(Real min, Real max) { mDurationMin = min; mDurationMax = max; initDurationRepeat(); } //----------------------------------------------------------------------- void ParticleEmitter::setMinDuration(Real min) { mDurationMin = min; initDurationRepeat(); } //----------------------------------------------------------------------- void ParticleEmitter::setMaxDuration(Real max) { mDurationMax = max; initDurationRepeat(); } //----------------------------------------------------------------------- void ParticleEmitter::initDurationRepeat(void) { if (mEnabled) { if (mDurationMin == mDurationMax) { mDurationRemain = mDurationMin; } else { mDurationRemain = Math::RangeRandom(mDurationMin, mDurationMax); } } else { // Reset repeat if (mRepeatDelayMin == mRepeatDelayMax) { mRepeatDelayRemain = mRepeatDelayMin; } else { mRepeatDelayRemain = Math::RangeRandom(mRepeatDelayMax, mRepeatDelayMin); } } } //----------------------------------------------------------------------- void ParticleEmitter::setRepeatDelay(Real delay) { setRepeatDelay(delay, delay); } //----------------------------------------------------------------------- Real ParticleEmitter::getRepeatDelay(void) const { return mRepeatDelayMin; } //----------------------------------------------------------------------- void ParticleEmitter::setRepeatDelay(Real min, Real max) { mRepeatDelayMin = min; mRepeatDelayMax = max; initDurationRepeat(); } //----------------------------------------------------------------------- void ParticleEmitter::setMinRepeatDelay(Real min) { mRepeatDelayMin = min; initDurationRepeat(); } //----------------------------------------------------------------------- void ParticleEmitter::setMaxRepeatDelay(Real max) { mRepeatDelayMax = max; initDurationRepeat(); } //----------------------------------------------------------------------- Real ParticleEmitter::getMinDuration(void) const { return mDurationMin; } //----------------------------------------------------------------------- Real ParticleEmitter::getMaxDuration(void) const { return mDurationMax; } //----------------------------------------------------------------------- Real ParticleEmitter::getMinRepeatDelay(void) const { return mRepeatDelayMin; } //----------------------------------------------------------------------- Real ParticleEmitter::getMaxRepeatDelay(void) const { return mRepeatDelayMax; } //----------------------------------------------------------------------- ParticleEmitterFactory::~ParticleEmitterFactory() { // Destroy all emitters std::vector::iterator i; for (i = mEmitters.begin(); i != mEmitters.end(); ++i) { delete (*i); } mEmitters.clear(); } //----------------------------------------------------------------------- void ParticleEmitterFactory::destroyEmitter(ParticleEmitter* e) { std::vector::iterator i; for (i = mEmitters.begin(); i != mEmitters.end(); ++i) { if ((*i) == e) { mEmitters.erase(i); delete e; break; } } } //----------------------------------------------------------------------- }