source: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreParticleSystem.cpp @ 1053

Revision 1053, 42.4 KB checked in by szirmay, 18 years ago (diff)
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-2005 The OGRE Team
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-----------------------------------------------------------------------------
24*/
25#include "OgreStableHeaders.h"
26
27#include "OgreParticleSystem.h"
28#include "OgreParticleSystemManager.h"
29#include "OgreRenderQueue.h"
30#include "OgreBillboardSet.h"
31#include "OgreParticleEmitter.h"
32#include "OgreParticleAffector.h"
33#include "OgreParticle.h"
34#include "OgreSceneNode.h"
35#include "OgreCamera.h"
36#include "OgreStringConverter.h"
37#include "OgreLogManager.h"
38#include "OgreException.h"
39#include "OgreParticleAffectorFactory.h"
40#include "OgreParticleSystemRenderer.h"
41#include "OgreMaterialManager.h"
42#include "OgreSceneManager.h"
43#include "OgreControllerManager.h"
44#include "OgreRoot.h"
45
46namespace Ogre {
47    // Init statics
48    ParticleSystem::CmdCull ParticleSystem::msCullCmd;
49    ParticleSystem::CmdHeight ParticleSystem::msHeightCmd;
50    ParticleSystem::CmdMaterial ParticleSystem::msMaterialCmd;
51    ParticleSystem::CmdQuota ParticleSystem::msQuotaCmd;
52    ParticleSystem::CmdWidth ParticleSystem::msWidthCmd;
53    ParticleSystem::CmdRenderer ParticleSystem::msRendererCmd;
54        ParticleSystem::CmdSorted ParticleSystem::msSortedCmd;
55        ParticleSystem::CmdLocalSpace ParticleSystem::msLocalSpaceCmd;
56        ParticleSystem::CmdIterationInterval ParticleSystem::msIterationIntervalCmd;
57        ParticleSystem::CmdNonvisibleTimeout ParticleSystem::msNonvisibleTimeoutCmd;
58
59    RadixSort<ParticleSystem::ActiveParticleList, Particle*, float> ParticleSystem::mRadixSorter;
60
61    Real ParticleSystem::msDefaultIterationInterval = 0;
62    Real ParticleSystem::msDefaultNonvisibleTimeout = 0;
63
64        //-----------------------------------------------------------------------
65        // Local class for updating based on time
66        class ParticleSystemUpdateValue : public ControllerValue<Real>
67        {
68        protected:
69                ParticleSystem* mTarget;
70        public:
71                ParticleSystemUpdateValue(ParticleSystem* target) : mTarget(target) {}
72
73                Real getValue(void) const { return 0; } // N/A
74
75                void setValue(Real value) { mTarget->_update(value); }
76
77        };
78    //-----------------------------------------------------------------------
79    ParticleSystem::ParticleSystem()
80      : mBoundsAutoUpdate(true),
81        mBoundsUpdateTime(10.0f),
82        mUpdateRemainTime(0),
83        mResourceGroupName(ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME),
84        mIsRendererConfigured(false),
85        mSpeedFactor(1.0f),
86        mIterationInterval(0),
87                mIterationIntervalSet(false),
88        mSorted(false),
89        mLocalSpace(false),
90                mNonvisibleTimeout(0),
91                mNonvisibleTimeoutSet(false),
92                mTimeSinceLastVisible(0),
93                mLastVisibleFrame(0),
94        mTimeController(0),
95        mRenderer(0),
96        mCullIndividual(false),
97        mPoolSize(0)
98    {
99        initParameters();
100        mAABB.setExtents(-1, -1, -1, 1, 1, 1);
101        mBoundingRadius = 1;
102        // Init world AABB to something silly
103        Vector3 min( Math::POS_INFINITY, Math::POS_INFINITY, Math::POS_INFINITY );
104        Vector3 max( Math::NEG_INFINITY, Math::NEG_INFINITY, Math::NEG_INFINITY );
105        mWorldAABB.setExtents(min, max);
106
107        // Default to billboard renderer
108        setRenderer("billboard");
109
110    }
111    //-----------------------------------------------------------------------
112    ParticleSystem::ParticleSystem(const String& name, const String& resourceGroup)
113      : MovableObject(name),
114        mBoundsAutoUpdate(true),
115        mBoundsUpdateTime(10.0f),
116        mUpdateRemainTime(0),
117        mResourceGroupName(resourceGroup),
118        mIsRendererConfigured(false),
119        mSpeedFactor(1.0f),
120        mIterationInterval(0),
121                mIterationIntervalSet(false),
122        mSorted(false),
123                mNonvisibleTimeout(0),
124                mNonvisibleTimeoutSet(false),
125                mTimeSinceLastVisible(0),
126                mLastVisibleFrame(Root::getSingleton().getCurrentFrameNumber()),
127        mTimeController(0),
128        mLocalSpace(false),
129        mRenderer(0),
130                mCullIndividual(false),
131        mPoolSize(0)
132    {
133        setDefaultDimensions( 100, 100 );
134        setMaterialName( "BaseWhite" );
135        // Default to 10 particles, expect app to specify (will only be increased, not decreased)
136        setParticleQuota( 10 );
137        initParameters();
138        mAABB.setExtents(-1, -1, -1, 1, 1, 1);
139        mBoundingRadius = 1;
140        // Init world AABB to something silly
141        Vector3 min( Math::POS_INFINITY, Math::POS_INFINITY, Math::POS_INFINITY );
142        Vector3 max( Math::NEG_INFINITY, Math::NEG_INFINITY, Math::NEG_INFINITY );
143        mWorldAABB.setExtents(min, max);
144
145        // Default to billboard renderer
146        setRenderer("billboard");
147    }
148    //-----------------------------------------------------------------------
149    ParticleSystem::~ParticleSystem()
150    {
151        if (mTimeController)
152        {
153            // Destroy controller
154            ControllerManager::getSingleton().destroyController(mTimeController);
155            mTimeController = 0;
156        }
157
158                // Arrange for the deletion of emitters & affectors
159        removeAllEmitters();
160        removeAllAffectors();
161
162                // Deallocate all particles
163                destroyVisualParticles(0, mParticlePool.size());
164        // Free pool items
165        ParticlePool::iterator i;
166        for (i = mParticlePool.begin(); i != mParticlePool.end(); ++i)
167        {
168            delete *i;
169        }
170
171        if (mRenderer)
172        {
173            ParticleSystemManager::getSingleton()._destroyRenderer(mRenderer);
174            mRenderer = 0;
175        }
176
177    }
178    //-----------------------------------------------------------------------
179    ParticleEmitter* ParticleSystem::addEmitter(const String& emitterType)
180    {
181        ParticleEmitter* em =
182            ParticleSystemManager::getSingleton()._createEmitter(emitterType, this);
183        mEmitters.push_back(em);
184        return em;
185    }
186    //-----------------------------------------------------------------------
187    ParticleEmitter* ParticleSystem::getEmitter(unsigned short index) const
188    {
189        assert(index < mEmitters.size() && "Emitter index out of bounds!");
190        return mEmitters[index];
191    }
192    //-----------------------------------------------------------------------
193    unsigned short ParticleSystem::getNumEmitters(void) const
194    {
195        return static_cast< unsigned short >( mEmitters.size() );
196    }
197    //-----------------------------------------------------------------------
198    void ParticleSystem::removeEmitter(unsigned short index)
199    {
200        assert(index < mEmitters.size() && "Emitter index out of bounds!");
201        ParticleEmitterList::iterator ei = mEmitters.begin() + index;
202        ParticleSystemManager::getSingleton()._destroyEmitter(*ei);
203        mEmitters.erase(ei);
204    }
205    //-----------------------------------------------------------------------
206    void ParticleSystem::removeAllEmitters(void)
207    {
208        // DON'T delete directly, we don't know what heap these have been created on
209        ParticleEmitterList::iterator ei;
210        for (ei = mEmitters.begin(); ei != mEmitters.end(); ++ei)
211        {
212            ParticleSystemManager::getSingleton()._destroyEmitter(*ei);
213        }
214        mEmitters.clear();
215    }
216    //-----------------------------------------------------------------------
217    ParticleAffector* ParticleSystem::addAffector(const String& affectorType)
218    {
219        ParticleAffector* af =
220            ParticleSystemManager::getSingleton()._createAffector(affectorType, this);
221        mAffectors.push_back(af);
222        return af;
223    }
224    //-----------------------------------------------------------------------
225    ParticleAffector* ParticleSystem::getAffector(unsigned short index) const
226    {
227        assert(index < mAffectors.size() && "Affector index out of bounds!");
228        return mAffectors[index];
229    }
230    //-----------------------------------------------------------------------
231    unsigned short ParticleSystem::getNumAffectors(void) const
232    {
233        return static_cast< unsigned short >( mAffectors.size() );
234    }
235    //-----------------------------------------------------------------------
236    void ParticleSystem::removeAffector(unsigned short index)
237    {
238        assert(index < mAffectors.size() && "Affector index out of bounds!");
239        ParticleAffectorList::iterator ai = mAffectors.begin() + index;
240        ParticleSystemManager::getSingleton()._destroyAffector(*ai);
241        mAffectors.erase(ai);
242    }
243    //-----------------------------------------------------------------------
244    void ParticleSystem::removeAllAffectors(void)
245    {
246        // DON'T delete directly, we don't know what heap these have been created on
247        ParticleAffectorList::iterator ai;
248        for (ai = mAffectors.begin(); ai != mAffectors.end(); ++ai)
249        {
250            ParticleSystemManager::getSingleton()._destroyAffector(*ai);
251        }
252        mAffectors.clear();
253    }
254    //-----------------------------------------------------------------------
255    ParticleSystem& ParticleSystem::operator=(const ParticleSystem& rhs)
256    {
257        // Blank this system's emitters & affectors
258        removeAllEmitters();
259        removeAllAffectors();
260
261        // Copy emitters
262        unsigned int i;
263        for(i = 0; i < rhs.getNumEmitters(); ++i)
264        {
265            ParticleEmitter* rhsEm = rhs.getEmitter(i);
266            ParticleEmitter* newEm = addEmitter(rhsEm->getType());
267            rhsEm->copyParametersTo(newEm);
268        }
269        // Copy affectors
270        for(i = 0; i < rhs.getNumAffectors(); ++i)
271        {
272            ParticleAffector* rhsAf = rhs.getAffector(i);
273            ParticleAffector* newAf = addAffector(rhsAf->getType());
274            rhsAf->copyParametersTo(newAf);
275        }
276        setParticleQuota(rhs.getParticleQuota());
277        setMaterialName(rhs.mMaterialName);
278        setDefaultDimensions(rhs.mDefaultWidth, rhs.mDefaultHeight);
279        mCullIndividual = rhs.mCullIndividual;
280                mSorted = rhs.mSorted;
281                mLocalSpace = rhs.mLocalSpace;
282                mIterationInterval = rhs.mIterationInterval;
283                mIterationIntervalSet = rhs.mIterationIntervalSet;
284                mNonvisibleTimeout = rhs.mNonvisibleTimeout;
285                mNonvisibleTimeoutSet = rhs.mNonvisibleTimeoutSet;
286                // last frame visible and time since last visible should be left default
287
288        setRenderer(rhs.getRendererName());
289        // Copy settings
290        if (mRenderer && rhs.getRenderer())
291        {
292            rhs.getRenderer()->copyParametersTo(mRenderer);
293        }
294
295        return *this;
296
297    }
298    //-----------------------------------------------------------------------
299    size_t ParticleSystem::getNumParticles(void) const
300    {
301        return mActiveParticles.size();
302    }
303    //-----------------------------------------------------------------------
304    size_t ParticleSystem::getParticleQuota(void) const
305    {
306        return mPoolSize;
307    }
308    //-----------------------------------------------------------------------
309    void ParticleSystem::setParticleQuota(size_t size)
310    {
311        // Never shrink below size()
312        size_t currSize = mParticlePool.size();
313
314        if( currSize < size )
315        {
316            // Will allocate particles on demand
317            mPoolSize = size;
318           
319        }
320    }
321    //-----------------------------------------------------------------------
322        void ParticleSystem::setNonVisibleUpdateTimeout(Real timeout)
323        {
324                mNonvisibleTimeout = timeout;
325                mNonvisibleTimeoutSet = true;
326        }
327    //-----------------------------------------------------------------------
328        void ParticleSystem::setIterationInterval(Real interval)
329        {
330                mIterationInterval = interval;
331                mIterationIntervalSet = true;
332        }
333    //-----------------------------------------------------------------------
334    void ParticleSystem::_update(Real timeElapsed)
335    {
336        // Only update if attached to a node
337        if (!mParentNode)
338            return;
339
340                Real nonvisibleTimeout = mNonvisibleTimeoutSet ?
341                        mNonvisibleTimeout : msDefaultNonvisibleTimeout;
342
343                if (nonvisibleTimeout > 0)
344                {
345                        // Check whether it's been more than one frame (update is ahead of
346                        // camera notification by one frame because of the ordering)
347                        long frameDiff = Root::getSingleton().getCurrentFrameNumber() - mLastVisibleFrame;
348                        if (frameDiff > 1 || frameDiff < 0) // < 0 if wrap only
349                        {
350                                mTimeSinceLastVisible += timeElapsed;
351                                if (mTimeSinceLastVisible >= nonvisibleTimeout)
352                                {
353                                        // No update
354                                        return;
355                                }
356                        }
357                }
358
359                // Scale incoming speed for the rest of the calculation
360                timeElapsed *= mSpeedFactor;
361
362        // Init renderer if not done already
363        configureRenderer();
364
365        Real iterationInterval = mIterationIntervalSet ?
366            mIterationInterval : msDefaultIterationInterval;
367        if (iterationInterval > 0)
368        {
369            mUpdateRemainTime += timeElapsed;
370
371            while (mUpdateRemainTime >= iterationInterval)
372            {
373                // Update existing particles
374                _expire(iterationInterval);
375                _triggerAffectors(iterationInterval);
376                _applyMotion(iterationInterval);
377                // Emit new particles
378                _triggerEmitters(iterationInterval);
379
380                mUpdateRemainTime -= iterationInterval;
381            }
382        }
383        else
384        {
385            // Update existing particles
386            _expire(timeElapsed);
387            _triggerAffectors(timeElapsed);
388            _applyMotion(timeElapsed);
389            // Emit new particles
390            _triggerEmitters(timeElapsed);
391        }
392
393        if (!mBoundsAutoUpdate && mBoundsUpdateTime > 0.0f)
394            mBoundsUpdateTime -= timeElapsed; // count down
395        _updateBounds();
396
397    }
398    //-----------------------------------------------------------------------
399    void ParticleSystem::_expire(Real timeElapsed)
400    {
401        ActiveParticleList::iterator i, itEnd;
402        Particle* pParticle;
403
404        itEnd = mActiveParticles.end();
405
406        for (i = mActiveParticles.begin(); i != itEnd; )
407        {
408            pParticle = static_cast<Particle*>(*i);
409
410#ifdef GAMETOOLS_ILLUMINATION_MODULE
411                        if(pParticle->timeToLive == 0)
412                        {
413                                ++i;
414                                continue;
415                        }
416#endif
417                        if (pParticle->timeToLive < timeElapsed)           
418            {
419                // Destroy this one
420                mFreeParticles.push_back( *i );
421                i = mActiveParticles.erase( i );
422            }
423            else
424            {
425                // Decrement TTL
426                pParticle->timeToLive -= timeElapsed;
427                                ++i;
428            }
429
430        }
431    }
432    //-----------------------------------------------------------------------
433    void ParticleSystem::_triggerEmitters(Real timeElapsed)
434    {
435        // Add up requests for emission
436        static std::vector<unsigned> requested;
437        if( requested.size() != mEmitters.size() )
438            requested.resize( mEmitters.size() );
439
440        size_t totalRequested, emitterCount, i, emissionAllowed;
441        ParticleEmitterList::iterator   itEmit, iEmitEnd;
442        ParticleAffectorList::iterator  itAff, itAffEnd;
443                           
444        iEmitEnd = mEmitters.end();
445        emitterCount = mEmitters.size();
446        emissionAllowed = mFreeParticles.size();
447        totalRequested = 0;
448
449        // Count up total requested emissions
450        for (itEmit = mEmitters.begin(), i = 0; itEmit != iEmitEnd; ++itEmit, ++i)
451        {
452            requested[i] = (*itEmit)->_getEmissionCount(timeElapsed);
453            totalRequested += requested[i];
454        }
455
456
457        // Check if the quota will be exceeded, if so reduce demand
458        if (totalRequested > emissionAllowed)
459        {
460            // Apportion down requested values to allotted values
461            Real ratio =  (Real)emissionAllowed / (Real)totalRequested;
462            for (i = 0; i < emitterCount; ++i)
463            {
464                requested[i] = static_cast<unsigned>(requested[i] * ratio);
465            }
466        }
467
468        // Emit
469                // For each emission, apply a subset of the motion for the frame
470                // this ensures an even distribution of particles when many are
471                // emitted in a single frame
472        for (itEmit = mEmitters.begin(), i = 0; itEmit != iEmitEnd; ++itEmit, ++i)
473        {
474                        Real timePoint = 0.0f;
475                        Real timeInc = timeElapsed / requested[i];
476                for (unsigned int j = 0; j < requested[i]; ++j)
477            {
478                // Create a new particle & init using emitter
479                Particle* p = createParticle();
480                (*itEmit)->_initParticle(p);
481
482                                // Translate position & direction into world space
483                                if (!mLocalSpace)
484                                {
485                                        p->position  =
486                                                (mParentNode->_getDerivedOrientation() *
487                         (mParentNode->_getDerivedScale() * p->position))
488                                                + mParentNode->_getDerivedPosition();
489                                        p->direction =
490                                                (mParentNode->_getDerivedOrientation() * p->direction);
491                                }
492
493                                // apply partial frame motion to this particle
494                p->position += (p->direction * timePoint);
495
496                                // apply particle initialization by the affectors
497                                itAffEnd = mAffectors.end();
498                                for (itAff = mAffectors.begin(); itAff != itAffEnd; ++itAff)
499                                        (*itAff)->_initParticle(p);
500
501                                // Increment time fragment
502                                timePoint += timeInc;
503            }
504        }
505
506
507    }
508    //-----------------------------------------------------------------------
509    void ParticleSystem::_applyMotion(Real timeElapsed)
510    {
511        ActiveParticleList::iterator i, itEnd;
512        Particle* pParticle;
513
514        itEnd = mActiveParticles.end();
515        for (i = mActiveParticles.begin(); i != itEnd; ++i)
516        {
517            pParticle = static_cast<Particle*>(*i);
518            pParticle->position += (pParticle->direction * timeElapsed);
519        }
520
521    }
522    //-----------------------------------------------------------------------
523    void ParticleSystem::_triggerAffectors(Real timeElapsed)
524    {
525        ParticleAffectorList::iterator i, itEnd;
526       
527        itEnd = mAffectors.end();
528        for (i = mAffectors.begin(); i != itEnd; ++i)
529        {
530            (*i)->_affectParticles(this, timeElapsed);
531        }
532
533    }
534    //-----------------------------------------------------------------------
535    void ParticleSystem::increasePool(size_t size)
536    {
537        size_t oldSize = mParticlePool.size();
538
539        // Increase size
540        mParticlePool.reserve(size);
541        mParticlePool.resize(size);
542
543        // Create new particles
544        for( size_t i = oldSize; i < size; i++ )
545                {
546            mParticlePool[i] = new Particle();
547                }
548
549                if (mIsRendererConfigured)
550                {
551                        createVisualParticles(oldSize, size);
552                }
553
554
555    }
556    //-----------------------------------------------------------------------
557    ParticleIterator ParticleSystem::_getIterator(void)
558    {
559        return ParticleIterator(mActiveParticles.begin(), mActiveParticles.end());
560    }
561    //-----------------------------------------------------------------------
562        Particle* ParticleSystem::getParticle(size_t index)
563        {
564                assert (index < mActiveParticles.size() && "Index out of bounds!");
565                ActiveParticleList::iterator i = mActiveParticles.begin();
566                std::advance(i, index);
567                return *i;
568        }
569    //-----------------------------------------------------------------------
570    Particle* ParticleSystem::createParticle(void)
571    {
572        // Fast creation (don't use superclass since emitter will init)
573        Particle* p = mFreeParticles.front();
574        mActiveParticles.splice(mActiveParticles.end(), mFreeParticles, mFreeParticles.begin());
575
576        p->_notifyOwner(this);
577
578        return p;
579
580    }
581    //-----------------------------------------------------------------------
582    void ParticleSystem::_updateRenderQueue(RenderQueue* queue)
583    {
584        if (mRenderer)
585        {
586            mRenderer->_updateRenderQueue(queue, mActiveParticles, mCullIndividual);
587        }
588    }
589    void ParticleSystem::initParameters(void)
590    {
591        if (createParamDictionary("ParticleSystem"))
592        {
593            ParamDictionary* dict = getParamDictionary();
594
595            dict->addParameter(ParameterDef("quota",
596                "The maximum number of particle allowed at once in this system.",
597                PT_UNSIGNED_INT),
598                &msQuotaCmd);
599
600            dict->addParameter(ParameterDef("material",
601                "The name of the material to be used to render all particles in this system.",
602                PT_STRING),
603                &msMaterialCmd);
604
605            dict->addParameter(ParameterDef("particle_width",
606                "The width of particles in world units.",
607                PT_REAL),
608                &msWidthCmd);
609
610            dict->addParameter(ParameterDef("particle_height",
611                "The height of particles in world units.",
612                PT_REAL),
613                &msHeightCmd);
614
615            dict->addParameter(ParameterDef("cull_each",
616                "If true, each particle is culled in it's own right. If false, the entire system is culled as a whole.",
617                PT_BOOL),
618                &msCullCmd);
619
620                        dict->addParameter(ParameterDef("renderer",
621                                "Sets the particle system renderer to use (default 'billboard').",
622                                PT_STRING),
623                                &msRendererCmd);
624
625                        dict->addParameter(ParameterDef("sorted",
626                                "Sets whether particles should be sorted relative to the camera. ",
627                                PT_BOOL),
628                                &msSortedCmd);
629
630                        dict->addParameter(ParameterDef("local_space",
631                                "Sets whether particles should be kept in local space rather than "
632                                "emitted into world space. ",
633                                PT_BOOL),
634                                &msLocalSpaceCmd);
635
636                        dict->addParameter(ParameterDef("iteration_interval",
637                                "Sets a fixed update interval for the system, or 0 for the frame rate. ",
638                                PT_REAL),
639                                &msIterationIntervalCmd);
640
641                        dict->addParameter(ParameterDef("nonvisible_update_timeout",
642                                "Sets a timeout on updates to the system if the system is not visible "
643                                "for the given number of seconds (0 to always update)",
644                                PT_REAL),
645                                &msNonvisibleTimeoutCmd);
646
647        }
648    }
649    //-----------------------------------------------------------------------
650    void ParticleSystem::_updateBounds()
651    {
652
653        if (mParentNode && (mBoundsAutoUpdate || mBoundsUpdateTime > 0.0f))
654        {
655
656            Vector3 min; 
657            Vector3 max;
658            if (!mBoundsAutoUpdate)
659            {
660                // We're on a limit, grow rather than reset each time
661                // so that we pick up the worst case scenario
662                min = mWorldAABB.getMinimum();
663                max = mWorldAABB.getMaximum();
664            }
665            else
666            {
667                min.x = min.y = min.z = Math::POS_INFINITY;
668                max.x = max.y = max.z = Math::NEG_INFINITY;
669            }
670            ActiveParticleList::iterator p;
671            Vector3 halfScale = Vector3::UNIT_SCALE * 0.5;
672            Vector3 defaultPadding =
673                halfScale * std::max(mDefaultHeight, mDefaultWidth);
674            for (p = mActiveParticles.begin(); p != mActiveParticles.end(); ++p)
675            {
676
677                if ((*p)->mOwnDimensions)
678                {
679                    Vector3 padding =
680                        halfScale * std::max((*p)->mWidth, (*p)->mHeight);
681                    min.makeFloor((*p)->position - padding);
682                    max.makeCeil((*p)->position + padding);
683                }
684                else
685                {
686                    min.makeFloor((*p)->position - defaultPadding);
687                    max.makeCeil((*p)->position + defaultPadding);
688                }
689            }
690            mWorldAABB.setExtents(min, max);
691
692
693            if (mLocalSpace)
694            {
695                // Merge calculated box with current AABB to preserve any user-set AABB
696                mAABB.merge(mWorldAABB);
697            }
698            else
699            {
700                // We've already put particles in world space to decouple them from the
701                // node transform, so reverse transform back since we're expected to
702                // provide a local AABB
703                AxisAlignedBox newAABB(mWorldAABB);
704                newAABB.transform(mParentNode->_getFullTransform().inverse());
705
706                // Merge calculated box with current AABB to preserve any user-set AABB
707                mAABB.merge(newAABB);
708            }
709
710            mParentNode->needUpdate();
711        }
712    }
713    //-----------------------------------------------------------------------
714    void ParticleSystem::fastForward(Real time, Real interval)
715    {
716        // First make sure all transforms are up to date
717
718        for (Real ftime = 0; ftime < time; ftime += interval)
719        {
720            _update(interval);
721        }
722    }
723    //-----------------------------------------------------------------------
724    const String& ParticleSystem::getMovableType(void) const
725    {
726        return ParticleSystemFactory::FACTORY_TYPE_NAME;
727    }
728    //-----------------------------------------------------------------------
729    void ParticleSystem::_notifyParticleResized(void)
730    {
731        if (mRenderer)
732        {
733            mRenderer->_notifyParticleResized();
734        }
735    }
736    //-----------------------------------------------------------------------
737    void ParticleSystem::_notifyParticleRotated(void)
738    {
739        if (mRenderer)
740        {
741            mRenderer->_notifyParticleRotated();
742        }
743    }
744    //-----------------------------------------------------------------------
745    void ParticleSystem::setDefaultDimensions( Real width, Real height )
746    {
747        mDefaultWidth = width;
748        mDefaultHeight = height;
749        if (mRenderer)
750        {
751            mRenderer->_notifyDefaultDimensions(width, height);
752        }
753    }
754    //-----------------------------------------------------------------------
755    void ParticleSystem::setDefaultWidth(Real width)
756    {
757        mDefaultWidth = width;
758        if (mRenderer)
759        {
760            mRenderer->_notifyDefaultDimensions(mDefaultWidth, mDefaultHeight);
761        }
762    }
763    //-----------------------------------------------------------------------
764    Real ParticleSystem::getDefaultWidth(void) const
765    {
766        return mDefaultWidth;
767    }
768    //-----------------------------------------------------------------------
769    void ParticleSystem::setDefaultHeight(Real height)
770    {
771        mDefaultHeight = height;
772        if (mRenderer)
773        {
774            mRenderer->_notifyDefaultDimensions(mDefaultWidth, mDefaultHeight);
775        }
776    }
777    //-----------------------------------------------------------------------
778    Real ParticleSystem::getDefaultHeight(void) const
779    {
780        return mDefaultHeight;
781    }
782    //-----------------------------------------------------------------------
783    void ParticleSystem::_notifyCurrentCamera(Camera* cam)
784    {
785                MovableObject::_notifyCurrentCamera(cam);
786
787                // Record visible
788                mLastVisibleFrame = Root::getSingleton().getCurrentFrameNumber();
789                mTimeSinceLastVisible = 0.0f;
790
791        if (mSorted)
792                {
793                        _sortParticles(cam);
794                }
795
796                if (mRenderer)
797        {
798                        if (!mIsRendererConfigured)
799                                configureRenderer();
800
801            mRenderer->_notifyCurrentCamera(cam);
802        }
803    }
804    //-----------------------------------------------------------------------
805    void ParticleSystem::_notifyAttached(Node* parent, bool isTagPoint)
806    {
807        MovableObject::_notifyAttached(parent, isTagPoint);
808        if (mRenderer)
809        {
810            mRenderer->_notifyAttached(parent, isTagPoint);
811        }
812
813        if (parent && !mTimeController)
814        {
815            // Assume visible
816            mTimeSinceLastVisible = 0;
817            mLastVisibleFrame = Root::getSingleton().getCurrentFrameNumber();
818
819            // Create time controller when attached
820            ControllerManager& mgr = ControllerManager::getSingleton();
821            ControllerValueRealPtr updValue(new ParticleSystemUpdateValue(this));
822            mTimeController = mgr.createFrameTimePassthroughController(updValue);
823        }
824        else if (!parent && mTimeController)
825        {
826            // Destroy controller
827            ControllerManager::getSingleton().destroyController(mTimeController);
828            mTimeController = 0;
829        }
830    }
831    //-----------------------------------------------------------------------
832    void ParticleSystem::setMaterialName(const String& name)
833    {
834        mMaterialName = name;
835        if (mIsRendererConfigured)
836        {
837            MaterialPtr mat = MaterialManager::getSingleton().load(
838                mMaterialName, mResourceGroupName);
839            mRenderer->_setMaterial(mat);
840        }
841    }
842    //-----------------------------------------------------------------------
843    const String& ParticleSystem::getMaterialName(void) const
844    {
845        return mMaterialName;
846    }
847    //-----------------------------------------------------------------------
848    void ParticleSystem::clear()
849    {
850        // Insert actives into free list
851        mFreeParticles.insert(mFreeParticles.end(), mActiveParticles.begin(), mActiveParticles.end());
852
853        // Remove all active instances
854        mActiveParticles.clear();
855
856        // Reset update remain time
857        mUpdateRemainTime = 0;
858    }
859    //-----------------------------------------------------------------------
860    void ParticleSystem::setRenderer(const String& rendererName)
861    {
862                if (mRenderer)
863                {
864                        // Destroy existing
865                        destroyVisualParticles(0, mParticlePool.size());
866                        ParticleSystemManager::getSingleton()._destroyRenderer(mRenderer);
867                        mRenderer = 0;
868                }
869
870        if (!rendererName.empty())
871        {
872                        mRenderer = ParticleSystemManager::getSingleton()._createRenderer(rendererName);
873            mIsRendererConfigured = false;
874        }
875    }
876    //-----------------------------------------------------------------------
877    void ParticleSystem::configureRenderer(void)
878    {
879        // Actual allocate particles
880        size_t currSize = mParticlePool.size();
881        size_t size = mPoolSize;
882        if( currSize < size )
883        {
884            this->increasePool(size);
885
886            for( size_t i = currSize; i < size; ++i )
887            {
888                // Add new items to the queue
889                mFreeParticles.push_back( mParticlePool[i] );
890            }
891
892            // Tell the renderer, if already configured
893            if (mRenderer && mIsRendererConfigured)
894            {
895                mRenderer->_notifyParticleQuota(size);
896            }
897        }
898
899        if (mRenderer && !mIsRendererConfigured)
900        {
901            mRenderer->_notifyParticleQuota(mParticlePool.size());
902            if (mParentNode)
903                mRenderer->_notifyAttached(mParentNode, mParentIsTagPoint);
904            mRenderer->_notifyDefaultDimensions(mDefaultWidth, mDefaultHeight);
905            createVisualParticles(0, mParticlePool.size());
906            MaterialPtr mat = MaterialManager::getSingleton().load(
907                mMaterialName, mResourceGroupName);
908            mRenderer->_setMaterial(mat);
909                        if (mRenderQueueIDSet)
910                                mRenderer->setRenderQueueGroup(mRenderQueueID);
911                        mRenderer->setKeepParticlesInLocalSpace(mLocalSpace);
912            mIsRendererConfigured = true;
913        }
914    }
915    //-----------------------------------------------------------------------
916    ParticleSystemRenderer* ParticleSystem::getRenderer(void) const
917    {
918        return mRenderer;
919    }
920    //-----------------------------------------------------------------------
921    const String& ParticleSystem::getRendererName(void) const
922    {
923        if (mRenderer)
924        {
925            return mRenderer->getType();
926        }
927        else
928        {
929            return StringUtil::BLANK;
930        }
931    }
932    //-----------------------------------------------------------------------
933    bool ParticleSystem::getCullIndividually(void) const
934    {
935        return mCullIndividual;
936    }
937    //-----------------------------------------------------------------------
938    void ParticleSystem::setCullIndividually(bool cullIndividual)
939    {
940        mCullIndividual = cullIndividual;
941    }
942    //-----------------------------------------------------------------------
943        void ParticleSystem::createVisualParticles(size_t poolstart, size_t poolend)
944        {
945                ParticlePool::iterator i = mParticlePool.begin();
946                ParticlePool::iterator iend = mParticlePool.begin();
947                std::advance(i, poolstart);
948                std::advance(iend, poolend);
949                for (; i != iend; ++i)
950                {
951                        (*i)->_notifyVisualData(
952                                mRenderer->_createVisualData());
953                }
954        }
955    //-----------------------------------------------------------------------
956        void ParticleSystem::destroyVisualParticles(size_t poolstart, size_t poolend)
957        {
958                ParticlePool::iterator i = mParticlePool.begin();
959                ParticlePool::iterator iend = mParticlePool.begin();
960                std::advance(i, poolstart);
961                std::advance(iend, poolend);
962                for (; i != iend; ++i)
963                {
964                        mRenderer->_destroyVisualData((*i)->getVisualData());
965                        (*i)->_notifyVisualData(0);
966                }
967        }
968    //-----------------------------------------------------------------------
969    void ParticleSystem::setBounds(const AxisAlignedBox& aabb)
970    {
971        mAABB = aabb;
972        Real sqDist = std::max(mAABB.getMinimum().squaredLength(),
973            mAABB.getMaximum().squaredLength());
974        mBoundingRadius = Math::Sqrt(sqDist);
975
976    }
977    //-----------------------------------------------------------------------
978    void ParticleSystem::setBoundsAutoUpdated(bool autoUpdate, Real stopIn)
979    {
980        mBoundsAutoUpdate = autoUpdate;
981        mBoundsUpdateTime = stopIn;
982    }
983        //-----------------------------------------------------------------------
984        void ParticleSystem::setRenderQueueGroup(uint8 queueID)
985        {
986                MovableObject::setRenderQueueGroup(queueID);
987                if (mRenderer)
988                {
989                        mRenderer->setRenderQueueGroup(queueID);
990                }
991        }
992        //-----------------------------------------------------------------------
993        void ParticleSystem::setKeepParticlesInLocalSpace(bool keepLocal)
994        {
995                mLocalSpace = keepLocal;
996                if (mRenderer)
997                {
998                        mRenderer->setKeepParticlesInLocalSpace(keepLocal);
999                }
1000        }
1001    //-----------------------------------------------------------------------
1002    void ParticleSystem::_sortParticles(Camera* cam)
1003    {
1004        if (mRenderer)
1005        {
1006            SortMode sortMode = mRenderer->_getSortMode();
1007            if (sortMode == SM_DIRECTION)
1008            {
1009                Vector3 camDir = cam->getDerivedDirection();
1010                if (mLocalSpace)
1011                {
1012                    // transform the camera direction into local space
1013                    camDir = mParentNode->_getDerivedOrientation().UnitInverse() * camDir;
1014                }
1015                mRadixSorter.sort(mActiveParticles, SortByDirectionFunctor(- camDir));
1016            }
1017            else if (sortMode == SM_DISTANCE)
1018            {
1019                Vector3 camPos = cam->getDerivedPosition();
1020                if (mLocalSpace)
1021                {
1022                    // transform the camera position into local space
1023                    camPos = mParentNode->_getDerivedOrientation().UnitInverse() *
1024                        (camPos - mParentNode->_getDerivedPosition()) / mParentNode->_getDerivedScale();
1025                }
1026                mRadixSorter.sort(mActiveParticles, SortByDistanceFunctor(camPos));
1027            }
1028        }
1029    }
1030    ParticleSystem::SortByDirectionFunctor::SortByDirectionFunctor(const Vector3& dir)
1031        : sortDir(dir)
1032    {
1033    }
1034    float ParticleSystem::SortByDirectionFunctor::operator()(Particle* p) const
1035    {
1036        return sortDir.dotProduct(p->position);
1037    }
1038    ParticleSystem::SortByDistanceFunctor::SortByDistanceFunctor(const Vector3& pos)
1039        : sortPos(pos)
1040    {
1041    }
1042    float ParticleSystem::SortByDistanceFunctor::operator()(Particle* p) const
1043    {
1044        // Sort descending by squared distance
1045        return - (sortPos - p->position).squaredLength();
1046    }
1047        //-----------------------------------------------------------------------
1048        uint32 ParticleSystem::getTypeFlags(void) const
1049        {
1050                return SceneManager::FX_TYPE_MASK;
1051        }
1052    //-----------------------------------------------------------------------
1053    String ParticleSystem::CmdCull::doGet(const void* target) const
1054    {
1055        return StringConverter::toString(
1056            static_cast<const ParticleSystem*>(target)->getCullIndividually() );
1057    }
1058    void ParticleSystem::CmdCull::doSet(void* target, const String& val)
1059    {
1060        static_cast<ParticleSystem*>(target)->setCullIndividually(
1061            StringConverter::parseBool(val));
1062    }
1063    //-----------------------------------------------------------------------
1064    String ParticleSystem::CmdHeight::doGet(const void* target) const
1065    {
1066        return StringConverter::toString(
1067            static_cast<const ParticleSystem*>(target)->getDefaultHeight() );
1068    }
1069    void ParticleSystem::CmdHeight::doSet(void* target, const String& val)
1070    {
1071        static_cast<ParticleSystem*>(target)->setDefaultHeight(
1072            StringConverter::parseReal(val));
1073    }
1074    //-----------------------------------------------------------------------
1075    String ParticleSystem::CmdWidth::doGet(const void* target) const
1076    {
1077        return StringConverter::toString(
1078            static_cast<const ParticleSystem*>(target)->getDefaultWidth() );
1079    }
1080    void ParticleSystem::CmdWidth::doSet(void* target, const String& val)
1081    {
1082        static_cast<ParticleSystem*>(target)->setDefaultWidth(
1083            StringConverter::parseReal(val));
1084    }
1085    //-----------------------------------------------------------------------
1086    String ParticleSystem::CmdMaterial::doGet(const void* target) const
1087    {
1088        return static_cast<const ParticleSystem*>(target)->getMaterialName();
1089    }
1090    void ParticleSystem::CmdMaterial::doSet(void* target, const String& val)
1091    {
1092        static_cast<ParticleSystem*>(target)->setMaterialName(val);
1093    }
1094    //-----------------------------------------------------------------------
1095    String ParticleSystem::CmdQuota::doGet(const void* target) const
1096    {
1097        return StringConverter::toString(
1098            static_cast<const ParticleSystem*>(target)->getParticleQuota() );
1099    }
1100    void ParticleSystem::CmdQuota::doSet(void* target, const String& val)
1101    {
1102        static_cast<ParticleSystem*>(target)->setParticleQuota(
1103            StringConverter::parseUnsignedInt(val));
1104    }
1105    //-----------------------------------------------------------------------
1106    String ParticleSystem::CmdRenderer::doGet(const void* target) const
1107    {
1108        return static_cast<const ParticleSystem*>(target)->getRendererName();
1109    }
1110    void ParticleSystem::CmdRenderer::doSet(void* target, const String& val)
1111    {
1112        static_cast<ParticleSystem*>(target)->setRenderer(val);
1113    }
1114        //-----------------------------------------------------------------------
1115        String ParticleSystem::CmdSorted::doGet(const void* target) const
1116        {
1117                return StringConverter::toString(
1118                        static_cast<const ParticleSystem*>(target)->getSortingEnabled());
1119        }
1120        void ParticleSystem::CmdSorted::doSet(void* target, const String& val)
1121        {
1122                static_cast<ParticleSystem*>(target)->setSortingEnabled(
1123                        StringConverter::parseBool(val));
1124        }
1125        //-----------------------------------------------------------------------
1126        String ParticleSystem::CmdLocalSpace::doGet(const void* target) const
1127        {
1128                return StringConverter::toString(
1129                        static_cast<const ParticleSystem*>(target)->getKeepParticlesInLocalSpace());
1130        }
1131        void ParticleSystem::CmdLocalSpace::doSet(void* target, const String& val)
1132        {
1133                static_cast<ParticleSystem*>(target)->setKeepParticlesInLocalSpace(
1134                        StringConverter::parseBool(val));
1135        }
1136        //-----------------------------------------------------------------------
1137        String ParticleSystem::CmdIterationInterval::doGet(const void* target) const
1138        {
1139                return StringConverter::toString(
1140                        static_cast<const ParticleSystem*>(target)->getIterationInterval());
1141        }
1142        void ParticleSystem::CmdIterationInterval::doSet(void* target, const String& val)
1143        {
1144                static_cast<ParticleSystem*>(target)->setIterationInterval(
1145                        StringConverter::parseReal(val));
1146        }
1147        //-----------------------------------------------------------------------
1148        String ParticleSystem::CmdNonvisibleTimeout::doGet(const void* target) const
1149        {
1150                return StringConverter::toString(
1151                        static_cast<const ParticleSystem*>(target)->getNonVisibleUpdateTimeout());
1152        }
1153        void ParticleSystem::CmdNonvisibleTimeout::doSet(void* target, const String& val)
1154        {
1155                static_cast<ParticleSystem*>(target)->setNonVisibleUpdateTimeout(
1156                        StringConverter::parseReal(val));
1157        }
1158   //-----------------------------------------------------------------------
1159    ParticleAffector::~ParticleAffector()
1160    {
1161    }
1162    //-----------------------------------------------------------------------
1163    ParticleAffectorFactory::~ParticleAffectorFactory()
1164    {
1165        // Destroy all affectors
1166        std::vector<ParticleAffector*>::iterator i;
1167        for (i = mAffectors.begin(); i != mAffectors.end(); ++i)
1168        {
1169            delete (*i);
1170        }
1171           
1172        mAffectors.clear();
1173
1174    }
1175    //-----------------------------------------------------------------------
1176    void ParticleAffectorFactory::destroyAffector(ParticleAffector* e)
1177    {
1178        std::vector<ParticleAffector*>::iterator i;
1179        for (i = mAffectors.begin(); i != mAffectors.end(); ++i)
1180        {
1181            if ((*i) == e)
1182            {
1183                mAffectors.erase(i);
1184                delete e;
1185                break;
1186            }
1187        }
1188    }
1189
1190}
Note: See TracBrowser for help on using the repository browser.