Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreParticleSystem.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

File size: 55.5 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30
31#include "OgreParticleSystem.h"
32#include "OgreParticleSystemManager.h"
33#include "OgreRenderQueue.h"
34#include "OgreBillboardSet.h"
35#include "OgreParticleEmitter.h"
36#include "OgreParticleAffector.h"
37#include "OgreParticle.h"
38#include "OgreSceneNode.h"
39#include "OgreCamera.h"
40#include "OgreStringConverter.h"
41#include "OgreLogManager.h"
42#include "OgreException.h"
43#include "OgreParticleAffectorFactory.h"
44#include "OgreParticleSystemRenderer.h"
45#include "OgreMaterialManager.h"
46#include "OgreSceneManager.h"
47#include "OgreControllerManager.h"
48#include "OgreRoot.h"
49
50namespace Ogre {
51    // Init statics
52    ParticleSystem::CmdCull ParticleSystem::msCullCmd;
53    ParticleSystem::CmdHeight ParticleSystem::msHeightCmd;
54    ParticleSystem::CmdMaterial ParticleSystem::msMaterialCmd;
55    ParticleSystem::CmdQuota ParticleSystem::msQuotaCmd;
56        ParticleSystem::CmdEmittedEmitterQuota ParticleSystem::msEmittedEmitterQuotaCmd;
57    ParticleSystem::CmdWidth ParticleSystem::msWidthCmd;
58    ParticleSystem::CmdRenderer ParticleSystem::msRendererCmd;
59        ParticleSystem::CmdSorted ParticleSystem::msSortedCmd;
60        ParticleSystem::CmdLocalSpace ParticleSystem::msLocalSpaceCmd;
61        ParticleSystem::CmdIterationInterval ParticleSystem::msIterationIntervalCmd;
62        ParticleSystem::CmdNonvisibleTimeout ParticleSystem::msNonvisibleTimeoutCmd;
63
64    RadixSort<ParticleSystem::ActiveParticleList, Particle*, float> ParticleSystem::mRadixSorter;
65
66    Real ParticleSystem::msDefaultIterationInterval = 0;
67    Real ParticleSystem::msDefaultNonvisibleTimeout = 0;
68
69        //-----------------------------------------------------------------------
70        // Local class for updating based on time
71        class ParticleSystemUpdateValue : public ControllerValue<Real>
72        {
73        protected:
74                ParticleSystem* mTarget;
75        public:
76                ParticleSystemUpdateValue(ParticleSystem* target) : mTarget(target) {}
77
78                Real getValue(void) const { return 0; } // N/A
79
80                void setValue(Real value) { mTarget->_update(value); }
81
82        };
83    //-----------------------------------------------------------------------
84    ParticleSystem::ParticleSystem() 
85      : mAABB(),
86        mBoundingRadius(1.0f),
87        mBoundsAutoUpdate(true),
88        mBoundsUpdateTime(10.0f),
89        mUpdateRemainTime(0),
90        mWorldAABB(),
91        mResourceGroupName(ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME),
92        mIsRendererConfigured(false),
93        mSpeedFactor(1.0f),
94        mIterationInterval(0),
95                mIterationIntervalSet(false),
96        mSorted(false),
97        mLocalSpace(false),
98                mNonvisibleTimeout(0),
99                mNonvisibleTimeoutSet(false),
100                mTimeSinceLastVisible(0),
101                mLastVisibleFrame(0),
102        mTimeController(0),
103                mEmittedEmitterPoolInitialised(false),
104        mRenderer(0),
105        mCullIndividual(false),
106        mPoolSize(0),
107                mEmittedEmitterPoolSize(0)
108        {
109        initParameters();
110
111        // Default to billboard renderer
112        setRenderer("billboard");
113
114    }
115    //-----------------------------------------------------------------------
116    ParticleSystem::ParticleSystem(const String& name, const String& resourceGroup)
117      : MovableObject(name),
118        mAABB(),
119        mBoundingRadius(1.0f),
120        mBoundsAutoUpdate(true),
121        mBoundsUpdateTime(10.0f),
122        mUpdateRemainTime(0),
123        mWorldAABB(),
124        mResourceGroupName(resourceGroup),
125        mIsRendererConfigured(false),
126        mSpeedFactor(1.0f),
127        mIterationInterval(0),
128                mIterationIntervalSet(false),
129        mSorted(false),
130        mLocalSpace(false),
131                mNonvisibleTimeout(0),
132                mNonvisibleTimeoutSet(false),
133                mTimeSinceLastVisible(0),
134                mLastVisibleFrame(Root::getSingleton().getCurrentFrameNumber()),
135        mTimeController(0),
136                mEmittedEmitterPoolInitialised(false),
137        mRenderer(0), 
138                mCullIndividual(false),
139        mPoolSize(0),
140                mEmittedEmitterPoolSize(0)
141    {
142        setDefaultDimensions( 100, 100 );
143        setMaterialName( "BaseWhite" );
144        // Default to 10 particles, expect app to specify (will only be increased, not decreased)
145        setParticleQuota( 10 );
146                setEmittedEmitterQuota( 3 );
147        initParameters();
148
149        // Default to billboard renderer
150        setRenderer("billboard");
151    }
152    //-----------------------------------------------------------------------
153    ParticleSystem::~ParticleSystem()
154    {
155        if (mTimeController)
156        {
157            // Destroy controller
158            ControllerManager::getSingleton().destroyController(mTimeController);
159            mTimeController = 0;
160        }
161
162                // Arrange for the deletion of emitters & affectors
163        removeAllEmitters();
164                removeAllEmittedEmitters();
165        removeAllAffectors();
166
167                // Deallocate all particles
168                destroyVisualParticles(0, mParticlePool.size());
169        // Free pool items
170        ParticlePool::iterator i;
171        for (i = mParticlePool.begin(); i != mParticlePool.end(); ++i)
172        {
173            delete *i;
174        }
175
176        if (mRenderer)
177        {
178            ParticleSystemManager::getSingleton()._destroyRenderer(mRenderer);
179            mRenderer = 0;
180        }
181
182    }
183    //-----------------------------------------------------------------------
184    ParticleEmitter* ParticleSystem::addEmitter(const String& emitterType)
185    {
186        ParticleEmitter* em = 
187            ParticleSystemManager::getSingleton()._createEmitter(emitterType, this);
188        mEmitters.push_back(em);
189        return em;
190    }
191    //-----------------------------------------------------------------------
192    ParticleEmitter* ParticleSystem::getEmitter(unsigned short index) const
193    {
194        assert(index < mEmitters.size() && "Emitter index out of bounds!");
195        return mEmitters[index];
196    }
197    //-----------------------------------------------------------------------
198    unsigned short ParticleSystem::getNumEmitters(void) const
199    {
200        return static_cast< unsigned short >( mEmitters.size() );
201    }
202    //-----------------------------------------------------------------------
203    void ParticleSystem::removeEmitter(unsigned short index)
204    {
205        assert(index < mEmitters.size() && "Emitter index out of bounds!");
206        ParticleEmitterList::iterator ei = mEmitters.begin() + index;
207        ParticleSystemManager::getSingleton()._destroyEmitter(*ei);
208        mEmitters.erase(ei);
209    }
210    //-----------------------------------------------------------------------
211    void ParticleSystem::removeAllEmitters(void)
212    {
213        // DON'T delete directly, we don't know what heap these have been created on
214        ParticleEmitterList::iterator ei;
215        for (ei = mEmitters.begin(); ei != mEmitters.end(); ++ei)
216        {
217            ParticleSystemManager::getSingleton()._destroyEmitter(*ei);
218        }
219        mEmitters.clear();
220    }
221    //-----------------------------------------------------------------------
222    ParticleAffector* ParticleSystem::addAffector(const String& affectorType)
223    {
224        ParticleAffector* af = 
225            ParticleSystemManager::getSingleton()._createAffector(affectorType, this);
226        mAffectors.push_back(af);
227        return af;
228    }
229    //-----------------------------------------------------------------------
230    ParticleAffector* ParticleSystem::getAffector(unsigned short index) const
231    {
232        assert(index < mAffectors.size() && "Affector index out of bounds!");
233        return mAffectors[index];
234    }
235    //-----------------------------------------------------------------------
236    unsigned short ParticleSystem::getNumAffectors(void) const
237    {
238        return static_cast< unsigned short >( mAffectors.size() );
239    }
240    //-----------------------------------------------------------------------
241    void ParticleSystem::removeAffector(unsigned short index)
242    {
243        assert(index < mAffectors.size() && "Affector index out of bounds!");
244        ParticleAffectorList::iterator ai = mAffectors.begin() + index;
245        ParticleSystemManager::getSingleton()._destroyAffector(*ai);
246        mAffectors.erase(ai);
247    }
248    //-----------------------------------------------------------------------
249    void ParticleSystem::removeAllAffectors(void)
250    {
251        // DON'T delete directly, we don't know what heap these have been created on
252        ParticleAffectorList::iterator ai;
253        for (ai = mAffectors.begin(); ai != mAffectors.end(); ++ai)
254        {
255            ParticleSystemManager::getSingleton()._destroyAffector(*ai);
256        }
257        mAffectors.clear();
258    }
259    //-----------------------------------------------------------------------
260    ParticleSystem& ParticleSystem::operator=(const ParticleSystem& rhs)
261    {
262        // Blank this system's emitters & affectors
263        removeAllEmitters();
264                removeAllEmittedEmitters();
265        removeAllAffectors();
266
267        // Copy emitters
268        unsigned int i;
269        for(i = 0; i < rhs.getNumEmitters(); ++i)
270        {
271            ParticleEmitter* rhsEm = rhs.getEmitter(i);
272            ParticleEmitter* newEm = addEmitter(rhsEm->getType());
273            rhsEm->copyParametersTo(newEm);
274        }
275        // Copy affectors
276        for(i = 0; i < rhs.getNumAffectors(); ++i)
277        {
278            ParticleAffector* rhsAf = rhs.getAffector(i);
279            ParticleAffector* newAf = addAffector(rhsAf->getType());
280            rhsAf->copyParametersTo(newAf);
281        }
282        setParticleQuota(rhs.getParticleQuota());
283                setEmittedEmitterQuota(rhs.getEmittedEmitterQuota());
284        setMaterialName(rhs.mMaterialName);
285        setDefaultDimensions(rhs.mDefaultWidth, rhs.mDefaultHeight);
286        mCullIndividual = rhs.mCullIndividual;
287                mSorted = rhs.mSorted;
288                mLocalSpace = rhs.mLocalSpace;
289                mIterationInterval = rhs.mIterationInterval;
290                mIterationIntervalSet = rhs.mIterationIntervalSet;
291                mNonvisibleTimeout = rhs.mNonvisibleTimeout;
292                mNonvisibleTimeoutSet = rhs.mNonvisibleTimeoutSet;
293                // last frame visible and time since last visible should be left default
294
295        setRenderer(rhs.getRendererName());
296        // Copy settings
297        if (mRenderer && rhs.getRenderer())
298        {
299            rhs.getRenderer()->copyParametersTo(mRenderer);
300        }
301
302        return *this;
303
304    }
305    //-----------------------------------------------------------------------
306    size_t ParticleSystem::getNumParticles(void) const
307    {
308        return mActiveParticles.size();
309    }
310    //-----------------------------------------------------------------------
311    size_t ParticleSystem::getParticleQuota(void) const
312    {
313        return mPoolSize;
314    }
315    //-----------------------------------------------------------------------
316    void ParticleSystem::setParticleQuota(size_t size)
317    {
318        // Never shrink below size()
319        size_t currSize = mParticlePool.size();
320
321        if( currSize < size )
322        {
323            // Will allocate particles on demand
324            mPoolSize = size;
325           
326        }
327    }
328        //-----------------------------------------------------------------------
329        size_t ParticleSystem::getEmittedEmitterQuota(void) const
330        {
331                return mEmittedEmitterPoolSize;
332        }
333        //-----------------------------------------------------------------------
334        void ParticleSystem::setEmittedEmitterQuota(size_t size)
335        {
336                // Never shrink below size()
337                EmittedEmitterPool::iterator i;
338                size_t currSize = 0;
339                for (i = mEmittedEmitterPool.begin(); i != mEmittedEmitterPool.end(); ++i)
340                {
341                        currSize += i->second.size();
342                }
343
344                if( currSize < size )
345                {
346                        // Will allocate emitted emitters on demand
347                        mEmittedEmitterPoolSize = size;
348                }
349        }
350    //-----------------------------------------------------------------------
351        void ParticleSystem::setNonVisibleUpdateTimeout(Real timeout)
352        {
353                mNonvisibleTimeout = timeout;
354                mNonvisibleTimeoutSet = true;
355        }
356    //-----------------------------------------------------------------------
357        void ParticleSystem::setIterationInterval(Real interval)
358        {
359                mIterationInterval = interval;
360                mIterationIntervalSet = true;
361        }
362    //-----------------------------------------------------------------------
363    void ParticleSystem::_update(Real timeElapsed)
364    {
365        // Only update if attached to a node
366        if (!mParentNode)
367            return;
368
369                Real nonvisibleTimeout = mNonvisibleTimeoutSet ?
370                        mNonvisibleTimeout : msDefaultNonvisibleTimeout;
371
372                if (nonvisibleTimeout > 0)
373                {
374                        // Check whether it's been more than one frame (update is ahead of
375                        // camera notification by one frame because of the ordering)
376                        long frameDiff = Root::getSingleton().getCurrentFrameNumber() - mLastVisibleFrame;
377                        if (frameDiff > 1 || frameDiff < 0) // < 0 if wrap only
378                        {
379                                mTimeSinceLastVisible += timeElapsed;
380                                if (mTimeSinceLastVisible >= nonvisibleTimeout)
381                                {
382                                        // No update
383                                        return;
384                                }
385                        }
386                }
387
388                // Scale incoming speed for the rest of the calculation
389                timeElapsed *= mSpeedFactor;
390
391        // Init renderer if not done already
392        configureRenderer();
393
394                // Initialise emitted emitters list if not done already
395                initialiseEmittedEmitters();
396
397                Real iterationInterval = mIterationIntervalSet ? 
398            mIterationInterval : msDefaultIterationInterval;
399        if (iterationInterval > 0)
400        {
401            mUpdateRemainTime += timeElapsed;
402
403            while (mUpdateRemainTime >= iterationInterval)
404            {
405                // Update existing particles
406                _expire(iterationInterval);
407                _triggerAffectors(iterationInterval);
408                _applyMotion(iterationInterval);
409                // Emit new particles
410                _triggerEmitters(iterationInterval);
411
412                mUpdateRemainTime -= iterationInterval;
413            }
414        }
415        else
416        {
417            // Update existing particles
418            _expire(timeElapsed);
419            _triggerAffectors(timeElapsed);
420            _applyMotion(timeElapsed);
421            // Emit new particles
422            _triggerEmitters(timeElapsed);
423        }
424
425        if (!mBoundsAutoUpdate && mBoundsUpdateTime > 0.0f)
426            mBoundsUpdateTime -= timeElapsed; // count down
427        _updateBounds();
428
429    }
430    //-----------------------------------------------------------------------
431    void ParticleSystem::_expire(Real timeElapsed)
432    {
433        ActiveParticleList::iterator i, itEnd;
434        Particle* pParticle;
435                ParticleEmitter* pParticleEmitter;
436
437        itEnd = mActiveParticles.end();
438
439        for (i = mActiveParticles.begin(); i != itEnd; )
440        {
441            pParticle = static_cast<Particle*>(*i);
442            if (pParticle->timeToLive < timeElapsed)
443            {
444                // Notify renderer
445                mRenderer->_notifyParticleExpired(pParticle);
446
447                                // Identify the particle type
448                                if (pParticle->particleType == Particle::Visual)
449                                {
450                        // Destroy this one
451                            mFreeParticles.splice(mFreeParticles.end(), mActiveParticles, i++);
452                                }
453                                else
454                                {
455                                        // For now, it can only be an emitted emitter
456                                        pParticleEmitter = static_cast<ParticleEmitter*>(*i);
457                                        std::list<ParticleEmitter*>* fee = findFreeEmittedEmitter(pParticleEmitter->getName());
458                                        fee->push_back(pParticleEmitter);
459
460                                        // Also erase from mActiveEmittedEmitters
461                                        removeFromActiveEmittedEmitters (pParticleEmitter);
462
463                                        // And erase from mActiveParticles
464                                        i = mActiveParticles.erase( i );
465                                }
466            }
467            else
468            {
469                // Decrement TTL
470                pParticle->timeToLive -= timeElapsed;
471                                ++i;
472            }
473
474        }
475    }
476    //-----------------------------------------------------------------------
477    void ParticleSystem::_triggerEmitters(Real timeElapsed)
478    {
479        // Add up requests for emission
480        static std::vector<unsigned> requested;
481        if( requested.size() != mEmitters.size() )
482            requested.resize( mEmitters.size() );
483
484        size_t totalRequested, emitterCount, i, emissionAllowed;
485        ParticleEmitterList::iterator itEmit, iEmitEnd;
486                ActiveEmittedEmitterList::iterator itActiveEmit;
487        iEmitEnd = mEmitters.end();
488        emitterCount = mEmitters.size();
489        emissionAllowed = mFreeParticles.size();
490        totalRequested = 0;
491
492        // Count up total requested emissions for regular emitters (and exclude the ones that are used as
493                // a template for emitted emitters)
494        for (itEmit = mEmitters.begin(), i = 0; itEmit != iEmitEnd; ++itEmit, ++i)
495        {
496                        if (!(*itEmit)->isEmitted())
497                        {
498                                requested[i] = (*itEmit)->_getEmissionCount(timeElapsed);
499                                totalRequested += requested[i];
500                        }
501        }
502
503                // Add up total requested emissions for (active) emitted emitters
504                for (itActiveEmit = mActiveEmittedEmitters.begin(); itActiveEmit != mActiveEmittedEmitters.end(); ++itActiveEmit)
505                {
506                        totalRequested += (*itActiveEmit)->_getEmissionCount(timeElapsed);
507                }
508
509        // Check if the quota will be exceeded, if so reduce demand
510                Real ratio =  1.0f;
511        if (totalRequested > emissionAllowed)
512        {
513            // Apportion down requested values to allotted values
514            ratio =  (Real)emissionAllowed / (Real)totalRequested;
515            for (i = 0; i < emitterCount; ++i)
516            {
517                requested[i] = static_cast<unsigned>(requested[i] * ratio);
518            }
519        }
520
521        // Emit
522                // For each emission, apply a subset of the motion for the frame
523                // this ensures an even distribution of particles when many are
524                // emitted in a single frame
525        for (itEmit = mEmitters.begin(), i = 0; itEmit != iEmitEnd; ++itEmit, ++i)
526        {
527                        // Trigger the emitters, but exclude the emitters that are already in the emitted emitters list;
528                        // they are handled in a separate loop
529                        if (!(*itEmit)->isEmitted())
530                                _executeTriggerEmitters (*itEmit, static_cast<unsigned>(requested[i]), timeElapsed);
531        }
532
533                // Do the same with all active emitted emitters
534                for (itActiveEmit = mActiveEmittedEmitters.begin(), i = 0; itActiveEmit != mActiveEmittedEmitters.end(); ++itActiveEmit, ++i)
535                        _executeTriggerEmitters (*itActiveEmit, static_cast<unsigned>((*itActiveEmit)->_getEmissionCount(timeElapsed) * ratio), timeElapsed);
536        }
537    //-----------------------------------------------------------------------
538    void ParticleSystem::_executeTriggerEmitters(ParticleEmitter* emitter, unsigned requested, Real timeElapsed)
539    {
540                ParticleAffectorList::iterator  itAff, itAffEnd;
541                Real timePoint = 0.0f;
542                Real timeInc = timeElapsed / requested;
543
544                for (unsigned int j = 0; j < requested; ++j)
545                {
546                        // Create a new particle & init using emitter
547                        // The particle is a visual particle if the emit_emitter property of the emitter isn't set
548                        Particle* p = 0;
549                        String  emitterName = emitter->getEmittedEmitter();
550                        if (emitterName == StringUtil::BLANK)
551                                p = createParticle();
552                        else
553                                p = createEmitterParticle(emitterName);
554
555                        // Only continue if the particle was really created (not null)
556                        if (!p)
557                                return;
558
559                        emitter->_initParticle(p);
560
561                        // Translate position & direction into world space
562                        if (!mLocalSpace)
563                        {
564                                p->position  = 
565                                        (mParentNode->_getDerivedOrientation() *
566                                        (mParentNode->_getDerivedScale() * p->position))
567                                        + mParentNode->_getDerivedPosition();
568                                p->direction = 
569                                        (mParentNode->_getDerivedOrientation() * p->direction);
570                        }
571
572                        // apply partial frame motion to this particle
573            p->position += (p->direction * timePoint);
574
575                        // apply particle initialization by the affectors
576                        itAffEnd = mAffectors.end();
577                        for (itAff = mAffectors.begin(); itAff != itAffEnd; ++itAff)
578                                (*itAff)->_initParticle(p);
579
580                        // Increment time fragment
581                        timePoint += timeInc;
582
583                        if (p->particleType == Particle::Emitter)
584                        {
585                                // If the particle is an emitter, the position on the emitter side must also be initialised
586                                // Note, that position of the emitter becomes a position in worldspace if mLocalSpace is set
587                                // to false (will this become a problem?)
588                                ParticleEmitter* pParticleEmitter = static_cast<ParticleEmitter*>(p);
589                                pParticleEmitter->setPosition(p->position);
590                        }
591
592            // Notify renderer
593            mRenderer->_notifyParticleEmitted(p);
594        }
595    }
596    //-----------------------------------------------------------------------
597    void ParticleSystem::_applyMotion(Real timeElapsed)
598    {
599        ActiveParticleList::iterator i, itEnd;
600        Particle* pParticle;
601                ParticleEmitter* pParticleEmitter;
602
603        itEnd = mActiveParticles.end();
604        for (i = mActiveParticles.begin(); i != itEnd; ++i)
605        {
606            pParticle = static_cast<Particle*>(*i);
607            pParticle->position += (pParticle->direction * timeElapsed);
608
609                        if (pParticle->particleType == Particle::Emitter)
610                        {
611                                // If it is an emitter, the emitter position must also be updated
612                                // Note, that position of the emitter becomes a position in worldspace if mLocalSpace is set
613                                // to false (will this become a problem?)
614                                pParticleEmitter = static_cast<ParticleEmitter*>(*i);
615                                pParticleEmitter->setPosition(pParticle->position);
616                        }
617        }
618
619        // Notify renderer
620        mRenderer->_notifyParticleMoved(mActiveParticles);
621    }
622    //-----------------------------------------------------------------------
623    void ParticleSystem::_triggerAffectors(Real timeElapsed)
624    {
625        ParticleAffectorList::iterator i, itEnd;
626       
627        itEnd = mAffectors.end();
628        for (i = mAffectors.begin(); i != itEnd; ++i)
629        {
630            (*i)->_affectParticles(this, timeElapsed);
631        }
632
633    }
634    //-----------------------------------------------------------------------
635    void ParticleSystem::increasePool(size_t size)
636    {
637        size_t oldSize = mParticlePool.size();
638
639        // Increase size
640        mParticlePool.reserve(size);
641        mParticlePool.resize(size);
642
643        // Create new particles
644        for( size_t i = oldSize; i < size; i++ )
645                {
646            mParticlePool[i] = new Particle();
647                }
648
649                if (mIsRendererConfigured)
650                {
651                        createVisualParticles(oldSize, size);
652                }
653
654
655    }
656    //-----------------------------------------------------------------------
657    ParticleIterator ParticleSystem::_getIterator(void)
658    {
659        return ParticleIterator(mActiveParticles.begin(), mActiveParticles.end());
660    }
661    //-----------------------------------------------------------------------
662        Particle* ParticleSystem::getParticle(size_t index) 
663        {
664                assert (index < mActiveParticles.size() && "Index out of bounds!");
665                ActiveParticleList::iterator i = mActiveParticles.begin();
666                std::advance(i, index);
667                return *i;
668        }
669    //-----------------------------------------------------------------------
670    Particle* ParticleSystem::createParticle(void)
671    {
672                Particle* p = 0;
673                if (!mFreeParticles.empty())
674                {
675                // Fast creation (don't use superclass since emitter will init)
676                p = mFreeParticles.front();
677                mActiveParticles.splice(mActiveParticles.end(), mFreeParticles, mFreeParticles.begin());
678
679                        p->_notifyOwner(this);
680                }
681
682        return p;
683
684    }
685    //-----------------------------------------------------------------------
686    Particle* ParticleSystem::createEmitterParticle(const String& emitterName)
687    {
688                // Get the appropriate list and retrieve an emitter     
689                Particle* p = 0;
690                std::list<ParticleEmitter*>* fee = findFreeEmittedEmitter(emitterName);
691                if (fee && !fee->empty())
692                {
693                p = fee->front();
694                        p->particleType = Particle::Emitter;
695                        fee->pop_front();
696                        mActiveParticles.push_back(p);
697
698                        // Also add to mActiveEmittedEmitters. This is needed to traverse through all active emitters
699                        // that are emitted. Don't use mActiveParticles for that (although they are added to
700                        // mActiveParticles also), because it would take too long to traverse.
701                        mActiveEmittedEmitters.push_back(static_cast<ParticleEmitter*>(p));
702                       
703                        p->_notifyOwner(this);
704                }
705
706        return p;
707    }
708    //-----------------------------------------------------------------------
709    void ParticleSystem::_updateRenderQueue(RenderQueue* queue)
710    {
711        if (mRenderer)
712        {
713            mRenderer->_updateRenderQueue(queue, mActiveParticles, mCullIndividual);
714        }
715    }
716    void ParticleSystem::initParameters(void)
717    {
718        if (createParamDictionary("ParticleSystem"))
719        {
720            ParamDictionary* dict = getParamDictionary();
721
722            dict->addParameter(ParameterDef("quota", 
723                "The maximum number of particle allowed at once in this system.",
724                PT_UNSIGNED_INT),
725                &msQuotaCmd);
726
727            dict->addParameter(ParameterDef("emit_emitter_quota", 
728                "The maximum number of emitters to be emitted at once in this system.",
729                PT_UNSIGNED_INT),
730                                &msEmittedEmitterQuotaCmd);
731
732                        dict->addParameter(ParameterDef("material", 
733                "The name of the material to be used to render all particles in this system.",
734                PT_STRING),
735                &msMaterialCmd);
736
737            dict->addParameter(ParameterDef("particle_width", 
738                "The width of particles in world units.",
739                PT_REAL),
740                &msWidthCmd);
741
742            dict->addParameter(ParameterDef("particle_height", 
743                "The height of particles in world units.",
744                PT_REAL),
745                &msHeightCmd);
746
747            dict->addParameter(ParameterDef("cull_each", 
748                "If true, each particle is culled in it's own right. If false, the entire system is culled as a whole.",
749                PT_BOOL),
750                &msCullCmd);
751
752                        dict->addParameter(ParameterDef("renderer", 
753                                "Sets the particle system renderer to use (default 'billboard').",
754                                PT_STRING),
755                                &msRendererCmd);
756
757                        dict->addParameter(ParameterDef("sorted", 
758                                "Sets whether particles should be sorted relative to the camera. ",
759                                PT_BOOL),
760                                &msSortedCmd);
761
762                        dict->addParameter(ParameterDef("local_space", 
763                                "Sets whether particles should be kept in local space rather than "
764                                "emitted into world space. ",
765                                PT_BOOL),
766                                &msLocalSpaceCmd);
767
768                        dict->addParameter(ParameterDef("iteration_interval", 
769                                "Sets a fixed update interval for the system, or 0 for the frame rate. ",
770                                PT_REAL),
771                                &msIterationIntervalCmd);
772
773                        dict->addParameter(ParameterDef("nonvisible_update_timeout", 
774                                "Sets a timeout on updates to the system if the system is not visible "
775                                "for the given number of seconds (0 to always update)",
776                                PT_REAL),
777                                &msNonvisibleTimeoutCmd);
778
779        }
780    }
781    //-----------------------------------------------------------------------
782    void ParticleSystem::_updateBounds()
783    {
784
785        if (mParentNode && (mBoundsAutoUpdate || mBoundsUpdateTime > 0.0f))
786        {
787            if (mActiveParticles.empty())
788            {
789                // No particles, reset to null if auto update bounds
790                if (mBoundsAutoUpdate)
791                {
792                    mWorldAABB.setNull();
793                }
794            }
795            else
796            {
797                Vector3 min;
798                Vector3 max;
799                if (!mBoundsAutoUpdate && mWorldAABB.isFinite())
800                {
801                    // We're on a limit, grow rather than reset each time
802                    // so that we pick up the worst case scenario
803                    min = mWorldAABB.getMinimum();
804                    max = mWorldAABB.getMaximum();
805                }
806                else
807                {
808                    min.x = min.y = min.z = Math::POS_INFINITY;
809                    max.x = max.y = max.z = Math::NEG_INFINITY;
810                }
811                ActiveParticleList::iterator p;
812                Vector3 halfScale = Vector3::UNIT_SCALE * 0.5;
813                Vector3 defaultPadding = 
814                    halfScale * std::max(mDefaultHeight, mDefaultWidth);
815                for (p = mActiveParticles.begin(); p != mActiveParticles.end(); ++p)
816                {
817                    if ((*p)->mOwnDimensions)
818                    {
819                        Vector3 padding = 
820                            halfScale * std::max((*p)->mWidth, (*p)->mHeight);
821                        min.makeFloor((*p)->position - padding);
822                        max.makeCeil((*p)->position + padding);
823                    }
824                    else
825                    {
826                        min.makeFloor((*p)->position - defaultPadding);
827                        max.makeCeil((*p)->position + defaultPadding);
828                    }
829                }
830                mWorldAABB.setExtents(min, max);
831            }
832
833
834            if (mLocalSpace)
835            {
836                // Merge calculated box with current AABB to preserve any user-set AABB
837                mAABB.merge(mWorldAABB);
838            }
839            else
840            {
841                // We've already put particles in world space to decouple them from the
842                // node transform, so reverse transform back since we're expected to
843                // provide a local AABB
844                AxisAlignedBox newAABB(mWorldAABB);
845                newAABB.transformAffine(mParentNode->_getFullTransform().inverseAffine());
846
847                // Merge calculated box with current AABB to preserve any user-set AABB
848                mAABB.merge(newAABB);
849            }
850
851            mParentNode->needUpdate();
852        }
853    }
854    //-----------------------------------------------------------------------
855    void ParticleSystem::fastForward(Real time, Real interval)
856    {
857        // First make sure all transforms are up to date
858
859        for (Real ftime = 0; ftime < time; ftime += interval)
860        {
861            _update(interval);
862        }
863    }
864    //-----------------------------------------------------------------------
865    const String& ParticleSystem::getMovableType(void) const
866    {
867        return ParticleSystemFactory::FACTORY_TYPE_NAME;
868    }
869    //-----------------------------------------------------------------------
870    void ParticleSystem::_notifyParticleResized(void)
871    {
872        if (mRenderer)
873        {
874            mRenderer->_notifyParticleResized();
875        }
876    }
877    //-----------------------------------------------------------------------
878    void ParticleSystem::_notifyParticleRotated(void)
879    {
880        if (mRenderer)
881        {
882            mRenderer->_notifyParticleRotated();
883        }
884    }
885    //-----------------------------------------------------------------------
886    void ParticleSystem::setDefaultDimensions( Real width, Real height )
887    {
888        mDefaultWidth = width;
889        mDefaultHeight = height;
890        if (mRenderer)
891        {
892            mRenderer->_notifyDefaultDimensions(width, height);
893        }
894    }
895    //-----------------------------------------------------------------------
896    void ParticleSystem::setDefaultWidth(Real width)
897    {
898        mDefaultWidth = width;
899        if (mRenderer)
900        {
901            mRenderer->_notifyDefaultDimensions(mDefaultWidth, mDefaultHeight);
902        }
903    }
904    //-----------------------------------------------------------------------
905    Real ParticleSystem::getDefaultWidth(void) const
906    {
907        return mDefaultWidth;
908    }
909    //-----------------------------------------------------------------------
910    void ParticleSystem::setDefaultHeight(Real height)
911    {
912        mDefaultHeight = height;
913        if (mRenderer)
914        {
915            mRenderer->_notifyDefaultDimensions(mDefaultWidth, mDefaultHeight);
916        }
917    }
918    //-----------------------------------------------------------------------
919    Real ParticleSystem::getDefaultHeight(void) const
920    {
921        return mDefaultHeight;
922    }
923    //-----------------------------------------------------------------------
924    void ParticleSystem::_notifyCurrentCamera(Camera* cam)
925    {
926                MovableObject::_notifyCurrentCamera(cam);
927
928                // Record visible
929                mLastVisibleFrame = Root::getSingleton().getCurrentFrameNumber();
930                mTimeSinceLastVisible = 0.0f;
931
932        if (mSorted)
933                {
934                        _sortParticles(cam);
935                }
936
937                if (mRenderer)
938        {
939                        if (!mIsRendererConfigured)
940                                configureRenderer();
941
942            mRenderer->_notifyCurrentCamera(cam);
943        }
944    }
945    //-----------------------------------------------------------------------
946    void ParticleSystem::_notifyAttached(Node* parent, bool isTagPoint)
947    {
948        MovableObject::_notifyAttached(parent, isTagPoint);
949        if (mRenderer && mIsRendererConfigured)
950        {
951            mRenderer->_notifyAttached(parent, isTagPoint);
952        }
953
954        if (parent && !mTimeController)
955        {
956            // Assume visible
957            mTimeSinceLastVisible = 0;
958            mLastVisibleFrame = Root::getSingleton().getCurrentFrameNumber();
959
960            // Create time controller when attached
961            ControllerManager& mgr = ControllerManager::getSingleton(); 
962            ControllerValueRealPtr updValue(new ParticleSystemUpdateValue(this));
963            mTimeController = mgr.createFrameTimePassthroughController(updValue);
964        }
965        else if (!parent && mTimeController)
966        {
967            // Destroy controller
968            ControllerManager::getSingleton().destroyController(mTimeController);
969            mTimeController = 0;
970        }
971    }
972    //-----------------------------------------------------------------------
973    void ParticleSystem::setMaterialName(const String& name)
974    {
975        mMaterialName = name;
976        if (mIsRendererConfigured)
977        {
978            MaterialPtr mat = MaterialManager::getSingleton().load(
979                mMaterialName, mResourceGroupName);
980            mRenderer->_setMaterial(mat);
981        }
982    }
983    //-----------------------------------------------------------------------
984    const String& ParticleSystem::getMaterialName(void) const
985    {
986        return mMaterialName;
987    }
988    //-----------------------------------------------------------------------
989    void ParticleSystem::clear()
990    {
991        // Notify renderer if exists
992        if (mRenderer)
993        {
994            mRenderer->_notifyParticleCleared(mActiveParticles);
995        }
996
997        // Move actives to free list
998        mFreeParticles.splice(mFreeParticles.end(), mActiveParticles);
999
1000        // Add active emitted emitters to free list
1001                addActiveEmittedEmittersToFreeList();
1002
1003                // Remove all active emitted emitter instances
1004                mActiveEmittedEmitters.clear();
1005
1006                // Reset update remain time
1007        mUpdateRemainTime = 0;
1008    }
1009    //-----------------------------------------------------------------------
1010    void ParticleSystem::setRenderer(const String& rendererName)
1011    {
1012                if (mRenderer)
1013                {
1014                        // Destroy existing
1015                        destroyVisualParticles(0, mParticlePool.size());
1016                        ParticleSystemManager::getSingleton()._destroyRenderer(mRenderer);
1017                        mRenderer = 0;
1018                }
1019
1020        if (!rendererName.empty())
1021        {
1022                        mRenderer = ParticleSystemManager::getSingleton()._createRenderer(rendererName);
1023            mIsRendererConfigured = false;
1024        }
1025    }
1026    //-----------------------------------------------------------------------
1027    void ParticleSystem::configureRenderer(void)
1028    {
1029        // Actual allocate particles
1030        size_t currSize = mParticlePool.size();
1031        size_t size = mPoolSize;
1032        if( currSize < size )
1033        {
1034            this->increasePool(size);
1035
1036            for( size_t i = currSize; i < size; ++i )
1037            {
1038                // Add new items to the queue
1039                mFreeParticles.push_back( mParticlePool[i] );
1040            }
1041
1042            // Tell the renderer, if already configured
1043            if (mRenderer && mIsRendererConfigured)
1044            {
1045                mRenderer->_notifyParticleQuota(size);
1046            }
1047        }
1048
1049        if (mRenderer && !mIsRendererConfigured)
1050        {
1051            mRenderer->_notifyParticleQuota(mParticlePool.size());
1052            mRenderer->_notifyAttached(mParentNode, mParentIsTagPoint);
1053            mRenderer->_notifyDefaultDimensions(mDefaultWidth, mDefaultHeight);
1054            createVisualParticles(0, mParticlePool.size());
1055            MaterialPtr mat = MaterialManager::getSingleton().load(
1056                mMaterialName, mResourceGroupName);
1057            mRenderer->_setMaterial(mat);
1058                        if (mRenderQueueIDSet)
1059                                mRenderer->setRenderQueueGroup(mRenderQueueID);
1060                        mRenderer->setKeepParticlesInLocalSpace(mLocalSpace);
1061            mIsRendererConfigured = true;
1062        }
1063    }
1064    //-----------------------------------------------------------------------
1065    ParticleSystemRenderer* ParticleSystem::getRenderer(void) const
1066    {
1067        return mRenderer;
1068    }
1069    //-----------------------------------------------------------------------
1070    const String& ParticleSystem::getRendererName(void) const
1071    {
1072        if (mRenderer)
1073        {
1074            return mRenderer->getType();
1075        }
1076        else
1077        {
1078            return StringUtil::BLANK;
1079        }
1080    }
1081    //-----------------------------------------------------------------------
1082    bool ParticleSystem::getCullIndividually(void) const
1083    {
1084        return mCullIndividual;
1085    }
1086    //-----------------------------------------------------------------------
1087    void ParticleSystem::setCullIndividually(bool cullIndividual)
1088    {
1089        mCullIndividual = cullIndividual;
1090    }
1091    //-----------------------------------------------------------------------
1092        void ParticleSystem::createVisualParticles(size_t poolstart, size_t poolend)
1093        {
1094                ParticlePool::iterator i = mParticlePool.begin();
1095                ParticlePool::iterator iend = mParticlePool.begin();
1096                std::advance(i, poolstart);
1097                std::advance(iend, poolend);
1098                for (; i != iend; ++i)
1099                {
1100                        (*i)->_notifyVisualData(
1101                                mRenderer->_createVisualData());
1102                }
1103        }
1104    //-----------------------------------------------------------------------
1105        void ParticleSystem::destroyVisualParticles(size_t poolstart, size_t poolend)
1106        {
1107                ParticlePool::iterator i = mParticlePool.begin();
1108                ParticlePool::iterator iend = mParticlePool.begin();
1109                std::advance(i, poolstart);
1110                std::advance(iend, poolend);
1111                for (; i != iend; ++i)
1112                {
1113                        mRenderer->_destroyVisualData((*i)->getVisualData());
1114                        (*i)->_notifyVisualData(0);
1115                }
1116        }
1117    //-----------------------------------------------------------------------
1118    void ParticleSystem::setBounds(const AxisAlignedBox& aabb)
1119    {
1120        mAABB = aabb;
1121        Real sqDist = std::max(mAABB.getMinimum().squaredLength(), 
1122            mAABB.getMaximum().squaredLength());
1123        mBoundingRadius = Math::Sqrt(sqDist);
1124
1125    }
1126    //-----------------------------------------------------------------------
1127    void ParticleSystem::setBoundsAutoUpdated(bool autoUpdate, Real stopIn)
1128    {
1129        mBoundsAutoUpdate = autoUpdate;
1130        mBoundsUpdateTime = stopIn;
1131    }
1132        //-----------------------------------------------------------------------
1133        void ParticleSystem::setRenderQueueGroup(uint8 queueID)
1134        {
1135                MovableObject::setRenderQueueGroup(queueID);
1136                if (mRenderer)
1137                {
1138                        mRenderer->setRenderQueueGroup(queueID);
1139                }
1140        }
1141        //-----------------------------------------------------------------------
1142        void ParticleSystem::setKeepParticlesInLocalSpace(bool keepLocal)
1143        {
1144                mLocalSpace = keepLocal;
1145                if (mRenderer)
1146                {
1147                        mRenderer->setKeepParticlesInLocalSpace(keepLocal);
1148                }
1149        }
1150    //-----------------------------------------------------------------------
1151    void ParticleSystem::_sortParticles(Camera* cam)
1152    {
1153        if (mRenderer)
1154        {
1155            SortMode sortMode = mRenderer->_getSortMode();
1156            if (sortMode == SM_DIRECTION)
1157            {
1158                Vector3 camDir = cam->getDerivedDirection();
1159                if (mLocalSpace)
1160                {
1161                    // transform the camera direction into local space
1162                    camDir = mParentNode->_getDerivedOrientation().UnitInverse() * camDir;
1163                }
1164                mRadixSorter.sort(mActiveParticles, SortByDirectionFunctor(- camDir));
1165            }
1166            else if (sortMode == SM_DISTANCE)
1167            {
1168                Vector3 camPos = cam->getDerivedPosition();
1169                if (mLocalSpace)
1170                {
1171                    // transform the camera position into local space
1172                    camPos = mParentNode->_getDerivedOrientation().UnitInverse() *
1173                        (camPos - mParentNode->_getDerivedPosition()) / mParentNode->_getDerivedScale();
1174                }
1175                mRadixSorter.sort(mActiveParticles, SortByDistanceFunctor(camPos));
1176            }
1177        }
1178    }
1179    ParticleSystem::SortByDirectionFunctor::SortByDirectionFunctor(const Vector3& dir)
1180        : sortDir(dir)
1181    {
1182    }
1183    float ParticleSystem::SortByDirectionFunctor::operator()(Particle* p) const
1184    {
1185        return sortDir.dotProduct(p->position);
1186    }
1187    ParticleSystem::SortByDistanceFunctor::SortByDistanceFunctor(const Vector3& pos)
1188        : sortPos(pos)
1189    {
1190    }
1191    float ParticleSystem::SortByDistanceFunctor::operator()(Particle* p) const
1192    {
1193        // Sort descending by squared distance
1194        return - (sortPos - p->position).squaredLength();
1195    }
1196        //-----------------------------------------------------------------------
1197        uint32 ParticleSystem::getTypeFlags(void) const
1198        {
1199                return SceneManager::FX_TYPE_MASK;
1200        }
1201        //-----------------------------------------------------------------------
1202    void ParticleSystem::initialiseEmittedEmitters(void)
1203    {
1204                // Initialise the pool if needed
1205                size_t currSize = 0;
1206                if (mEmittedEmitterPool.empty())
1207                {
1208                        if (mEmittedEmitterPoolInitialised)
1209                        {
1210                                // It was already initialised, but apparently no emitted emitters were used
1211                                return;
1212                        }
1213                        else
1214                        {
1215                                initialiseEmittedEmitterPool();
1216                        }
1217                }
1218                else
1219                {
1220                        EmittedEmitterPool::iterator i;
1221                        for (i = mEmittedEmitterPool.begin(); i != mEmittedEmitterPool.end(); ++i)
1222                        {
1223                                currSize += i->second.size();
1224                        }
1225                }
1226
1227        size_t size = mEmittedEmitterPoolSize;
1228        if( currSize < size && !mEmittedEmitterPool.empty())
1229        {
1230                        // Increase the pool. Equally distribute over all vectors in the map
1231            increaseEmittedEmitterPool(size);
1232                       
1233                        // Add new items to the free list
1234                        addFreeEmittedEmitters();
1235                }
1236    }
1237
1238        //-----------------------------------------------------------------------
1239        void ParticleSystem::initialiseEmittedEmitterPool(void)
1240        {
1241                if (mEmittedEmitterPoolInitialised)
1242                        return;
1243
1244                // Run through mEmitters and add keys to the pool
1245                ParticleEmitterList::iterator emitterIterator;
1246                ParticleEmitterList::iterator emitterIteratorInner;
1247                ParticleEmitter* emitter = 0;
1248                ParticleEmitter* emitterInner = 0;
1249                for (emitterIterator = mEmitters.begin(); emitterIterator != mEmitters.end(); ++emitterIterator)
1250                {
1251                        // Determine the names of all emitters that are emitted
1252                        emitter = *emitterIterator ;
1253                        if (emitter && emitter->getEmittedEmitter() != StringUtil::BLANK)
1254                        {
1255                                // This one will be emitted, register its name and leave the vector empty!
1256                                EmittedEmitterList empty;
1257                                mEmittedEmitterPool.insert(make_pair(emitter->getEmittedEmitter(), empty));
1258                        }
1259
1260                        // Determine whether the emitter itself will be emitted and set the 'mEmitted' attribute
1261                        for (emitterIteratorInner = mEmitters.begin(); emitterIteratorInner != mEmitters.end(); ++emitterIteratorInner)
1262                        {
1263                                emitterInner = *emitterIteratorInner;
1264                                if (emitter && 
1265                                        emitterInner && 
1266                                        emitter->getName() != StringUtil::BLANK && 
1267                                        emitter->getName() == emitterInner->getEmittedEmitter())
1268                                {
1269                                        emitter->setEmitted(true);
1270                                        break;
1271                                }
1272                                else
1273                                {
1274                                        // Set explicitly to 'false' although the default value is already 'false'
1275                                        emitter->setEmitted(false);
1276                                }
1277                        }
1278                }
1279
1280                mEmittedEmitterPoolInitialised = true;
1281        }
1282    //-----------------------------------------------------------------------
1283    void ParticleSystem::increaseEmittedEmitterPool(size_t size)
1284    {
1285                // Don't proceed if the pool doesn't contain any keys of emitted emitters
1286                if (mEmittedEmitterPool.empty())
1287                        return;
1288
1289                EmittedEmitterPool::iterator emittedEmitterPoolIterator;
1290                ParticleEmitterList::iterator emitterIterator;
1291                ParticleEmitter* emitter = 0;
1292                ParticleEmitter* clonedEmitter = 0;
1293                String name = StringUtil::BLANK;
1294                EmittedEmitterList* e = 0;
1295                size_t maxNumberOfEmitters = size / mEmittedEmitterPool.size(); // equally distribute the number for each emitted emitter list
1296                size_t oldSize = 0;
1297       
1298                // Run through mEmittedEmitterPool and search for every key (=name) its corresponding emitter in mEmitters
1299                for (emittedEmitterPoolIterator = mEmittedEmitterPool.begin(); emittedEmitterPoolIterator != mEmittedEmitterPool.end(); ++emittedEmitterPoolIterator)
1300        {
1301                        name = emittedEmitterPoolIterator->first;
1302                        e = &emittedEmitterPoolIterator->second;
1303
1304                        // Search the correct emitter in the mEmitters vector
1305                        emitter = 0;
1306                        for (emitterIterator = mEmitters.begin(); emitterIterator != mEmitters.end(); ++emitterIterator)
1307                        {
1308                                emitter = *emitterIterator;
1309                                if (emitter && 
1310                                        name != StringUtil::BLANK && 
1311                                        name == emitter->getName())
1312                                {               
1313                                        // Found the right emitter, clone each emitter a number of times
1314                                        oldSize = e->size();
1315                                        for (size_t t = oldSize; t < maxNumberOfEmitters; ++t)
1316                                        {
1317                                                clonedEmitter = ParticleSystemManager::getSingleton()._createEmitter(emitter->getType(), this);
1318                                                emitter->copyParametersTo(clonedEmitter);
1319                                                clonedEmitter->setEmitted(emitter->isEmitted()); // is always 'true' by the way, but just in case
1320
1321                                                // Initially deactivate the emitted emitter if duration/repeat_delay are set
1322                                                if (clonedEmitter->getDuration() > 0.0f && 
1323                                                        (clonedEmitter->getRepeatDelay() > 0.0f || clonedEmitter->getMinRepeatDelay() > 0.0f || clonedEmitter->getMinRepeatDelay() > 0.0f))
1324                                                        clonedEmitter->setEnabled(false);
1325
1326                                                // Add cloned emitters to the pool
1327                                                e->push_back(clonedEmitter);
1328                                        }
1329                                }
1330                        }
1331        }
1332        }
1333    //-----------------------------------------------------------------------
1334    void ParticleSystem::addFreeEmittedEmitters(void)
1335    {
1336                // Don't proceed if the EmittedEmitterPool is empty
1337                if (mEmittedEmitterPool.empty())
1338                        return;
1339
1340                // Copy all pooled emitters to the free list
1341                EmittedEmitterPool::iterator emittedEmitterPoolIterator;
1342                EmittedEmitterList::iterator emittedEmitterIterator;
1343                EmittedEmitterList* emittedEmitters = 0;
1344                std::list<ParticleEmitter*>* fee = 0;
1345                String name = StringUtil::BLANK;
1346
1347                // Run through the emittedEmitterPool map
1348                for (emittedEmitterPoolIterator = mEmittedEmitterPool.begin(); emittedEmitterPoolIterator != mEmittedEmitterPool.end(); ++emittedEmitterPoolIterator)
1349        {
1350                        name = emittedEmitterPoolIterator->first;
1351                        emittedEmitters = &emittedEmitterPoolIterator->second;
1352                        fee = findFreeEmittedEmitter(name);
1353
1354                        // If it´s not in the map, create an empty one
1355                        if (!fee)
1356                        {
1357                                FreeEmittedEmitterList empty;
1358                                mFreeEmittedEmitters.insert(make_pair(name, empty));
1359                                fee = findFreeEmittedEmitter(name);
1360                        }
1361
1362                        // Check anyway if it´s ok now
1363                        if (!fee)
1364                                return; // forget it!
1365
1366                        // Add all emitted emitters from the pool to the free list
1367                        for(emittedEmitterIterator = emittedEmitters->begin(); emittedEmitterIterator != emittedEmitters->end(); ++emittedEmitterIterator)
1368                        {
1369                                fee->push_back(*emittedEmitterIterator);
1370                        }
1371                }
1372        }
1373    //-----------------------------------------------------------------------
1374    void ParticleSystem::removeAllEmittedEmitters(void)
1375    {
1376                EmittedEmitterPool::iterator emittedEmitterPoolIterator;
1377                EmittedEmitterList::iterator emittedEmitterListIterator;
1378                EmittedEmitterList* e = 0;
1379        for (emittedEmitterPoolIterator = mEmittedEmitterPool.begin(); emittedEmitterPoolIterator != mEmittedEmitterPool.end(); ++emittedEmitterPoolIterator)
1380        {
1381                        e = &emittedEmitterPoolIterator->second;
1382                        for (emittedEmitterListIterator = e->begin(); emittedEmitterListIterator != e->end(); ++emittedEmitterListIterator)
1383                        {
1384                                ParticleSystemManager::getSingleton()._destroyEmitter(*emittedEmitterListIterator);
1385                        }
1386                        e->clear();
1387        }
1388
1389                // Don´t leave any references behind
1390                mEmittedEmitterPool.clear();
1391                mFreeEmittedEmitters.clear();
1392                mActiveEmittedEmitters.clear();
1393    }
1394        //-----------------------------------------------------------------------
1395        std::list<ParticleEmitter*>* ParticleSystem::findFreeEmittedEmitter (const String& name)
1396        {
1397                FreeEmittedEmitterMap::iterator it;
1398                it = mFreeEmittedEmitters.find (name);
1399                if (it != mFreeEmittedEmitters.end())
1400                {
1401                        // Found it
1402                        return &it->second;
1403                }
1404
1405                return 0;
1406        }
1407        //-----------------------------------------------------------------------
1408        void ParticleSystem::removeFromActiveEmittedEmitters (ParticleEmitter* emitter)
1409        {
1410                assert(emitter && "Emitter to be removed is 0!");
1411                ActiveEmittedEmitterList::iterator itActiveEmit;
1412                for (itActiveEmit = mActiveEmittedEmitters.begin(); itActiveEmit != mActiveEmittedEmitters.end(); ++itActiveEmit)
1413                {
1414                        if (emitter == (*itActiveEmit))
1415                        {
1416                                mActiveEmittedEmitters.erase(itActiveEmit);
1417                                break;
1418                        }
1419                }
1420        }
1421        //-----------------------------------------------------------------------
1422        void ParticleSystem::addActiveEmittedEmittersToFreeList (void)
1423        {
1424                ActiveEmittedEmitterList::iterator itActiveEmit;
1425                for (itActiveEmit = mActiveEmittedEmitters.begin(); itActiveEmit != mActiveEmittedEmitters.end(); ++itActiveEmit)
1426                {
1427                        std::list<ParticleEmitter*>* fee = findFreeEmittedEmitter ((*itActiveEmit)->getName());
1428                        if (fee)
1429                                fee->push_back(*itActiveEmit);
1430                }
1431        }
1432        //-----------------------------------------------------------------------
1433        void ParticleSystem::_notifyReorganiseEmittedEmitterData (void)
1434        {
1435                removeAllEmittedEmitters();
1436                mEmittedEmitterPoolInitialised = false; // Don´t rearrange immediately; it will be performed in the regular flow
1437        }
1438    //-----------------------------------------------------------------------
1439    String ParticleSystem::CmdCull::doGet(const void* target) const
1440    {
1441        return StringConverter::toString(
1442            static_cast<const ParticleSystem*>(target)->getCullIndividually() );
1443    }
1444    void ParticleSystem::CmdCull::doSet(void* target, const String& val)
1445    {
1446        static_cast<ParticleSystem*>(target)->setCullIndividually(
1447            StringConverter::parseBool(val));
1448    }
1449    //-----------------------------------------------------------------------
1450    String ParticleSystem::CmdHeight::doGet(const void* target) const
1451    {
1452        return StringConverter::toString(
1453            static_cast<const ParticleSystem*>(target)->getDefaultHeight() );
1454    }
1455    void ParticleSystem::CmdHeight::doSet(void* target, const String& val)
1456    {
1457        static_cast<ParticleSystem*>(target)->setDefaultHeight(
1458            StringConverter::parseReal(val));
1459    }
1460    //-----------------------------------------------------------------------
1461    String ParticleSystem::CmdWidth::doGet(const void* target) const
1462    {
1463        return StringConverter::toString(
1464            static_cast<const ParticleSystem*>(target)->getDefaultWidth() );
1465    }
1466    void ParticleSystem::CmdWidth::doSet(void* target, const String& val)
1467    {
1468        static_cast<ParticleSystem*>(target)->setDefaultWidth(
1469            StringConverter::parseReal(val));
1470    }
1471    //-----------------------------------------------------------------------
1472    String ParticleSystem::CmdMaterial::doGet(const void* target) const
1473    {
1474        return static_cast<const ParticleSystem*>(target)->getMaterialName();
1475    }
1476    void ParticleSystem::CmdMaterial::doSet(void* target, const String& val)
1477    {
1478        static_cast<ParticleSystem*>(target)->setMaterialName(val);
1479    }
1480    //-----------------------------------------------------------------------
1481    String ParticleSystem::CmdQuota::doGet(const void* target) const
1482    {
1483        return StringConverter::toString(
1484            static_cast<const ParticleSystem*>(target)->getParticleQuota() );
1485    }
1486    void ParticleSystem::CmdQuota::doSet(void* target, const String& val)
1487    {
1488        static_cast<ParticleSystem*>(target)->setParticleQuota(
1489            StringConverter::parseUnsignedInt(val));
1490    }
1491    //-----------------------------------------------------------------------
1492    String ParticleSystem::CmdEmittedEmitterQuota::doGet(const void* target) const
1493    {
1494        return StringConverter::toString(
1495            static_cast<const ParticleSystem*>(target)->getEmittedEmitterQuota() );
1496    }
1497    void ParticleSystem::CmdEmittedEmitterQuota::doSet(void* target, const String& val)
1498    {
1499        static_cast<ParticleSystem*>(target)->setEmittedEmitterQuota(
1500            StringConverter::parseUnsignedInt(val));
1501    }
1502    //-----------------------------------------------------------------------
1503    String ParticleSystem::CmdRenderer::doGet(const void* target) const
1504    {
1505        return static_cast<const ParticleSystem*>(target)->getRendererName();
1506    }
1507    void ParticleSystem::CmdRenderer::doSet(void* target, const String& val)
1508    {
1509        static_cast<ParticleSystem*>(target)->setRenderer(val);
1510    }
1511        //-----------------------------------------------------------------------
1512        String ParticleSystem::CmdSorted::doGet(const void* target) const
1513        {
1514                return StringConverter::toString(
1515                        static_cast<const ParticleSystem*>(target)->getSortingEnabled());
1516        }
1517        void ParticleSystem::CmdSorted::doSet(void* target, const String& val)
1518        {
1519                static_cast<ParticleSystem*>(target)->setSortingEnabled(
1520                        StringConverter::parseBool(val));
1521        }
1522        //-----------------------------------------------------------------------
1523        String ParticleSystem::CmdLocalSpace::doGet(const void* target) const
1524        {
1525                return StringConverter::toString(
1526                        static_cast<const ParticleSystem*>(target)->getKeepParticlesInLocalSpace());
1527        }
1528        void ParticleSystem::CmdLocalSpace::doSet(void* target, const String& val)
1529        {
1530                static_cast<ParticleSystem*>(target)->setKeepParticlesInLocalSpace(
1531                        StringConverter::parseBool(val));
1532        }
1533        //-----------------------------------------------------------------------
1534        String ParticleSystem::CmdIterationInterval::doGet(const void* target) const
1535        {
1536                return StringConverter::toString(
1537                        static_cast<const ParticleSystem*>(target)->getIterationInterval());
1538        }
1539        void ParticleSystem::CmdIterationInterval::doSet(void* target, const String& val)
1540        {
1541                static_cast<ParticleSystem*>(target)->setIterationInterval(
1542                        StringConverter::parseReal(val));
1543        }
1544        //-----------------------------------------------------------------------
1545        String ParticleSystem::CmdNonvisibleTimeout::doGet(const void* target) const
1546        {
1547                return StringConverter::toString(
1548                        static_cast<const ParticleSystem*>(target)->getNonVisibleUpdateTimeout());
1549        }
1550        void ParticleSystem::CmdNonvisibleTimeout::doSet(void* target, const String& val)
1551        {
1552                static_cast<ParticleSystem*>(target)->setNonVisibleUpdateTimeout(
1553                        StringConverter::parseReal(val));
1554        }
1555   //-----------------------------------------------------------------------
1556    ParticleAffector::~ParticleAffector() 
1557    {
1558    }
1559    //-----------------------------------------------------------------------
1560    ParticleAffectorFactory::~ParticleAffectorFactory() 
1561    {
1562        // Destroy all affectors
1563        std::vector<ParticleAffector*>::iterator i;
1564        for (i = mAffectors.begin(); i != mAffectors.end(); ++i)
1565        {
1566            delete (*i);
1567        }
1568           
1569        mAffectors.clear();
1570
1571    }
1572    //-----------------------------------------------------------------------
1573    void ParticleAffectorFactory::destroyAffector(ParticleAffector* e)
1574    {
1575        std::vector<ParticleAffector*>::iterator i;
1576        for (i = mAffectors.begin(); i != mAffectors.end(); ++i)
1577        {
1578            if ((*i) == e)
1579            {
1580                mAffectors.erase(i);
1581                delete e;
1582                break;
1583            }
1584        }
1585    }
1586
1587}
Note: See TracBrowser for help on using the repository browser.