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