source: OGRE/trunk/ogrenew/OgreMain/src/OgreParticleSystem.cpp @ 692

Revision 692, 42.3 KB checked in by mattausch, 19 years ago (diff)

adding ogre 1.2 and dependencies

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            if (pParticle->timeToLive < timeElapsed)
410            {
411                // Destroy this one
412                mFreeParticles.push_back( *i );
413                i = mActiveParticles.erase( i );
414            }
415            else
416            {
417                // Decrement TTL
418                pParticle->timeToLive -= timeElapsed;
419                                ++i;
420            }
421
422        }
423    }
424    //-----------------------------------------------------------------------
425    void ParticleSystem::_triggerEmitters(Real timeElapsed)
426    {
427        // Add up requests for emission
428        static std::vector<unsigned> requested;
429        if( requested.size() != mEmitters.size() )
430            requested.resize( mEmitters.size() );
431
432        size_t totalRequested, emitterCount, i, emissionAllowed;
433        ParticleEmitterList::iterator   itEmit, iEmitEnd;
434        ParticleAffectorList::iterator  itAff, itAffEnd;
435                           
436        iEmitEnd = mEmitters.end();
437        emitterCount = mEmitters.size();
438        emissionAllowed = mFreeParticles.size();
439        totalRequested = 0;
440
441        // Count up total requested emissions
442        for (itEmit = mEmitters.begin(), i = 0; itEmit != iEmitEnd; ++itEmit, ++i)
443        {
444            requested[i] = (*itEmit)->_getEmissionCount(timeElapsed);
445            totalRequested += requested[i];
446        }
447
448
449        // Check if the quota will be exceeded, if so reduce demand
450        if (totalRequested > emissionAllowed)
451        {
452            // Apportion down requested values to allotted values
453            Real ratio =  (Real)emissionAllowed / (Real)totalRequested;
454            for (i = 0; i < emitterCount; ++i)
455            {
456                requested[i] = static_cast<unsigned>(requested[i] * ratio);
457            }
458        }
459
460        // Emit
461                // For each emission, apply a subset of the motion for the frame
462                // this ensures an even distribution of particles when many are
463                // emitted in a single frame
464        for (itEmit = mEmitters.begin(), i = 0; itEmit != iEmitEnd; ++itEmit, ++i)
465        {
466                        Real timePoint = 0.0f;
467                        Real timeInc = timeElapsed / requested[i];
468                for (unsigned int j = 0; j < requested[i]; ++j)
469            {
470                // Create a new particle & init using emitter
471                Particle* p = createParticle();
472                (*itEmit)->_initParticle(p);
473
474                                // Translate position & direction into world space
475                                if (!mLocalSpace)
476                                {
477                                        p->position  =
478                                                (mParentNode->_getDerivedOrientation() *
479                         (mParentNode->_getDerivedScale() * p->position))
480                                                + mParentNode->_getDerivedPosition();
481                                        p->direction =
482                                                (mParentNode->_getDerivedOrientation() * p->direction);
483                                }
484
485                                // apply partial frame motion to this particle
486                p->position += (p->direction * timePoint);
487
488                                // apply particle initialization by the affectors
489                                itAffEnd = mAffectors.end();
490                                for (itAff = mAffectors.begin(); itAff != itAffEnd; ++itAff)
491                                        (*itAff)->_initParticle(p);
492
493                                // Increment time fragment
494                                timePoint += timeInc;
495            }
496        }
497
498
499    }
500    //-----------------------------------------------------------------------
501    void ParticleSystem::_applyMotion(Real timeElapsed)
502    {
503        ActiveParticleList::iterator i, itEnd;
504        Particle* pParticle;
505
506        itEnd = mActiveParticles.end();
507        for (i = mActiveParticles.begin(); i != itEnd; ++i)
508        {
509            pParticle = static_cast<Particle*>(*i);
510            pParticle->position += (pParticle->direction * timeElapsed);
511        }
512
513    }
514    //-----------------------------------------------------------------------
515    void ParticleSystem::_triggerAffectors(Real timeElapsed)
516    {
517        ParticleAffectorList::iterator i, itEnd;
518       
519        itEnd = mAffectors.end();
520        for (i = mAffectors.begin(); i != itEnd; ++i)
521        {
522            (*i)->_affectParticles(this, timeElapsed);
523        }
524
525    }
526    //-----------------------------------------------------------------------
527    void ParticleSystem::increasePool(size_t size)
528    {
529        size_t oldSize = mParticlePool.size();
530
531        // Increase size
532        mParticlePool.reserve(size);
533        mParticlePool.resize(size);
534
535        // Create new particles
536        for( size_t i = oldSize; i < size; i++ )
537                {
538            mParticlePool[i] = new Particle();
539                }
540
541                if (mIsRendererConfigured)
542                {
543                        createVisualParticles(oldSize, size);
544                }
545
546
547    }
548    //-----------------------------------------------------------------------
549    ParticleIterator ParticleSystem::_getIterator(void)
550    {
551        return ParticleIterator(mActiveParticles.begin(), mActiveParticles.end());
552    }
553    //-----------------------------------------------------------------------
554        Particle* ParticleSystem::getParticle(size_t index)
555        {
556                assert (index < mActiveParticles.size() && "Index out of bounds!");
557                ActiveParticleList::iterator i = mActiveParticles.begin();
558                std::advance(i, index);
559                return *i;
560        }
561    //-----------------------------------------------------------------------
562    Particle* ParticleSystem::createParticle(void)
563    {
564        // Fast creation (don't use superclass since emitter will init)
565        Particle* p = mFreeParticles.front();
566        mActiveParticles.splice(mActiveParticles.end(), mFreeParticles, mFreeParticles.begin());
567
568        p->_notifyOwner(this);
569
570        return p;
571
572    }
573    //-----------------------------------------------------------------------
574    void ParticleSystem::_updateRenderQueue(RenderQueue* queue)
575    {
576        if (mRenderer)
577        {
578            mRenderer->_updateRenderQueue(queue, mActiveParticles, mCullIndividual);
579        }
580    }
581    void ParticleSystem::initParameters(void)
582    {
583        if (createParamDictionary("ParticleSystem"))
584        {
585            ParamDictionary* dict = getParamDictionary();
586
587            dict->addParameter(ParameterDef("quota",
588                "The maximum number of particle allowed at once in this system.",
589                PT_UNSIGNED_INT),
590                &msQuotaCmd);
591
592            dict->addParameter(ParameterDef("material",
593                "The name of the material to be used to render all particles in this system.",
594                PT_STRING),
595                &msMaterialCmd);
596
597            dict->addParameter(ParameterDef("particle_width",
598                "The width of particles in world units.",
599                PT_REAL),
600                &msWidthCmd);
601
602            dict->addParameter(ParameterDef("particle_height",
603                "The height of particles in world units.",
604                PT_REAL),
605                &msHeightCmd);
606
607            dict->addParameter(ParameterDef("cull_each",
608                "If true, each particle is culled in it's own right. If false, the entire system is culled as a whole.",
609                PT_BOOL),
610                &msCullCmd);
611
612                        dict->addParameter(ParameterDef("renderer",
613                                "Sets the particle system renderer to use (default 'billboard').",
614                                PT_STRING),
615                                &msRendererCmd);
616
617                        dict->addParameter(ParameterDef("sorted",
618                                "Sets whether particles should be sorted relative to the camera. ",
619                                PT_BOOL),
620                                &msSortedCmd);
621
622                        dict->addParameter(ParameterDef("local_space",
623                                "Sets whether particles should be kept in local space rather than "
624                                "emitted into world space. ",
625                                PT_BOOL),
626                                &msLocalSpaceCmd);
627
628                        dict->addParameter(ParameterDef("iteration_interval",
629                                "Sets a fixed update interval for the system, or 0 for the frame rate. ",
630                                PT_REAL),
631                                &msIterationIntervalCmd);
632
633                        dict->addParameter(ParameterDef("nonvisible_update_timeout",
634                                "Sets a timeout on updates to the system if the system is not visible "
635                                "for the given number of seconds (0 to always update)",
636                                PT_REAL),
637                                &msNonvisibleTimeoutCmd);
638
639        }
640    }
641    //-----------------------------------------------------------------------
642    void ParticleSystem::_updateBounds()
643    {
644
645        if (mParentNode && (mBoundsAutoUpdate || mBoundsUpdateTime > 0.0f))
646        {
647
648            Vector3 min; 
649            Vector3 max;
650            if (!mBoundsAutoUpdate)
651            {
652                // We're on a limit, grow rather than reset each time
653                // so that we pick up the worst case scenario
654                min = mWorldAABB.getMinimum();
655                max = mWorldAABB.getMaximum();
656            }
657            else
658            {
659                min.x = min.y = min.z = Math::POS_INFINITY;
660                max.x = max.y = max.z = Math::NEG_INFINITY;
661            }
662            ActiveParticleList::iterator p;
663            Vector3 halfScale = Vector3::UNIT_SCALE * 0.5;
664            Vector3 defaultPadding =
665                halfScale * std::max(mDefaultHeight, mDefaultWidth);
666            for (p = mActiveParticles.begin(); p != mActiveParticles.end(); ++p)
667            {
668
669                if ((*p)->mOwnDimensions)
670                {
671                    Vector3 padding =
672                        halfScale * std::max((*p)->mWidth, (*p)->mHeight);
673                    min.makeFloor((*p)->position - padding);
674                    max.makeCeil((*p)->position + padding);
675                }
676                else
677                {
678                    min.makeFloor((*p)->position - defaultPadding);
679                    max.makeCeil((*p)->position + defaultPadding);
680                }
681            }
682            mWorldAABB.setExtents(min, max);
683
684
685            if (mLocalSpace)
686            {
687                // Merge calculated box with current AABB to preserve any user-set AABB
688                mAABB.merge(mWorldAABB);
689            }
690            else
691            {
692                // We've already put particles in world space to decouple them from the
693                // node transform, so reverse transform back since we're expected to
694                // provide a local AABB
695                AxisAlignedBox newAABB(mWorldAABB);
696                newAABB.transform(mParentNode->_getFullTransform().inverse());
697
698                // Merge calculated box with current AABB to preserve any user-set AABB
699                mAABB.merge(newAABB);
700            }
701
702            mParentNode->needUpdate();
703        }
704    }
705    //-----------------------------------------------------------------------
706    void ParticleSystem::fastForward(Real time, Real interval)
707    {
708        // First make sure all transforms are up to date
709
710        for (Real ftime = 0; ftime < time; ftime += interval)
711        {
712            _update(interval);
713        }
714    }
715    //-----------------------------------------------------------------------
716    const String& ParticleSystem::getMovableType(void) const
717    {
718        return ParticleSystemFactory::FACTORY_TYPE_NAME;
719    }
720    //-----------------------------------------------------------------------
721    void ParticleSystem::_notifyParticleResized(void)
722    {
723        if (mRenderer)
724        {
725            mRenderer->_notifyParticleResized();
726        }
727    }
728    //-----------------------------------------------------------------------
729    void ParticleSystem::_notifyParticleRotated(void)
730    {
731        if (mRenderer)
732        {
733            mRenderer->_notifyParticleRotated();
734        }
735    }
736    //-----------------------------------------------------------------------
737    void ParticleSystem::setDefaultDimensions( Real width, Real height )
738    {
739        mDefaultWidth = width;
740        mDefaultHeight = height;
741        if (mRenderer)
742        {
743            mRenderer->_notifyDefaultDimensions(width, height);
744        }
745    }
746    //-----------------------------------------------------------------------
747    void ParticleSystem::setDefaultWidth(Real width)
748    {
749        mDefaultWidth = width;
750        if (mRenderer)
751        {
752            mRenderer->_notifyDefaultDimensions(mDefaultWidth, mDefaultHeight);
753        }
754    }
755    //-----------------------------------------------------------------------
756    Real ParticleSystem::getDefaultWidth(void) const
757    {
758        return mDefaultWidth;
759    }
760    //-----------------------------------------------------------------------
761    void ParticleSystem::setDefaultHeight(Real height)
762    {
763        mDefaultHeight = height;
764        if (mRenderer)
765        {
766            mRenderer->_notifyDefaultDimensions(mDefaultWidth, mDefaultHeight);
767        }
768    }
769    //-----------------------------------------------------------------------
770    Real ParticleSystem::getDefaultHeight(void) const
771    {
772        return mDefaultHeight;
773    }
774    //-----------------------------------------------------------------------
775    void ParticleSystem::_notifyCurrentCamera(Camera* cam)
776    {
777                MovableObject::_notifyCurrentCamera(cam);
778
779                // Record visible
780                mLastVisibleFrame = Root::getSingleton().getCurrentFrameNumber();
781                mTimeSinceLastVisible = 0.0f;
782
783        if (mSorted)
784                {
785                        _sortParticles(cam);
786                }
787
788                if (mRenderer)
789        {
790                        if (!mIsRendererConfigured)
791                                configureRenderer();
792
793            mRenderer->_notifyCurrentCamera(cam);
794        }
795    }
796    //-----------------------------------------------------------------------
797    void ParticleSystem::_notifyAttached(Node* parent, bool isTagPoint)
798    {
799        MovableObject::_notifyAttached(parent, isTagPoint);
800        if (mRenderer)
801        {
802            mRenderer->_notifyAttached(parent, isTagPoint);
803        }
804
805        if (parent && !mTimeController)
806        {
807            // Assume visible
808            mTimeSinceLastVisible = 0;
809            mLastVisibleFrame = Root::getSingleton().getCurrentFrameNumber();
810
811            // Create time controller when attached
812            ControllerManager& mgr = ControllerManager::getSingleton();
813            ControllerValueRealPtr updValue(new ParticleSystemUpdateValue(this));
814            mTimeController = mgr.createFrameTimePassthroughController(updValue);
815        }
816        else if (!parent && mTimeController)
817        {
818            // Destroy controller
819            ControllerManager::getSingleton().destroyController(mTimeController);
820            mTimeController = 0;
821        }
822    }
823    //-----------------------------------------------------------------------
824    void ParticleSystem::setMaterialName(const String& name)
825    {
826        mMaterialName = name;
827        if (mIsRendererConfigured)
828        {
829            MaterialPtr mat = MaterialManager::getSingleton().load(
830                mMaterialName, mResourceGroupName);
831            mRenderer->_setMaterial(mat);
832        }
833    }
834    //-----------------------------------------------------------------------
835    const String& ParticleSystem::getMaterialName(void) const
836    {
837        return mMaterialName;
838    }
839    //-----------------------------------------------------------------------
840    void ParticleSystem::clear()
841    {
842        // Insert actives into free list
843        mFreeParticles.insert(mFreeParticles.end(), mActiveParticles.begin(), mActiveParticles.end());
844
845        // Remove all active instances
846        mActiveParticles.clear();
847
848        // Reset update remain time
849        mUpdateRemainTime = 0;
850    }
851    //-----------------------------------------------------------------------
852    void ParticleSystem::setRenderer(const String& rendererName)
853    {
854                if (mRenderer)
855                {
856                        // Destroy existing
857                        destroyVisualParticles(0, mParticlePool.size());
858                        ParticleSystemManager::getSingleton()._destroyRenderer(mRenderer);
859                        mRenderer = 0;
860                }
861
862        if (!rendererName.empty())
863        {
864                        mRenderer = ParticleSystemManager::getSingleton()._createRenderer(rendererName);
865            mIsRendererConfigured = false;
866        }
867    }
868    //-----------------------------------------------------------------------
869    void ParticleSystem::configureRenderer(void)
870    {
871        // Actual allocate particles
872        size_t currSize = mParticlePool.size();
873        size_t size = mPoolSize;
874        if( currSize < size )
875        {
876            this->increasePool(size);
877
878            for( size_t i = currSize; i < size; ++i )
879            {
880                // Add new items to the queue
881                mFreeParticles.push_back( mParticlePool[i] );
882            }
883
884            // Tell the renderer, if already configured
885            if (mRenderer && mIsRendererConfigured)
886            {
887                mRenderer->_notifyParticleQuota(size);
888            }
889        }
890
891        if (mRenderer && !mIsRendererConfigured)
892        {
893            mRenderer->_notifyParticleQuota(mParticlePool.size());
894            if (mParentNode)
895                mRenderer->_notifyAttached(mParentNode, mParentIsTagPoint);
896            mRenderer->_notifyDefaultDimensions(mDefaultWidth, mDefaultHeight);
897            createVisualParticles(0, mParticlePool.size());
898            MaterialPtr mat = MaterialManager::getSingleton().load(
899                mMaterialName, mResourceGroupName);
900            mRenderer->_setMaterial(mat);
901                        if (mRenderQueueIDSet)
902                                mRenderer->setRenderQueueGroup(mRenderQueueID);
903                        mRenderer->setKeepParticlesInLocalSpace(mLocalSpace);
904            mIsRendererConfigured = true;
905        }
906    }
907    //-----------------------------------------------------------------------
908    ParticleSystemRenderer* ParticleSystem::getRenderer(void) const
909    {
910        return mRenderer;
911    }
912    //-----------------------------------------------------------------------
913    const String& ParticleSystem::getRendererName(void) const
914    {
915        if (mRenderer)
916        {
917            return mRenderer->getType();
918        }
919        else
920        {
921            return StringUtil::BLANK;
922        }
923    }
924    //-----------------------------------------------------------------------
925    bool ParticleSystem::getCullIndividually(void) const
926    {
927        return mCullIndividual;
928    }
929    //-----------------------------------------------------------------------
930    void ParticleSystem::setCullIndividually(bool cullIndividual)
931    {
932        mCullIndividual = cullIndividual;
933    }
934    //-----------------------------------------------------------------------
935        void ParticleSystem::createVisualParticles(size_t poolstart, size_t poolend)
936        {
937                ParticlePool::iterator i = mParticlePool.begin();
938                ParticlePool::iterator iend = mParticlePool.begin();
939                std::advance(i, poolstart);
940                std::advance(iend, poolend);
941                for (; i != iend; ++i)
942                {
943                        (*i)->_notifyVisualData(
944                                mRenderer->_createVisualData());
945                }
946        }
947    //-----------------------------------------------------------------------
948        void ParticleSystem::destroyVisualParticles(size_t poolstart, size_t poolend)
949        {
950                ParticlePool::iterator i = mParticlePool.begin();
951                ParticlePool::iterator iend = mParticlePool.begin();
952                std::advance(i, poolstart);
953                std::advance(iend, poolend);
954                for (; i != iend; ++i)
955                {
956                        mRenderer->_destroyVisualData((*i)->getVisualData());
957                        (*i)->_notifyVisualData(0);
958                }
959        }
960    //-----------------------------------------------------------------------
961    void ParticleSystem::setBounds(const AxisAlignedBox& aabb)
962    {
963        mAABB = aabb;
964        Real sqDist = std::max(mAABB.getMinimum().squaredLength(),
965            mAABB.getMaximum().squaredLength());
966        mBoundingRadius = Math::Sqrt(sqDist);
967
968    }
969    //-----------------------------------------------------------------------
970    void ParticleSystem::setBoundsAutoUpdated(bool autoUpdate, Real stopIn)
971    {
972        mBoundsAutoUpdate = autoUpdate;
973        mBoundsUpdateTime = stopIn;
974    }
975        //-----------------------------------------------------------------------
976        void ParticleSystem::setRenderQueueGroup(uint8 queueID)
977        {
978                MovableObject::setRenderQueueGroup(queueID);
979                if (mRenderer)
980                {
981                        mRenderer->setRenderQueueGroup(queueID);
982                }
983        }
984        //-----------------------------------------------------------------------
985        void ParticleSystem::setKeepParticlesInLocalSpace(bool keepLocal)
986        {
987                mLocalSpace = keepLocal;
988                if (mRenderer)
989                {
990                        mRenderer->setKeepParticlesInLocalSpace(keepLocal);
991                }
992        }
993    //-----------------------------------------------------------------------
994    void ParticleSystem::_sortParticles(Camera* cam)
995    {
996        if (mRenderer)
997        {
998            SortMode sortMode = mRenderer->_getSortMode();
999            if (sortMode == SM_DIRECTION)
1000            {
1001                Vector3 camDir = cam->getDerivedDirection();
1002                if (mLocalSpace)
1003                {
1004                    // transform the camera direction into local space
1005                    camDir = mParentNode->_getDerivedOrientation().UnitInverse() * camDir;
1006                }
1007                mRadixSorter.sort(mActiveParticles, SortByDirectionFunctor(- camDir));
1008            }
1009            else if (sortMode == SM_DISTANCE)
1010            {
1011                Vector3 camPos = cam->getDerivedPosition();
1012                if (mLocalSpace)
1013                {
1014                    // transform the camera position into local space
1015                    camPos = mParentNode->_getDerivedOrientation().UnitInverse() *
1016                        (camPos - mParentNode->_getDerivedPosition()) / mParentNode->_getDerivedScale();
1017                }
1018                mRadixSorter.sort(mActiveParticles, SortByDistanceFunctor(camPos));
1019            }
1020        }
1021    }
1022    ParticleSystem::SortByDirectionFunctor::SortByDirectionFunctor(const Vector3& dir)
1023        : sortDir(dir)
1024    {
1025    }
1026    float ParticleSystem::SortByDirectionFunctor::operator()(Particle* p) const
1027    {
1028        return sortDir.dotProduct(p->position);
1029    }
1030    ParticleSystem::SortByDistanceFunctor::SortByDistanceFunctor(const Vector3& pos)
1031        : sortPos(pos)
1032    {
1033    }
1034    float ParticleSystem::SortByDistanceFunctor::operator()(Particle* p) const
1035    {
1036        // Sort descending by squared distance
1037        return - (sortPos - p->position).squaredLength();
1038    }
1039        //-----------------------------------------------------------------------
1040        uint32 ParticleSystem::getTypeFlags(void) const
1041        {
1042                return SceneManager::FX_TYPE_MASK;
1043        }
1044    //-----------------------------------------------------------------------
1045    String ParticleSystem::CmdCull::doGet(const void* target) const
1046    {
1047        return StringConverter::toString(
1048            static_cast<const ParticleSystem*>(target)->getCullIndividually() );
1049    }
1050    void ParticleSystem::CmdCull::doSet(void* target, const String& val)
1051    {
1052        static_cast<ParticleSystem*>(target)->setCullIndividually(
1053            StringConverter::parseBool(val));
1054    }
1055    //-----------------------------------------------------------------------
1056    String ParticleSystem::CmdHeight::doGet(const void* target) const
1057    {
1058        return StringConverter::toString(
1059            static_cast<const ParticleSystem*>(target)->getDefaultHeight() );
1060    }
1061    void ParticleSystem::CmdHeight::doSet(void* target, const String& val)
1062    {
1063        static_cast<ParticleSystem*>(target)->setDefaultHeight(
1064            StringConverter::parseReal(val));
1065    }
1066    //-----------------------------------------------------------------------
1067    String ParticleSystem::CmdWidth::doGet(const void* target) const
1068    {
1069        return StringConverter::toString(
1070            static_cast<const ParticleSystem*>(target)->getDefaultWidth() );
1071    }
1072    void ParticleSystem::CmdWidth::doSet(void* target, const String& val)
1073    {
1074        static_cast<ParticleSystem*>(target)->setDefaultWidth(
1075            StringConverter::parseReal(val));
1076    }
1077    //-----------------------------------------------------------------------
1078    String ParticleSystem::CmdMaterial::doGet(const void* target) const
1079    {
1080        return static_cast<const ParticleSystem*>(target)->getMaterialName();
1081    }
1082    void ParticleSystem::CmdMaterial::doSet(void* target, const String& val)
1083    {
1084        static_cast<ParticleSystem*>(target)->setMaterialName(val);
1085    }
1086    //-----------------------------------------------------------------------
1087    String ParticleSystem::CmdQuota::doGet(const void* target) const
1088    {
1089        return StringConverter::toString(
1090            static_cast<const ParticleSystem*>(target)->getParticleQuota() );
1091    }
1092    void ParticleSystem::CmdQuota::doSet(void* target, const String& val)
1093    {
1094        static_cast<ParticleSystem*>(target)->setParticleQuota(
1095            StringConverter::parseUnsignedInt(val));
1096    }
1097    //-----------------------------------------------------------------------
1098    String ParticleSystem::CmdRenderer::doGet(const void* target) const
1099    {
1100        return static_cast<const ParticleSystem*>(target)->getRendererName();
1101    }
1102    void ParticleSystem::CmdRenderer::doSet(void* target, const String& val)
1103    {
1104        static_cast<ParticleSystem*>(target)->setRenderer(val);
1105    }
1106        //-----------------------------------------------------------------------
1107        String ParticleSystem::CmdSorted::doGet(const void* target) const
1108        {
1109                return StringConverter::toString(
1110                        static_cast<const ParticleSystem*>(target)->getSortingEnabled());
1111        }
1112        void ParticleSystem::CmdSorted::doSet(void* target, const String& val)
1113        {
1114                static_cast<ParticleSystem*>(target)->setSortingEnabled(
1115                        StringConverter::parseBool(val));
1116        }
1117        //-----------------------------------------------------------------------
1118        String ParticleSystem::CmdLocalSpace::doGet(const void* target) const
1119        {
1120                return StringConverter::toString(
1121                        static_cast<const ParticleSystem*>(target)->getKeepParticlesInLocalSpace());
1122        }
1123        void ParticleSystem::CmdLocalSpace::doSet(void* target, const String& val)
1124        {
1125                static_cast<ParticleSystem*>(target)->setKeepParticlesInLocalSpace(
1126                        StringConverter::parseBool(val));
1127        }
1128        //-----------------------------------------------------------------------
1129        String ParticleSystem::CmdIterationInterval::doGet(const void* target) const
1130        {
1131                return StringConverter::toString(
1132                        static_cast<const ParticleSystem*>(target)->getIterationInterval());
1133        }
1134        void ParticleSystem::CmdIterationInterval::doSet(void* target, const String& val)
1135        {
1136                static_cast<ParticleSystem*>(target)->setIterationInterval(
1137                        StringConverter::parseReal(val));
1138        }
1139        //-----------------------------------------------------------------------
1140        String ParticleSystem::CmdNonvisibleTimeout::doGet(const void* target) const
1141        {
1142                return StringConverter::toString(
1143                        static_cast<const ParticleSystem*>(target)->getNonVisibleUpdateTimeout());
1144        }
1145        void ParticleSystem::CmdNonvisibleTimeout::doSet(void* target, const String& val)
1146        {
1147                static_cast<ParticleSystem*>(target)->setNonVisibleUpdateTimeout(
1148                        StringConverter::parseReal(val));
1149        }
1150   //-----------------------------------------------------------------------
1151    ParticleAffector::~ParticleAffector()
1152    {
1153    }
1154    //-----------------------------------------------------------------------
1155    ParticleAffectorFactory::~ParticleAffectorFactory()
1156    {
1157        // Destroy all affectors
1158        std::vector<ParticleAffector*>::iterator i;
1159        for (i = mAffectors.begin(); i != mAffectors.end(); ++i)
1160        {
1161            delete (*i);
1162        }
1163           
1164        mAffectors.clear();
1165
1166    }
1167    //-----------------------------------------------------------------------
1168    void ParticleAffectorFactory::destroyAffector(ParticleAffector* e)
1169    {
1170        std::vector<ParticleAffector*>::iterator i;
1171        for (i = mAffectors.begin(); i != mAffectors.end(); ++i)
1172        {
1173            if ((*i) == e)
1174            {
1175                mAffectors.erase(i);
1176                delete e;
1177                break;
1178            }
1179        }
1180    }
1181
1182}
Note: See TracBrowser for help on using the repository browser.