Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreParticleSystem.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreStableHeaders.h"
00026 
00027 #include "OgreParticleSystem.h"
00028 #include "OgreParticleSystemManager.h"
00029 #include "OgreRenderQueue.h"
00030 #include "OgreBillboardSet.h"
00031 #include "OgreParticleEmitter.h"
00032 #include "OgreParticleAffector.h"
00033 #include "OgreParticle.h"
00034 #include "OgreSceneNode.h"
00035 #include "OgreCamera.h"
00036 #include "OgreStringConverter.h"
00037 #include "OgreLogManager.h"
00038 #include "OgreException.h"
00039 
00040 
00041 
00042 namespace Ogre {
00043     // Init statics
00044     ParticleSystem::CmdCull ParticleSystem::msCullCmd;
00045     ParticleSystem::CmdHeight ParticleSystem::msHeightCmd;
00046     ParticleSystem::CmdMaterial ParticleSystem::msMaterialCmd;
00047     ParticleSystem::CmdQuota ParticleSystem::msQuotaCmd;
00048     ParticleSystem::CmdWidth ParticleSystem::msWidthCmd;
00049     ParticleSystem::CmdBillboardType ParticleSystem::msBillboardTypeCmd;
00050     ParticleSystem::CmdCommonDirection ParticleSystem::msCommonDirectionCmd;
00051 
00052     //-----------------------------------------------------------------------
00053     ParticleSystem::ParticleSystem()
00054     {
00055         initParameters();
00056     }
00057     //-----------------------------------------------------------------------
00058     ParticleSystem::ParticleSystem(const String& name)
00059     {
00060         // DO NOT use superclass constructor
00061         // This will call setPoolSize in the BillboardSet context and create Billboard objects
00062         //  instead of Particle objects
00063         // Unavoidable due to C++ funky virtualisation rules & constructors
00064         //mpPositions = 0;
00065         //mpColours = 0;
00066         //mpIndexes = 0;
00067         mVertexData = 0;
00068         mIndexData = 0;
00069         //mpTexCoords = 0;
00070         mAutoExtendPool = true;
00071         mAllDefaultSize = true;
00072         mOriginType = BBO_CENTER;
00073         mName = name;
00074         mCullIndividual = true;
00075         setDefaultDimensions( 100, 100 );
00076         setMaterialName( "BaseWhite" );
00077         // Default to 10 particles, expect app to specify (will only be increased, not decreased)
00078         setPoolSize( 10 );
00079 
00080         initParameters();
00081 
00082     }
00083     //-----------------------------------------------------------------------
00084     ParticleSystem::~ParticleSystem()
00085     {
00086         // Arrange for the deletion of emitters & affectors
00087         removeAllEmitters();
00088         removeAllAffectors();
00089     }
00090     //-----------------------------------------------------------------------
00091     ParticleEmitter* ParticleSystem::addEmitter(const String& emitterType)
00092     {
00093         ParticleEmitter* em = ParticleSystemManager::getSingleton()._createEmitter(emitterType);
00094         mEmitters.push_back(em);
00095         return em;
00096     }
00097     //-----------------------------------------------------------------------
00098     ParticleEmitter* ParticleSystem::getEmitter(unsigned short index) const
00099     {
00100         assert(index < mEmitters.size() && "Emitter index out of bounds!");
00101         return mEmitters[index];
00102     }
00103     //-----------------------------------------------------------------------
00104     unsigned short ParticleSystem::getNumEmitters(void) const
00105     {
00106         return static_cast< unsigned short >( mEmitters.size() );
00107     }
00108     //-----------------------------------------------------------------------
00109     void ParticleSystem::removeEmitter(unsigned short index)
00110     {
00111         assert(index < mEmitters.size() && "Emitter index out of bounds!");
00112         ParticleEmitterList::iterator ei = mEmitters.begin() + index;
00113         ParticleSystemManager::getSingleton()._destroyEmitter(*ei);
00114         mEmitters.erase(ei);
00115     }
00116     //-----------------------------------------------------------------------
00117     void ParticleSystem::removeAllEmitters(void)
00118     {
00119         // DON'T delete directly, we don't know what heap these have been created on
00120         ParticleEmitterList::iterator ei;
00121         for (ei = mEmitters.begin(); ei != mEmitters.end(); ++ei)
00122         {
00123             ParticleSystemManager::getSingleton()._destroyEmitter(*ei);
00124         }
00125         mEmitters.clear();
00126     }
00127     //-----------------------------------------------------------------------
00128     ParticleAffector* ParticleSystem::addAffector(const String& affectorType)
00129     {
00130         ParticleAffector* af = ParticleSystemManager::getSingleton()._createAffector(affectorType);
00131         mAffectors.push_back(af);
00132         return af;
00133     }
00134     //-----------------------------------------------------------------------
00135     ParticleAffector* ParticleSystem::getAffector(unsigned short index) const
00136     {
00137         assert(index < mAffectors.size() && "Affector index out of bounds!");
00138         return mAffectors[index];
00139     }
00140     //-----------------------------------------------------------------------
00141     unsigned short ParticleSystem::getNumAffectors(void) const
00142     {
00143         return static_cast< unsigned short >( mAffectors.size() );
00144     }
00145     //-----------------------------------------------------------------------
00146     void ParticleSystem::removeAffector(unsigned short index)
00147     {
00148         assert(index < mAffectors.size() && "Affector index out of bounds!");
00149         ParticleAffectorList::iterator ai = mAffectors.begin() + index;
00150         ParticleSystemManager::getSingleton()._destroyAffector(*ai);
00151         mAffectors.erase(ai);
00152     }
00153     //-----------------------------------------------------------------------
00154     void ParticleSystem::removeAllAffectors(void)
00155     {
00156         // DON'T delete directly, we don't know what heap these have been created on
00157         ParticleAffectorList::iterator ai;
00158         for (ai = mAffectors.begin(); ai != mAffectors.end(); ++ai)
00159         {
00160             ParticleSystemManager::getSingleton()._destroyAffector(*ai);
00161         }
00162         mAffectors.clear();
00163     }
00164     //-----------------------------------------------------------------------
00165     ParticleSystem& ParticleSystem::operator=(const ParticleSystem& rhs)
00166     {
00167         // Blank this system's emitters & affectors
00168         removeAllEmitters();
00169         removeAllAffectors();
00170 
00171         // Copy emitters
00172         unsigned int i;
00173         for(i = 0; i < rhs.getNumEmitters(); ++i)
00174         {
00175             ParticleEmitter* rhsEm = rhs.getEmitter(i);
00176             ParticleEmitter* newEm = addEmitter(rhsEm->getType());
00177             rhsEm->copyParametersTo(newEm);
00178         }
00179         // Copy affectors
00180         for(i = 0; i < rhs.getNumAffectors(); ++i)
00181         {
00182             ParticleAffector* rhsAf = rhs.getAffector(i);
00183             ParticleAffector* newAf = addAffector(rhsAf->getType());
00184             rhsAf->copyParametersTo(newAf);
00185         }
00186         setPoolSize(rhs.getPoolSize());
00187         setMaterialName(rhs.mMaterialName);
00188         mOriginType = rhs.mOriginType;
00189         mDefaultHeight = rhs.mDefaultHeight;
00190         mDefaultWidth = rhs.mDefaultWidth;
00191         mCullIndividual = rhs.mCullIndividual;
00192         mBillboardType = rhs.mBillboardType;
00193         mCommonDirection = rhs.mCommonDirection;
00194 
00195 
00196         return *this;
00197 
00198     }
00199     //-----------------------------------------------------------------------
00200     unsigned int ParticleSystem::getNumParticles(void) const
00201     {
00202         return (unsigned int)mActiveBillboards.size();
00203     }
00204     //-----------------------------------------------------------------------
00205     unsigned int ParticleSystem::getParticleQuota(void) const
00206     {
00207         // This is basically a renamed property
00208         return getPoolSize();
00209     }
00210     //-----------------------------------------------------------------------
00211     void ParticleSystem::setParticleQuota(unsigned int quota)
00212     {
00213         // This is basically a renamed property
00214         setPoolSize(quota);
00215     }
00216     //-----------------------------------------------------------------------
00217     void ParticleSystem::_update(Real timeElapsed)
00218     {
00219         // Only update if attached to a node
00220         if (mParentNode)
00221         {
00222             // Update existing particles
00223             _expire(timeElapsed);
00224             _triggerAffectors(timeElapsed);
00225             _applyMotion(timeElapsed);
00226             // Emit new particles
00227             _triggerEmitters(timeElapsed);
00228             // Update bounds
00229             _updateBounds();
00230         }
00231         
00232 
00233     }
00234     //-----------------------------------------------------------------------
00235     void ParticleSystem::_expire(Real timeElapsed)
00236     {
00237         ActiveBillboardList::iterator i, itEnd;
00238         Particle* pParticle;
00239 
00240         itEnd = mActiveBillboards.end();
00241 
00242         for (i = mActiveBillboards.begin(); i != itEnd; )
00243         {
00244             pParticle = static_cast<Particle*>(*i);
00245             if (pParticle->mTimeToLive < timeElapsed)
00246             {
00247                 // Destroy this one
00248                 mFreeBillboards.push_back( *i );
00249                 i = mActiveBillboards.erase( i );
00250             }
00251             else
00252             {
00253                 // Decrement TTL
00254                 pParticle->mTimeToLive -= timeElapsed;
00255                 ++i;
00256             }
00257 
00258         }
00259     }
00260     //-----------------------------------------------------------------------
00261     void ParticleSystem::_triggerEmitters(Real timeElapsed)
00262     {
00263         // Add up requests for emission
00264         static std::vector<unsigned> requested;
00265         if( requested.size() != mEmitters.size() )
00266             requested.resize( mEmitters.size() );
00267 
00268         size_t totalRequested, emitterCount, i, emissionAllowed;
00269         ParticleEmitterList::iterator   itEmit, iEmitEnd;
00270         ParticleAffectorList::iterator  itAff, itAffEnd;
00271                 
00272         iEmitEnd = mEmitters.end();
00273         emitterCount = mEmitters.size();
00274         emissionAllowed = getParticleQuota() - mActiveBillboards.size();
00275         totalRequested = 0;
00276 
00277         // Count up total requested emissions
00278         for (itEmit = mEmitters.begin(), i = 0; itEmit != iEmitEnd; ++itEmit, ++i)
00279         {
00280             requested[i] = (*itEmit)->_getEmissionCount(timeElapsed);
00281             totalRequested += requested[i];
00282         }
00283 
00284 
00285         // Check if the quota will be exceeded, if so reduce demand
00286         if (totalRequested > emissionAllowed)
00287         {
00288             // Apportion down requested values to allotted values
00289             Real ratio =  (Real)emissionAllowed / (Real)totalRequested;
00290             for (i = 0; i < emitterCount; ++i)
00291             {
00292                 requested[i] *= (unsigned int)ratio;
00293             }
00294         }
00295 
00296         // Emit
00297         // For each emission, apply a subset of the motion for the frame
00298         // this ensures an even distribution of particles when many are
00299         // emitted in a single frame
00300         for (itEmit = mEmitters.begin(), i = 0; itEmit != iEmitEnd; ++itEmit, ++i)
00301         {
00302             Real timePoint = 0.0f;
00303             Real timeInc = timeElapsed / requested[i];
00304             for (unsigned int j = 0; j < requested[i]; ++j)
00305             {
00306                 // Create a new particle & init using emitter
00307                 Particle* p = addParticle();
00308                 (*itEmit)->_initParticle(p);
00309 
00310                 // Translate position & direction into world space
00311                 // Maybe make emitter do this?
00312                 p->mPosition  = (mParentNode->_getDerivedOrientation() * p->mPosition) + mParentNode->_getDerivedPosition();
00313                 p->mDirection = (mParentNode->_getDerivedOrientation() * p->mDirection);
00314 
00315                 // apply partial frame motion to this particle
00316                 p->mPosition += (p->mDirection * timePoint);
00317 
00318                 // apply particle initialization by the affectors
00319                 itAffEnd = mAffectors.end();
00320                 for (itAff = mAffectors.begin(); itAff != itAffEnd; ++itAff)
00321                     (*itAff)->_initParticle(p);
00322 
00323                 // Increment time fragment
00324                 timePoint += timeInc;
00325             }
00326         }
00327 
00328 
00329     }
00330     //-----------------------------------------------------------------------
00331     void ParticleSystem::_applyMotion(Real timeElapsed)
00332     {
00333         ActiveBillboardList::iterator i, itEnd;
00334         Particle* pParticle;
00335 
00336         itEnd = mActiveBillboards.end();
00337         for (i = mActiveBillboards.begin(); i != itEnd; ++i)
00338         {
00339             pParticle = static_cast<Particle*>(*i);
00340             pParticle->mPosition += (pParticle->mDirection * timeElapsed);
00341         }
00342 
00343     }
00344     //-----------------------------------------------------------------------
00345     void ParticleSystem::_triggerAffectors(Real timeElapsed)
00346     {
00347         ParticleAffectorList::iterator i, itEnd;
00348         
00349         itEnd = mAffectors.end();
00350         for (i = mAffectors.begin(); i != itEnd; ++i)
00351         {
00352             (*i)->_affectParticles(this, timeElapsed);
00353         }
00354 
00355     }
00356     //-----------------------------------------------------------------------
00357     void ParticleSystem::increasePool(unsigned int size)
00358     {
00359         size_t oldSize = mBillboardPool.size();
00360 
00361         // Increase size
00362         mBillboardPool.reserve(size);
00363         mBillboardPool.resize(size);
00364 
00365         // Create new particles
00366         for( size_t i = oldSize; i < size; i++ )
00367             mBillboardPool[i] = new Particle();
00368 
00369     }
00370     //-----------------------------------------------------------------------
00371     ParticleIterator ParticleSystem::_getIterator(void)
00372     {
00373         return ParticleIterator(mActiveBillboards.begin(), mActiveBillboards.end());
00374     }
00375     //-----------------------------------------------------------------------
00376     Particle* ParticleSystem::addParticle(void)
00377     {
00378         // Fast creation (don't use superclass since emitter will init)
00379         Billboard* newBill = mFreeBillboards.front();
00380         mFreeBillboards.pop_front();
00381         mActiveBillboards.push_back(newBill);
00382 
00383         newBill->_notifyOwner(this);
00384 
00385         // Because we're creating objects here we know this is a Particle
00386         return static_cast<Particle*>(newBill);
00387 
00388     }
00389     //-----------------------------------------------------------------------
00390     void ParticleSystem::genBillboardAxes(const Camera& cam, Vector3* pX, Vector3 *pY, const Billboard* pBill)    
00391     {
00392         // Orientation different from BillboardSet
00393         // Billboards are in world space (to decouple them from emitters in node space)
00394         Quaternion camQ;
00395 
00396         switch (mBillboardType)
00397         {
00398         case BBT_POINT:
00399             // Get camera world axes for X and Y (depth is irrelevant)
00400             // No inverse transform
00401             camQ = cam.getDerivedOrientation();
00402             *pX = camQ * Vector3::UNIT_X;
00403             *pY = camQ * Vector3::UNIT_Y;
00404            
00405             break;
00406         case BBT_ORIENTED_COMMON:
00407              // Y-axis is common direction
00408             // X-axis is cross with camera direction 
00409             *pY = mCommonDirection;
00410             *pX = cam.getDerivedDirection().crossProduct(*pY);
00411            
00412             break;
00413         case BBT_ORIENTED_SELF:
00414             // Y-axis is direction
00415             // X-axis is cross with camera direction 
00416 
00417             // Scale direction first
00418             *pY = (pBill->mDirection * 0.01);
00419             *pX = cam.getDerivedDirection().crossProduct(*pY);
00420 
00421             break;
00422         }
00423 
00424     }
00425     //-----------------------------------------------------------------------
00426     void ParticleSystem::getWorldTransforms(Matrix4* xform) const
00427     {
00428         // Particles are already in world space
00429         *xform = Matrix4::IDENTITY;
00430 
00431     }
00432     //-----------------------------------------------------------------------
00433     const Quaternion& ParticleSystem::getWorldOrientation(void) const
00434     {
00435         return mParentNode->_getDerivedOrientation();
00436     }
00437     //-----------------------------------------------------------------------
00438     const Vector3& ParticleSystem::getWorldPosition(void) const
00439     {
00440         return mParentNode->_getDerivedPosition();
00441     }
00442     //-----------------------------------------------------------------------
00443     void ParticleSystem::initParameters(void)
00444     {
00445         if (createParamDictionary("ParticleSystem"))
00446         {
00447             ParamDictionary* dict = getParamDictionary();
00448 
00449             dict->addParameter(ParameterDef("quota", 
00450                 "The maximum number of particle allowed at once in this system.",
00451                 PT_UNSIGNED_INT),
00452                 &msQuotaCmd);
00453 
00454             dict->addParameter(ParameterDef("material", 
00455                 "The name of the material to be used to render all particles in this system.",
00456                 PT_STRING),
00457                 &msMaterialCmd);
00458 
00459             dict->addParameter(ParameterDef("particle_width", 
00460                 "The width of particles in world units.",
00461                 PT_REAL),
00462                 &msWidthCmd);
00463 
00464             dict->addParameter(ParameterDef("particle_height", 
00465                 "The height of particles in world units.",
00466                 PT_REAL),
00467                 &msHeightCmd);
00468 
00469             dict->addParameter(ParameterDef("cull_each", 
00470                 "If true, each particle is culled in it's own right. If false, the entire system is culled as a whole.",
00471                 PT_BOOL),
00472                 &msCullCmd);
00473 
00474             dict->addParameter(ParameterDef("billboard_type", 
00475                 "The type of billboard to use. 'point' means a simulated spherical particle, " 
00476                 "'oriented_common' means all particles in the set are oriented around common_direction, "
00477                 "and 'oriented_self' means particles are oriented around their own direction.",
00478                 PT_STRING),
00479                 &msBillboardTypeCmd);
00480 
00481             dict->addParameter(ParameterDef("common_direction", 
00482                 "Only useful when billboard_type is oriented_common. This parameter sets the common "
00483                 "orientation for all particles in the set (e.g. raindrops may all be oriented downwards).",
00484                 PT_VECTOR3),
00485                 &msCommonDirectionCmd);
00486 
00487         }
00488     }
00489     //-----------------------------------------------------------------------
00490     void ParticleSystem::_updateBounds()
00491     {
00492         // Call superclass
00493         BillboardSet::_updateBounds();
00494 
00495         if (mParentNode && !mAABB.isNull())
00496         {
00497             // Have to override because bounds are supposed to be in local node space
00498             // but we've already put particles in world space to decouple them from the
00499             // node transform, so reverse transform back
00500 
00501             Vector3 min( Math::POS_INFINITY, Math::POS_INFINITY, Math::POS_INFINITY );
00502             Vector3 max( Math::NEG_INFINITY, Math::NEG_INFINITY, Math::NEG_INFINITY );
00503             Vector3 temp;
00504             const Vector3 *corner = mAABB.getAllCorners();
00505             Quaternion invQ = mParentNode->_getDerivedOrientation().Inverse();
00506             Vector3 t = mParentNode->_getDerivedPosition();
00507 
00508             for (int i = 0; i < 8; ++i)
00509             {
00510                 // Reverse transform corner
00511                 temp = invQ * (corner[i] - t);
00512                 min.makeFloor(temp);
00513                 max.makeCeil(temp);
00514             }
00515             mAABB.setExtents(min, max);
00516         }
00517     }
00518     //-----------------------------------------------------------------------
00519 
00520     void ParticleSystem::fastForward(Real time, Real interval)
00521     {
00522         // First make sure all transforms are up to date
00523 
00524         for (Real ftime = 0; ftime < time; ftime += interval)
00525         {
00526             _update(interval);
00527         }
00528     }
00529     //-----------------------------------------------------------------------
00530     const String& ParticleSystem::getMovableType(void) const
00531     {
00532         static String mType = "ParticleSystem";
00533         return mType;
00534     }
00535 
00536     //-----------------------------------------------------------------------
00537     String ParticleSystem::CmdCull::doGet(const void* target) const
00538     {
00539         return StringConverter::toString(
00540             static_cast<const ParticleSystem*>(target)->getCullIndividually() );
00541     }
00542     void ParticleSystem::CmdCull::doSet(void* target, const String& val)
00543     {
00544         static_cast<ParticleSystem*>(target)->setCullIndividually(
00545             StringConverter::parseBool(val));
00546     }
00547     //-----------------------------------------------------------------------
00548     String ParticleSystem::CmdHeight::doGet(const void* target) const
00549     {
00550         return StringConverter::toString(
00551             static_cast<const ParticleSystem*>(target)->getDefaultHeight() );
00552     }
00553     void ParticleSystem::CmdHeight::doSet(void* target, const String& val)
00554     {
00555         static_cast<ParticleSystem*>(target)->setDefaultHeight(
00556             StringConverter::parseReal(val));
00557     }
00558     //-----------------------------------------------------------------------
00559     String ParticleSystem::CmdWidth::doGet(const void* target) const
00560     {
00561         return StringConverter::toString(
00562             static_cast<const ParticleSystem*>(target)->getDefaultWidth() );
00563     }
00564     void ParticleSystem::CmdWidth::doSet(void* target, const String& val)
00565     {
00566         static_cast<ParticleSystem*>(target)->setDefaultWidth(
00567             StringConverter::parseReal(val));
00568     }
00569     //-----------------------------------------------------------------------
00570     String ParticleSystem::CmdMaterial::doGet(const void* target) const
00571     {
00572         return static_cast<const ParticleSystem*>(target)->getMaterialName();
00573     }
00574     void ParticleSystem::CmdMaterial::doSet(void* target, const String& val)
00575     {
00576         static_cast<ParticleSystem*>(target)->setMaterialName(val);
00577     }
00578     //-----------------------------------------------------------------------
00579     String ParticleSystem::CmdQuota::doGet(const void* target) const
00580     {
00581         return StringConverter::toString(
00582             static_cast<const ParticleSystem*>(target)->getParticleQuota() );
00583     }
00584     void ParticleSystem::CmdQuota::doSet(void* target, const String& val)
00585     {
00586         static_cast<ParticleSystem*>(target)->setParticleQuota(
00587             StringConverter::parseUnsignedInt(val));
00588     }
00589     //-----------------------------------------------------------------------
00590     String ParticleSystem::CmdBillboardType::doGet(const void* target) const
00591     {
00592         BillboardType t = static_cast<const ParticleSystem*>(target)->getBillboardType();
00593         switch(t)
00594         {
00595         case BBT_POINT:
00596             return "point";
00597             break;
00598         case BBT_ORIENTED_COMMON:
00599             return "oriented_common";
00600             break;
00601         case BBT_ORIENTED_SELF:
00602             return "oriented_self";
00603             break;
00604         }
00605         // Compiler nicety
00606         return "";
00607     }
00608     void ParticleSystem::CmdBillboardType::doSet(void* target, const String& val)
00609     {
00610         BillboardType t;
00611         if (val == "point")
00612         {
00613             t = BBT_POINT;
00614         }
00615         else if (val == "oriented_common")
00616         {
00617             t = BBT_ORIENTED_COMMON;
00618         }
00619         else if (val == "oriented_self")
00620         {
00621             t = BBT_ORIENTED_SELF;
00622         }
00623         else
00624         {
00625             Except(Exception::ERR_INVALIDPARAMS, 
00626                 "Invalid billboard_type '" + val + "'", 
00627                 "ParticleSystem::CmdBillboardType::doSet");
00628         }
00629 
00630         static_cast<ParticleSystem*>(target)->setBillboardType(t);
00631     }
00632     //-----------------------------------------------------------------------
00633     String ParticleSystem::CmdCommonDirection::doGet(const void* target) const
00634     {
00635         return StringConverter::toString(
00636             static_cast<const ParticleSystem*>(target)->getCommonDirection() );
00637     }
00638     void ParticleSystem::CmdCommonDirection::doSet(void* target, const String& val)
00639     {
00640         static_cast<ParticleSystem*>(target)->setCommonDirection(
00641             StringConverter::parseVector3(val));
00642     }
00643 
00644 }

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:38 2004