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