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 
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     const String& ParticleSystem::getName(void) const
00092     {
00093         return mName;
00094     }
00095     //-----------------------------------------------------------------------
00096     ParticleEmitter* ParticleSystem::addEmitter(const String& emitterType)
00097     {
00098         ParticleEmitter* em = ParticleSystemManager::getSingleton()._createEmitter(emitterType);
00099         mEmitters.push_back(em);
00100         return em;
00101     }
00102     //-----------------------------------------------------------------------
00103     ParticleEmitter* ParticleSystem::getEmitter(unsigned short index) const
00104     {
00105         assert(index < mEmitters.size() && "Emitter index out of bounds!");
00106         return mEmitters[index];
00107     }
00108     //-----------------------------------------------------------------------
00109     unsigned short ParticleSystem::getNumEmitters(void) const
00110     {
00111         return static_cast< unsigned short >( mEmitters.size() );
00112     }
00113     //-----------------------------------------------------------------------
00114     void ParticleSystem::removeEmitter(unsigned short index)
00115     {
00116         assert(index < mEmitters.size() && "Emitter index out of bounds!");
00117         ParticleEmitterList::iterator ei = mEmitters.begin() + index;
00118         ParticleSystemManager::getSingleton()._destroyEmitter(*ei);
00119         mEmitters.erase(ei);
00120     }
00121     //-----------------------------------------------------------------------
00122     void ParticleSystem::removeAllEmitters(void)
00123     {
00124         // DON'T delete directly, we don't know what heap these have been created on
00125         ParticleEmitterList::iterator ei;
00126         for (ei = mEmitters.begin(); ei != mEmitters.end(); ++ei)
00127         {
00128             ParticleSystemManager::getSingleton()._destroyEmitter(*ei);
00129         }
00130         mEmitters.clear();
00131     }
00132     //-----------------------------------------------------------------------
00133     ParticleAffector* ParticleSystem::addAffector(const String& affectorType)
00134     {
00135         ParticleAffector* af = ParticleSystemManager::getSingleton()._createAffector(affectorType);
00136         mAffectors.push_back(af);
00137         return af;
00138     }
00139     //-----------------------------------------------------------------------
00140     ParticleAffector* ParticleSystem::getAffector(unsigned short index) const
00141     {
00142         assert(index < mAffectors.size() && "Affector index out of bounds!");
00143         return mAffectors[index];
00144     }
00145     //-----------------------------------------------------------------------
00146     unsigned short ParticleSystem::getNumAffectors(void) const
00147     {
00148         return static_cast< unsigned short >( mAffectors.size() );
00149     }
00150     //-----------------------------------------------------------------------
00151     void ParticleSystem::removeAffector(unsigned short index)
00152     {
00153         assert(index < mAffectors.size() && "Affector index out of bounds!");
00154         ParticleAffectorList::iterator ai = mAffectors.begin() + index;
00155         ParticleSystemManager::getSingleton()._destroyAffector(*ai);
00156         mAffectors.erase(ai);
00157     }
00158     //-----------------------------------------------------------------------
00159     void ParticleSystem::removeAllAffectors(void)
00160     {
00161         // DON'T delete directly, we don't know what heap these have been created on
00162         ParticleAffectorList::iterator ai;
00163         for (ai = mAffectors.begin(); ai != mAffectors.end(); ++ai)
00164         {
00165             ParticleSystemManager::getSingleton()._destroyAffector(*ai);
00166         }
00167         mAffectors.clear();
00168     }
00169     //-----------------------------------------------------------------------
00170     ParticleSystem& ParticleSystem::operator=(const ParticleSystem& rhs)
00171     {
00172         // Blank this system's emitters & affectors
00173         removeAllEmitters();
00174         removeAllAffectors();
00175 
00176         // Copy emitters
00177         unsigned int i;
00178         for(i = 0; i < rhs.getNumEmitters(); ++i)
00179         {
00180             ParticleEmitter* rhsEm = rhs.getEmitter(i);
00181             ParticleEmitter* newEm = addEmitter(rhsEm->getType());
00182             rhsEm->copyParametersTo(newEm);
00183         }
00184         // Copy affectors
00185         for(i = 0; i < rhs.getNumAffectors(); ++i)
00186         {
00187             ParticleAffector* rhsAf = rhs.getAffector(i);
00188             ParticleAffector* newAf = addAffector(rhsAf->getType());
00189             rhsAf->copyParametersTo(newAf);
00190         }
00191         setPoolSize(rhs.getPoolSize());
00192         setMaterialName(rhs.mMaterialName);
00193         mOriginType = rhs.mOriginType;
00194         mDefaultHeight = rhs.mDefaultHeight;
00195         mDefaultWidth = rhs.mDefaultWidth;
00196         mCullIndividual = rhs.mCullIndividual;
00197         mBillboardType = rhs.mBillboardType;
00198         mCommonDirection = rhs.mCommonDirection;
00199 
00200 
00201         return *this;
00202 
00203     }
00204     //-----------------------------------------------------------------------
00205     unsigned int ParticleSystem::getNumParticles(void) const
00206     {
00207         return (unsigned int)mActiveBillboards.size();
00208     }
00209     //-----------------------------------------------------------------------
00210     unsigned int ParticleSystem::getParticleQuota(void) const
00211     {
00212         // This is basically a renamed property
00213         return getPoolSize();
00214     }
00215     //-----------------------------------------------------------------------
00216     void ParticleSystem::setParticleQuota(unsigned int quota)
00217     {
00218         // This is basically a renamed property
00219         setPoolSize(quota);
00220     }
00221     //-----------------------------------------------------------------------
00222     void ParticleSystem::_update(Real timeElapsed)
00223     {
00224         // Only update if attached to a node
00225         if (mParentNode)
00226         {
00227             // Update existing particles
00228             _expire(timeElapsed);
00229             _triggerAffectors(timeElapsed);
00230             _applyMotion(timeElapsed);
00231             // Emit new particles
00232             _triggerEmitters(timeElapsed);
00233             // Update bounds
00234             _updateBounds();
00235         }
00236         
00237 
00238     }
00239     //-----------------------------------------------------------------------
00240     void ParticleSystem::_expire(Real timeElapsed)
00241     {
00242         ActiveBillboardList::iterator i, itEnd;
00243         Particle* pParticle;
00244 
00245         itEnd = mActiveBillboards.end();
00246 
00247         for (i = mActiveBillboards.begin(); i != itEnd; ++i)
00248         {
00249             pParticle = static_cast<Particle*>(*i);
00250             if (pParticle->mTimeToLive < timeElapsed)
00251             {
00252                 // Destroy this one
00253                 mFreeBillboards.push_back( *i );
00254                 i = mActiveBillboards.erase( i );
00255             }
00256             else
00257             {
00258                 // Decrement TTL
00259                 pParticle->mTimeToLive -= timeElapsed;
00260             }
00261 
00262         }
00263     }
00264     //-----------------------------------------------------------------------
00265     void ParticleSystem::_triggerEmitters(Real timeElapsed)
00266     {
00267         // Add up requests for emission
00268         static std::vector<unsigned> requested;
00269         if( requested.size() != mEmitters.size() )
00270             requested.resize( mEmitters.size() );
00271 
00272         size_t totalRequested, emitterCount, i, emissionAllowed;
00273         ParticleEmitterList::iterator   itEmit, iEmitEnd;
00274         ParticleAffectorList::iterator  itAff, itAffEnd;
00275                 
00276         iEmitEnd = mEmitters.end();
00277         emitterCount = mEmitters.size();
00278         emissionAllowed = getParticleQuota() - mActiveBillboards.size();
00279         totalRequested = 0;
00280 
00281         // Count up total requested emissions
00282         for (itEmit = mEmitters.begin(), i = 0; itEmit != iEmitEnd; ++itEmit, ++i)
00283         {
00284             requested[i] = (*itEmit)->_getEmissionCount(timeElapsed);
00285             totalRequested += requested[i];
00286         }
00287 
00288 
00289         // Check if the quota will be exceeded, if so reduce demand
00290         if (totalRequested > emissionAllowed)
00291         {
00292             // Apportion down requested values to allotted values
00293             Real ratio =  (Real)emissionAllowed / (Real)totalRequested;
00294             for (i = 0; i < emitterCount; ++i)
00295             {
00296                 requested[i] *= (unsigned int)ratio;
00297             }
00298         }
00299 
00300         // Emit
00301         // For each emission, apply a subset of the motion for the frame
00302         // this ensures an even distribution of particles when many are
00303         // emitted in a single frame
00304         for (itEmit = mEmitters.begin(), i = 0; itEmit != iEmitEnd; ++itEmit, ++i)
00305         {
00306             Real timePoint = 0.0f;
00307             Real timeInc = timeElapsed / requested[i];
00308             for (unsigned int j = 0; j < requested[i]; ++j)
00309             {
00310                 // Create a new particle & init using emitter
00311                 Particle* p = addParticle();
00312                 (*itEmit)->_initParticle(p);
00313 
00314                 // Translate position & direction into world space
00315                 // Maybe make emitter do this?
00316                 p->mPosition  = (mParentNode->_getDerivedOrientation() * p->mPosition) + mParentNode->_getDerivedPosition();
00317                 p->mDirection = (mParentNode->_getDerivedOrientation() * p->mDirection);
00318 
00319                 // apply partial frame motion to this particle
00320                 p->mPosition += (p->mDirection * timePoint);
00321 
00322                 // apply particle initialization by the affectors
00323                 itAffEnd = mAffectors.end();
00324                 for (itAff = mAffectors.begin(); itAff != itAffEnd; ++itAff)
00325                     (*itAff)->_initParticle(p);
00326 
00327                 // Increment time fragment
00328                 timePoint += timeInc;
00329             }
00330         }
00331 
00332 
00333     }
00334     //-----------------------------------------------------------------------
00335     void ParticleSystem::_applyMotion(Real timeElapsed)
00336     {
00337         ActiveBillboardList::iterator i, itEnd;
00338         Particle* pParticle;
00339 
00340         itEnd = mActiveBillboards.end();
00341         for (i = mActiveBillboards.begin(); i != itEnd; ++i)
00342         {
00343             pParticle = static_cast<Particle*>(*i);
00344             pParticle->mPosition += (pParticle->mDirection * timeElapsed);
00345         }
00346 
00347     }
00348     //-----------------------------------------------------------------------
00349     void ParticleSystem::_triggerAffectors(Real timeElapsed)
00350     {
00351         ParticleAffectorList::iterator i, itEnd;
00352         
00353         itEnd = mAffectors.end();
00354         for (i = mAffectors.begin(); i != itEnd; ++i)
00355         {
00356             (*i)->_affectParticles(this, timeElapsed);
00357         }
00358 
00359     }
00360     //-----------------------------------------------------------------------
00361     void ParticleSystem::increasePool(unsigned int size)
00362     {
00363         size_t oldSize = mBillboardPool.size();
00364 
00365         // Increase size
00366         mBillboardPool.reserve(size);
00367         mBillboardPool.resize(size);
00368 
00369         // Create new particles
00370         for( size_t i = oldSize; i < size; i++ )
00371             mBillboardPool[i] = new Particle();
00372 
00373     }
00374     //-----------------------------------------------------------------------
00375     ParticleIterator ParticleSystem::_getIterator(void)
00376     {
00377         return ParticleIterator(mActiveBillboards.begin(), mActiveBillboards.end());
00378     }
00379     //-----------------------------------------------------------------------
00380     Particle* ParticleSystem::addParticle(void)
00381     {
00382         // Fast creation (don't use superclass since emitter will init)
00383         Billboard* newBill = mFreeBillboards.front();
00384         mFreeBillboards.pop_front();
00385         mActiveBillboards.push_back(newBill);
00386 
00387         newBill->_notifyOwner(this);
00388 
00389         // Because we're creating objects here we know this is a Particle
00390         return static_cast<Particle*>(newBill);
00391 
00392     }
00393     //-----------------------------------------------------------------------
00394     void ParticleSystem::genBillboardAxes(Camera& cam, Vector3* pX, Vector3 *pY, const Billboard* pBill)    
00395     {
00396         // Orientation different from BillboardSet
00397         // Billboards are in world space (to decouple them from emitters in node space)
00398         Quaternion camQ;
00399 
00400         switch (mBillboardType)
00401         {
00402         case BBT_POINT:
00403             // Get camera world axes for X and Y (depth is irrelevant)
00404             // No inverse transform
00405             camQ = cam.getDerivedOrientation();
00406             *pX = camQ * Vector3::UNIT_X;
00407             *pY = camQ * Vector3::UNIT_Y;
00408            
00409             break;
00410         case BBT_ORIENTED_COMMON:
00411              // Y-axis is common direction
00412             // X-axis is cross with camera direction 
00413             *pY = mCommonDirection;
00414             *pX = cam.getDerivedDirection().crossProduct(*pY);
00415            
00416             break;
00417         case BBT_ORIENTED_SELF:
00418             // Y-axis is direction
00419             // X-axis is cross with camera direction 
00420 
00421             // Scale direction first
00422             *pY = (pBill->mDirection * 0.01);
00423             *pX = cam.getDerivedDirection().crossProduct(*pY);
00424 
00425             break;
00426         }
00427 
00428     }
00429     //-----------------------------------------------------------------------
00430     void ParticleSystem::getWorldTransforms(Matrix4* xform) const
00431     {
00432         // Particles are already in world space
00433         *xform = Matrix4::IDENTITY;
00434 
00435     }
00436     //-----------------------------------------------------------------------
00437     const Quaternion& ParticleSystem::getWorldOrientation(void) const
00438     {
00439         return mParentNode->_getDerivedOrientation();
00440     }
00441     //-----------------------------------------------------------------------
00442     const Vector3& ParticleSystem::getWorldPosition(void) const
00443     {
00444         return mParentNode->_getDerivedPosition();
00445     }
00446     //-----------------------------------------------------------------------
00447     void ParticleSystem::initParameters(void)
00448     {
00449         if (createParamDictionary("ParticleSystem"))
00450         {
00451             ParamDictionary* dict = getParamDictionary();
00452 
00453             dict->addParameter(ParameterDef("quota", 
00454                 "The maximum number of particle allowed at once in this system.",
00455                 PT_UNSIGNED_INT),
00456                 &msQuotaCmd);
00457 
00458             dict->addParameter(ParameterDef("material", 
00459                 "The name of the material to be used to render all particles in this system.",
00460                 PT_STRING),
00461                 &msMaterialCmd);
00462 
00463             dict->addParameter(ParameterDef("particle_width", 
00464                 "The width of particles in world units.",
00465                 PT_REAL),
00466                 &msWidthCmd);
00467 
00468             dict->addParameter(ParameterDef("particle_height", 
00469                 "The height of particles in world units.",
00470                 PT_REAL),
00471                 &msHeightCmd);
00472 
00473             dict->addParameter(ParameterDef("cull_each", 
00474                 "If true, each particle is culled in it's own right. If false, the entire system is culled as a whole.",
00475                 PT_BOOL),
00476                 &msCullCmd);
00477 
00478             dict->addParameter(ParameterDef("billboard_type", 
00479                 "The type of billboard to use. 'point' means a simulated spherical particle, " 
00480                 "'oriented_common' means all particles in the set are oriented around common_direction, "
00481                 "and 'oriented_self' means particles are oriented around their own direction.",
00482                 PT_UNSIGNED_INT),
00483                 &msBillboardTypeCmd);
00484 
00485             dict->addParameter(ParameterDef("common_direction", 
00486                 "Only useful when billboard_type is oriented_common. This parameter sets the common "
00487                 "orientation for all particles in the set (e.g. raindrops may all be oriented downwards).",
00488                 PT_VECTOR3),
00489                 &msCommonDirectionCmd);
00490 
00491         }
00492     }
00493     //-----------------------------------------------------------------------
00494     void ParticleSystem::_updateBounds()
00495     {
00496         // Call superclass
00497         BillboardSet::_updateBounds();
00498 
00499         if (mParentNode && !mAABB.isNull())
00500         {
00501             // Have to override because bounds are supposed to be in local node space
00502             // but we've already put particles in world space to decouple them from the
00503             // node transform, so reverse transform back
00504 
00505             Vector3 min( Math::POS_INFINITY, Math::POS_INFINITY, Math::POS_INFINITY );
00506             Vector3 max( Math::NEG_INFINITY, Math::NEG_INFINITY, Math::NEG_INFINITY );
00507             Vector3 temp;
00508             const Vector3 *corner = mAABB.getAllCorners();
00509             Quaternion invQ = mParentNode->_getDerivedOrientation().Inverse();
00510             Vector3 t = mParentNode->_getDerivedPosition();
00511 
00512             for (int i = 0; i < 8; ++i)
00513             {
00514                 // Reverse transform corner
00515                 temp = invQ * (corner[i] - t);
00516                 min.makeFloor(temp);
00517                 max.makeCeil(temp);
00518             }
00519             mAABB.setExtents(min, max);
00520         }
00521     }
00522     //-----------------------------------------------------------------------
00523 
00524     void ParticleSystem::fastForward(Real time, Real interval)
00525     {
00526         // First make sure all transforms are up to date
00527 
00528         for (Real ftime = 0; ftime < time; ftime += interval)
00529         {
00530             _update(interval);
00531         }
00532     }
00533     //-----------------------------------------------------------------------
00534     const String& ParticleSystem::getMovableType(void) const
00535     {
00536         static String mType = "ParticleSystem";
00537         return mType;
00538     }
00539 
00540     //-----------------------------------------------------------------------
00541     String ParticleSystem::CmdCull::doGet(const void* target) const
00542     {
00543         return StringConverter::toString(
00544             static_cast<const ParticleSystem*>(target)->getCullIndividually() );
00545     }
00546     void ParticleSystem::CmdCull::doSet(void* target, const String& val)
00547     {
00548         static_cast<ParticleSystem*>(target)->setCullIndividually(
00549             StringConverter::parseBool(val));
00550     }
00551     //-----------------------------------------------------------------------
00552     String ParticleSystem::CmdHeight::doGet(const void* target) const
00553     {
00554         return StringConverter::toString(
00555             static_cast<const ParticleSystem*>(target)->getDefaultHeight() );
00556     }
00557     void ParticleSystem::CmdHeight::doSet(void* target, const String& val)
00558     {
00559         static_cast<ParticleSystem*>(target)->setDefaultHeight(
00560             StringConverter::parseReal(val));
00561     }
00562     //-----------------------------------------------------------------------
00563     String ParticleSystem::CmdWidth::doGet(const void* target) const
00564     {
00565         return StringConverter::toString(
00566             static_cast<const ParticleSystem*>(target)->getDefaultWidth() );
00567     }
00568     void ParticleSystem::CmdWidth::doSet(void* target, const String& val)
00569     {
00570         static_cast<ParticleSystem*>(target)->setDefaultWidth(
00571             StringConverter::parseReal(val));
00572     }
00573     //-----------------------------------------------------------------------
00574     String ParticleSystem::CmdMaterial::doGet(const void* target) const
00575     {
00576         return static_cast<const ParticleSystem*>(target)->getMaterialName();
00577     }
00578     void ParticleSystem::CmdMaterial::doSet(void* target, const String& val)
00579     {
00580         static_cast<ParticleSystem*>(target)->setMaterialName(val);
00581     }
00582     //-----------------------------------------------------------------------
00583     String ParticleSystem::CmdQuota::doGet(const void* target) const
00584     {
00585         return StringConverter::toString(
00586             static_cast<const ParticleSystem*>(target)->getParticleQuota() );
00587     }
00588     void ParticleSystem::CmdQuota::doSet(void* target, const String& val)
00589     {
00590         static_cast<ParticleSystem*>(target)->setParticleQuota(
00591             StringConverter::parseUnsignedInt(val));
00592     }
00593     //-----------------------------------------------------------------------
00594     String ParticleSystem::CmdBillboardType::doGet(const void* target) const
00595     {
00596         BillboardType t = static_cast<const ParticleSystem*>(target)->getBillboardType();
00597         switch(t)
00598         {
00599         case BBT_POINT:
00600             return "point";
00601             break;
00602         case BBT_ORIENTED_COMMON:
00603             return "oriented_common";
00604             break;
00605         case BBT_ORIENTED_SELF:
00606             return "oriented_self";
00607             break;
00608         }
00609         // Compiler nicety
00610         return "";
00611     }
00612     void ParticleSystem::CmdBillboardType::doSet(void* target, const String& val)
00613     {
00614         BillboardType t;
00615         if (val == "point")
00616         {
00617             t = BBT_POINT;
00618         }
00619         else if (val == "oriented_common")
00620         {
00621             t = BBT_ORIENTED_COMMON;
00622         }
00623         else if (val == "oriented_self")
00624         {
00625             t = BBT_ORIENTED_SELF;
00626         }
00627         static_cast<ParticleSystem*>(target)->setBillboardType(t);
00628     }
00629     //-----------------------------------------------------------------------
00630     String ParticleSystem::CmdCommonDirection::doGet(const void* target) const
00631     {
00632         return StringConverter::toString(
00633             static_cast<const ParticleSystem*>(target)->getCommonDirection() );
00634     }
00635     void ParticleSystem::CmdCommonDirection::doSet(void* target, const String& val)
00636     {
00637         static_cast<ParticleSystem*>(target)->setCommonDirection(
00638             StringConverter::parseVector3(val));
00639     }
00640 
00641 }

Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:21 2004