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