00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include <stdlib.h>
00029 #include "3d/ps_emitter.h"
00030 #include "3d/material.h"
00031 #include "nel/misc/line.h"
00032 #include "3d/dru.h"
00033 #include "3d/particle_system.h"
00034
00035 namespace NL3D {
00036
00037
00038
00039
00040 const uint emitterBuffSize = 512;
00041
00043
00045
00046 _SpeedInheritanceFactor(0.f),
00047 _EmissionType(regular),
00048 _Period(0.02f),
00049 _PeriodScheme(NULL),
00050 _GenNb(1),
00051 _GenNbScheme(NULL),
00052 _EmitDelay(0),
00053 _MaxEmissionCount(0),
00054 _SpeedBasisEmission(false),
00055 _EmitDirBasis(true),
00056 _ConsistentEmission(true)
00057 {
00058 }
00059
00060
00062 CPSEmitter::~CPSEmitter()
00063 {
00064 delete _PeriodScheme;
00065 delete _GenNbScheme;
00066
00067 if (_EmittedType)
00068 {
00069 _EmittedType->unregisterDtorObserver(this);
00070 }
00071 }
00072
00074 void CPSEmitter::releaseRefTo(const CParticleSystemProcess *other)
00075 {
00076 if (_EmittedType == other)
00077 {
00078 setEmittedType(NULL);
00079 }
00080 }
00081
00082 void CPSEmitter::releaseAllRef()
00083 {
00084 setEmittedType(NULL);
00085 }
00086
00087
00089 inline void CPSEmitter::processEmit(uint32 index, sint nbToGenerate)
00090 {
00091 static NLMISC::CVector speed, pos;
00092
00093 if (!_SpeedBasisEmission)
00094 {
00095 if (_SpeedInheritanceFactor == 0.f)
00096 {
00097 if (_EmitDirBasis)
00098 {
00099 while (nbToGenerate > 0)
00100 {
00101 nbToGenerate --;
00102 emit(_Owner->getPos()[index], index, pos, speed);
00103 _EmittedType->newElement(pos, speed, this->_Owner, index);
00104 }
00105 }
00106 else
00107 {
00108 while (nbToGenerate > 0)
00109 {
00110 nbToGenerate --;
00111 emit(_Owner->getPos()[index], index, pos, speed);
00112 _EmittedType->newElement(pos, speed, this->_Owner, index, false);
00113 }
00114 }
00115 }
00116 else
00117 {
00118 while (nbToGenerate --)
00119 {
00120 emit(_Owner->getPos()[index], index, pos, speed);
00121 _EmittedType->newElement(pos, speed + _SpeedInheritanceFactor * _Owner->getSpeed()[index], this->_Owner);
00122 }
00123 }
00124 }
00125 else
00126 {
00127 NLMISC::CMatrix m;
00128 CPSUtil::buildSchmidtBasis(_Owner->getSpeed()[index], m);
00129 if (_SpeedInheritanceFactor == 0.f)
00130 {
00131 while (nbToGenerate > 0)
00132 {
00133 nbToGenerate --;
00134 emit(_Owner->getPos()[index], index, pos, speed);
00135 _EmittedType->newElement(pos, m * speed, this->_Owner, index);
00136 }
00137 }
00138 else
00139 {
00140 while (nbToGenerate --)
00141 {
00142 emit(_Owner->getPos()[index], index, pos, speed);
00143 _EmittedType->newElement(pos, m * speed + _SpeedInheritanceFactor * _Owner->getSpeed()[index], this->_Owner, index);
00144 }
00145 }
00146 }
00147 }
00148
00152 static inline void CompensateEmission(CPSLocated *emittedType, uint emittedIndex, TAnimationTime deltaT, TAnimationTime ellapsedTime, float realEllapsedTimeRatio)
00153 {
00154
00155 if (emittedType->getLastForever())
00156 {
00157 emittedType->getTime()[emittedIndex] += realEllapsedTimeRatio * deltaT;
00158
00159 if (emittedType->isParametricMotionEnabled())
00160 {
00161 emittedType->getParametricInfos()[emittedIndex].Date -= realEllapsedTimeRatio * deltaT;
00162 }
00163 else
00164 {
00165 if (!emittedType->hasCollisionInfos())
00166 {
00167
00168 emittedType->getPos()[emittedIndex] += deltaT * emittedType->getSpeed()[emittedIndex];
00169 }
00170 else
00171 {
00172 emittedType->getCollisionInfo()[emittedIndex].TimeSliceRatio = deltaT / ellapsedTime;
00173 }
00174 }
00175 }
00176 else
00177 {
00178 TAnimationTime &destTime = emittedType->getTime()[emittedIndex];
00179 if (emittedType->getLifeScheme() != NULL)
00180 {
00181 destTime = realEllapsedTimeRatio * deltaT * emittedType->getTimeIncrement()[emittedIndex];
00182 }
00183 else
00184 {
00185 if (emittedType->getInitialLife() != 0.f)
00186 {
00187 destTime = realEllapsedTimeRatio * deltaT / emittedType->getInitialLife();
00188 }
00189 }
00190 if (destTime >= 1.f)
00191 {
00192 emittedType->deleteElement(emittedIndex);
00193 }
00194 else
00195 {
00196 if (emittedType->isParametricMotionEnabled())
00197 {
00198 emittedType->getParametricInfos()[emittedIndex].Date -= realEllapsedTimeRatio * deltaT;
00199 }
00200 else
00201 {
00202 if (!emittedType->hasCollisionInfos())
00203 {
00204
00205 emittedType->getPos()[emittedIndex] += deltaT * emittedType->getSpeed()[emittedIndex];
00206 }
00207 else
00208 {
00209 emittedType->getCollisionInfo()[emittedIndex].TimeSliceRatio = deltaT / ellapsedTime;
00210 }
00211 }
00212 }
00213 }
00214 }
00215
00217 inline void CPSEmitter::processEmitConsistent(const NLMISC::CVector &emitterPos,
00218 uint32 index,
00219 sint nbToGenerate,
00220 TAnimationTime deltaT,
00221 TAnimationTime ellapsedTime,
00222 float realEllapsedTimeRatio
00223 )
00224 {
00225 static NLMISC::CVector speed, pos;
00226 sint emittedIndex;
00227 if (!_SpeedBasisEmission)
00228 {
00229 if (_SpeedInheritanceFactor == 0.f)
00230 {
00231 if (_EmitDirBasis)
00232 {
00233 while (nbToGenerate > 0)
00234 {
00235 nbToGenerate --;
00236 emit(emitterPos, index, pos, speed);
00237 emittedIndex = _EmittedType->newElement(pos, speed, this->_Owner, index, true, deltaT);
00238 if (emittedIndex != - 1) CompensateEmission(_EmittedType, emittedIndex, deltaT, ellapsedTime, realEllapsedTimeRatio);
00239 else break;
00240 }
00241 }
00242 else
00243 {
00244 while (nbToGenerate > 0)
00245 {
00246 nbToGenerate --;
00247 emit(emitterPos, index, pos, speed);
00248 emittedIndex = _EmittedType->newElement(pos, speed, this->_Owner, index, false, deltaT);
00249 if (emittedIndex != - 1) CompensateEmission(_EmittedType, emittedIndex, deltaT, ellapsedTime, realEllapsedTimeRatio);
00250 else break;
00251 }
00252 }
00253 }
00254 else
00255 {
00256 while (nbToGenerate --)
00257 {
00258 emit(emitterPos, index, pos, speed);
00259 emittedIndex = _EmittedType->newElement(pos, speed + _SpeedInheritanceFactor * _Owner->getSpeed()[index], this->_Owner, index, true, deltaT);
00260 if (emittedIndex != - 1) CompensateEmission(_EmittedType, emittedIndex, deltaT, ellapsedTime, realEllapsedTimeRatio);
00261 else break;
00262 }
00263 }
00264 }
00265 else
00266 {
00267 NLMISC::CMatrix m;
00268 CPSUtil::buildSchmidtBasis(_Owner->getSpeed()[index], m);
00269 if (_SpeedInheritanceFactor == 0.f)
00270 {
00271 while (nbToGenerate > 0)
00272 {
00273 nbToGenerate --;
00274 emit(emitterPos, index, pos, speed);
00275 emittedIndex = _EmittedType->newElement(pos, m * speed, this->_Owner, index, true, deltaT);
00276 if (emittedIndex != - 1) CompensateEmission(_EmittedType, emittedIndex, deltaT, ellapsedTime, realEllapsedTimeRatio);
00277 else break;
00278 }
00279 }
00280 else
00281 {
00282 while (nbToGenerate --)
00283 {
00284 emit(emitterPos, index, pos, speed);
00285 emittedIndex = _EmittedType->newElement(pos, m * speed + _SpeedInheritanceFactor * _Owner->getSpeed()[index], this->_Owner, index, true, deltaT);
00286 if (emittedIndex != - 1) CompensateEmission(_EmittedType, emittedIndex, deltaT, ellapsedTime, realEllapsedTimeRatio);
00287 else break;
00288 }
00289 }
00290 }
00291 }
00292
00293
00295 void CPSEmitter::setEmissionType(TEmissionType freqType)
00296 {
00297 _EmissionType = freqType;
00298 }
00299
00301 void CPSEmitter::setEmittedType(CPSLocated *et)
00302 {
00303 if (_EmittedType)
00304 {
00305 _EmittedType->unregisterDtorObserver(this);
00306 }
00307 if (et)
00308 {
00309 et->registerDtorObserver(this);
00310 }
00311
00312 _EmittedType = et;
00313 }
00314
00316 void CPSEmitter::notifyTargetRemoved(CPSLocated *ptr)
00317 {
00318 nlassert(ptr == _EmittedType && _EmittedType);
00319 setEmittedType(NULL);
00320 }
00321
00323 void CPSEmitter::setPeriod(float period)
00324 {
00325 if (_PeriodScheme)
00326 {
00327 delete _PeriodScheme;
00328 _PeriodScheme = NULL;
00329 }
00330 _Period = period;
00331 }
00332
00334 void CPSEmitter::setPeriodScheme(CPSAttribMaker<float> *scheme)
00335 {
00336 delete _PeriodScheme;
00337 _PeriodScheme = scheme;
00338 if (_Owner && scheme->hasMemory()) scheme->resize(_Owner->getMaxSize(), _Owner->getSize());
00339 }
00340
00342 void CPSEmitter::setGenNb(uint32 genNb)
00343 {
00344 if (_GenNbScheme)
00345 {
00346 delete _GenNbScheme;
00347 _GenNbScheme = NULL;
00348 }
00349 _GenNb = genNb;
00350 }
00351
00353 void CPSEmitter::setGenNbScheme(CPSAttribMaker<uint32> *scheme)
00354 {
00355 delete _GenNbScheme;
00356 _GenNbScheme = scheme;
00357 if (_Owner && scheme->hasMemory()) scheme->resize(_Owner->getMaxSize(), _Owner->getSize());
00358 }
00359
00361 void CPSEmitter::showTool(void)
00362 {
00363 uint32 size = _Owner->getSize();
00364 if (!size) return;
00365 setupDriverModelMatrix();
00366
00367 const CVector I = computeI();
00368 const CVector K = computeK();
00369
00370
00371 for (uint k = 0; k < size; ++k)
00372 {
00373
00374 const CVector p = _Owner->getPos()[k];
00375 const float sSize =0.1f;
00376 std::vector<NLMISC::CLine> lines;
00377 NLMISC::CLine l;
00378 l.V0 = p - sSize * I; l.V1 = p + sSize * I; lines.push_back(l);
00379 l.V0 = p - sSize * K; l.V1 = p + sSize * K; lines.push_back(l);
00380 l.V0 = p - sSize * (I + K); l.V1 = p + sSize * (I + K); lines.push_back(l);
00381 l.V0 = p - sSize * (I - K); l.V1 = p + sSize * (I - K); lines.push_back(l);
00382
00383 CMaterial mat;
00384 mat.setBlendFunc(CMaterial::one, CMaterial::one);
00385 mat.setZWrite(false);
00386 mat.setLighting(false);
00387 mat.setBlend(true);
00388 mat.setZFunc(CMaterial::less);
00389
00390
00391 CPSLocated *loc;
00392 uint32 index;
00393 CPSLocatedBindable *lb;
00394 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00395
00396 mat.setColor((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
00397
00398
00399 CDRU::drawLinesUnlit(lines, mat, *getDriver() );
00400 }
00401 }
00402
00404 void CPSEmitter::singleEmit(uint32 index, uint quantity)
00405 {
00406 nlassert(_Owner);
00407 const uint32 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner,0) : _GenNb;
00408 processEmit(index, quantity * nbToGenerate);
00409 }
00410
00411
00413 void CPSEmitter::processRegularEmission(TAnimationTime ellapsedTime)
00414 {
00415 nlassert(_Owner);
00416 const uint size = _Owner->getSize();
00417 uint leftToDo = size, toProcess;
00418 float emitPeriod[emitterBuffSize];
00419 float *currEmitPeriod;
00420 uint currEmitPeriodPtrInc = _PeriodScheme ? 1 : 0;
00421 sint32 nbToGenerate;
00422
00423 TPSAttribTime::iterator phaseIt = _Phase.begin(), endPhaseIt;
00424 TPSAttribUInt8::iterator numEmitIt = _NumEmission.begin();
00425
00426
00427
00428 do
00429 {
00430 toProcess = leftToDo < emitterBuffSize ? leftToDo : emitterBuffSize;
00431
00432
00433 if (_PeriodScheme)
00434 {
00435 currEmitPeriod = (float *) (_PeriodScheme->make(_Owner, size - leftToDo, emitPeriod, sizeof(float), toProcess, true));
00436 }
00437 else
00438 {
00439 currEmitPeriod = &_Period;
00440 }
00441
00442 endPhaseIt = phaseIt + toProcess;
00443
00444 if (_MaxEmissionCount == 0)
00445 {
00447 if (_EmitDelay == 0.f)
00448 {
00449 do
00450 {
00451 *phaseIt += ellapsedTime;
00452 if ( *phaseIt >= *currEmitPeriod)
00453 {
00454 if (*currEmitPeriod != 0)
00455 {
00456 *phaseIt -= ::floorf(*phaseIt / *currEmitPeriod) * *currEmitPeriod;
00457 }
00458 const uint32 k = phaseIt - (_Phase.begin());
00459 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, k) : _GenNb;
00460 processEmit(k, nbToGenerate);
00461 }
00462
00463 ++phaseIt;
00464 currEmitPeriod += currEmitPeriodPtrInc;
00465 }
00466 while (phaseIt != endPhaseIt);
00467 }
00468 else
00469 {
00470 do
00471 {
00472 *phaseIt += ellapsedTime;
00473 if ( *phaseIt >= *currEmitPeriod + _EmitDelay)
00474 {
00475 if (*currEmitPeriod != 0)
00476 {
00477 *phaseIt -= ::floorf((*phaseIt - _EmitDelay) / *currEmitPeriod) * *currEmitPeriod;
00478 }
00479 const uint32 k = phaseIt - (_Phase.begin());
00480 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, k) : _GenNb;
00481 processEmit(k, nbToGenerate);
00482 }
00483
00484 ++phaseIt;
00485 currEmitPeriod += currEmitPeriodPtrInc;
00486 }
00487 while (phaseIt != endPhaseIt);
00488 }
00489 }
00490 else
00491 {
00493 if (_EmitDelay == 0.f)
00494 {
00495 do
00496 {
00497 if (*numEmitIt < _MaxEmissionCount)
00498 {
00499 *phaseIt += ellapsedTime;
00500 if ( *phaseIt >= *currEmitPeriod)
00501 {
00502 if (*currEmitPeriod != 0)
00503 {
00504 *phaseIt -= ::floorf(*phaseIt / *currEmitPeriod) * *currEmitPeriod;
00505 }
00506 const uint32 k = phaseIt - (_Phase.begin());
00507 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, k) : _GenNb;
00508 processEmit(k, nbToGenerate);
00509 ++*numEmitIt;
00510 }
00511 }
00512 ++phaseIt;
00513 currEmitPeriod += currEmitPeriodPtrInc;
00514 ++ numEmitIt;
00515 }
00516 while (phaseIt != endPhaseIt);
00517 }
00518 else
00519 {
00520 do
00521 {
00522 if (*numEmitIt < _MaxEmissionCount)
00523 {
00524 *phaseIt += ellapsedTime;
00525 if ( *phaseIt >= *currEmitPeriod + _EmitDelay)
00526 {
00527 if (*currEmitPeriod != 0)
00528 {
00529 *phaseIt -= ::floorf((*phaseIt - _EmitDelay) / *currEmitPeriod) * *currEmitPeriod;
00530 }
00531 const uint32 k = phaseIt - (_Phase.begin());
00532 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, k) : _GenNb;
00533 processEmit(k, nbToGenerate);
00534 ++*numEmitIt;
00535 }
00536 }
00537 ++phaseIt;
00538 currEmitPeriod += currEmitPeriodPtrInc;
00539 ++numEmitIt;
00540 }
00541 while (phaseIt != endPhaseIt);
00542 }
00543 }
00544
00545 leftToDo -= toProcess;
00546 }
00547 while (leftToDo);
00548 }
00549
00551
00552
00553 static inline uint GenEmitterPositions(CPSLocated *emitter,
00554 CPSLocated *emittee,
00555 uint emitterIndex,
00556 uint numStep,
00557 TAnimationTime deltaT,
00558 TAnimationTime step,
00559 std::vector<NLMISC::CVector> &dest
00560 )
00561 {
00562 const uint toProcess = std::max(1U, std::min(numStep, (uint) emittee->getMaxSize()));
00563 dest.resize(toProcess);
00564
00565
00566 if (!emitter->isParametricMotionEnabled())
00567 {
00568 if (toProcess == 1)
00569 {
00570 dest[0] = emitter->getPos()[emitterIndex] - deltaT * emitter->getSpeed()[emitterIndex];
00571 }
00572 else
00573 {
00574 std::vector<NLMISC::CVector>::iterator outIt = dest.end();
00575 std::vector<NLMISC::CVector>::iterator endIt = dest.begin();
00576 NLMISC::CVector pos = emitter->getPos()[emitterIndex] - deltaT * emitter->getSpeed()[emitterIndex];
00577 NLMISC::CVector speed = step * emitter->getSpeed()[emitterIndex];
00578 do
00579 {
00580 -- outIt;
00581 *outIt = pos;
00582 pos -= speed;
00583 }
00584 while (outIt != endIt);
00585 }
00586 }
00587 else
00588 {
00589 emitter->integrateSingle(emitter->getOwner()->getSystemDate() - deltaT - step * toProcess,
00590 step,
00591 toProcess,
00592 emitterIndex,
00593 &dest[0]
00594 );
00595 }
00596
00597 return toProcess;
00598 }
00599
00601 void CPSEmitter::processRegularEmissionConsistent(TAnimationTime ellapsedTime, float realEllapsedTimeRatio)
00602 {
00604
00605 static std::vector<NLMISC::CVector> emitterPositions;
00606
00607
00608 const uint size = _Owner->getSize();
00609 uint leftToDo = size, toProcess;
00610 float emitPeriod[emitterBuffSize];
00611 float *currEmitPeriod;
00612 uint currEmitPeriodPtrInc = _PeriodScheme ? 1 : 0;
00613 sint32 nbToGenerate;
00614
00615
00616 TPSAttribTime::iterator phaseIt = _Phase.begin(), endPhaseIt;
00617 TPSAttribUInt8::iterator numEmitIt = _NumEmission.begin();
00618
00619
00620
00621 do
00622 {
00623 toProcess = leftToDo < emitterBuffSize ? leftToDo : emitterBuffSize;
00624
00625
00626 if (_PeriodScheme)
00627 {
00628 currEmitPeriod = (float *) (_PeriodScheme->make(_Owner, size - leftToDo, emitPeriod, sizeof(float), toProcess, true));
00629 }
00630 else
00631 {
00632 currEmitPeriod = &_Period;
00633 }
00634
00635 endPhaseIt = phaseIt + toProcess;
00636
00637 if (_MaxEmissionCount == 0)
00638 {
00640 if (_EmitDelay == 0.f)
00641 {
00642 do
00643 {
00644 *phaseIt += ellapsedTime;
00645 if ( *phaseIt >= *currEmitPeriod)
00646 {
00647 if (*currEmitPeriod != 0)
00648 {
00651 *phaseIt = std::min(*phaseIt, *currEmitPeriod + ellapsedTime);
00652
00654
00655 *phaseIt -= *currEmitPeriod * numEmissions;
00656 float deltaT = std::max(0.f, *phaseIt);
00657
00658 uint emitterIndex = phaseIt - _Phase.begin();
00659
00661 numEmissions = GenEmitterPositions(_Owner,
00662 _EmittedType,
00663 emitterIndex,
00664 numEmissions,
00665 deltaT,
00666 *currEmitPeriod,
00667 emitterPositions
00668 );
00669
00671 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00672 uint k = numEmissions;
00673 do
00674 {
00675 --k;
00676 processEmitConsistent(emitterPositions[k],
00677 emitterIndex,
00678 nbToGenerate,
00679 deltaT,
00680 ellapsedTime,
00681 realEllapsedTimeRatio);
00682 deltaT += *currEmitPeriod;
00683 }
00684 while (k);
00685 }
00686 else
00687 {
00688 const uint32 emitterIndex = phaseIt - (_Phase.begin());
00689 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00690 processEmit(emitterIndex, nbToGenerate);
00691 }
00692 }
00693
00694 ++phaseIt;
00695 currEmitPeriod += currEmitPeriodPtrInc;
00696 }
00697 while (phaseIt != endPhaseIt);
00698 }
00699 else
00700 {
00701 do
00702 {
00703 *phaseIt += ellapsedTime;
00704 if ( *phaseIt >= *currEmitPeriod + _EmitDelay)
00705 {
00706 if (*currEmitPeriod != 0)
00707 {
00710 *phaseIt = std::min(*phaseIt, *currEmitPeriod + ellapsedTime + _EmitDelay);
00711
00712 uint numEmissions = (uint) ::floorf((*phaseIt - _EmitDelay) / *currEmitPeriod);
00713 *phaseIt -= *currEmitPeriod * numEmissions;
00714 float deltaT = std::max(*phaseIt - _EmitDelay, 0.f);
00715
00716
00717 uint emitterIndex = phaseIt - _Phase.begin();
00719 numEmissions = GenEmitterPositions(_Owner,
00720 _EmittedType,
00721 emitterIndex,
00722 numEmissions,
00723 deltaT,
00724 *currEmitPeriod,
00725 emitterPositions
00726 );
00728 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00729 uint k = numEmissions;
00730 do
00731 {
00732 --k;
00733 processEmitConsistent(emitterPositions[k],
00734 emitterIndex,
00735 nbToGenerate,
00736 deltaT,
00737 ellapsedTime,
00738 realEllapsedTimeRatio);
00739 deltaT += *currEmitPeriod;
00740 }
00741 while (k);
00742 }
00743 else
00744 {
00745 const uint32 emitterIndex = phaseIt - (_Phase.begin());
00746 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00747 processEmit(emitterIndex, nbToGenerate);
00748 }
00749 }
00750
00751 ++phaseIt;
00752 currEmitPeriod += currEmitPeriodPtrInc;
00753 }
00754 while (phaseIt != endPhaseIt);
00755 }
00756 }
00757 else
00758 {
00760 if (_EmitDelay == 0.f)
00761 {
00762 do
00763 {
00764 if (*numEmitIt < _MaxEmissionCount)
00765 {
00766 *phaseIt += ellapsedTime;
00767 if ( *phaseIt >= *currEmitPeriod)
00768 {
00769 if (*currEmitPeriod != 0)
00770 {
00773 *phaseIt = std::min(*phaseIt, *currEmitPeriod + ellapsedTime);
00774
00775 uint numEmissions = (uint) ::floorf(*phaseIt / *currEmitPeriod);
00776 *numEmitIt += numEmissions;
00777 *phaseIt -= *currEmitPeriod * numEmissions;
00778 float deltaT = std::max(*phaseIt, 0.f);
00779
00780 uint emitterIndex = phaseIt - _Phase.begin();
00781 if (*numEmitIt > _MaxEmissionCount)
00782 {
00783 numEmissions -= *numEmitIt - _MaxEmissionCount;
00784 *numEmitIt = _MaxEmissionCount;
00785 }
00787 numEmissions = GenEmitterPositions(_Owner,
00788 _EmittedType,
00789 emitterIndex,
00790 numEmissions,
00791 deltaT,
00792 *currEmitPeriod,
00793 emitterPositions
00794 );
00795 uint k = numEmissions;
00797 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00798 do
00799 {
00800 --k;
00801 processEmitConsistent(emitterPositions[k],
00802 emitterIndex,
00803 nbToGenerate,
00804 deltaT,
00805 ellapsedTime,
00806 realEllapsedTimeRatio);
00807 deltaT += *currEmitPeriod;
00808 }
00809 while (k);
00810 }
00811 else
00812 {
00813 const uint32 emitterIndex = phaseIt - _Phase.begin();
00814 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00815 processEmit(emitterIndex, nbToGenerate);
00816 ++*numEmitIt;
00817 }
00818 }
00819 }
00820 ++phaseIt;
00821 currEmitPeriod += currEmitPeriodPtrInc;
00822 ++ numEmitIt;
00823 }
00824 while (phaseIt != endPhaseIt);
00825 }
00826 else
00827 {
00828 do
00829 {
00830 if (*numEmitIt < _MaxEmissionCount)
00831 {
00832 *phaseIt += ellapsedTime;
00833 if ( *phaseIt >= *currEmitPeriod + _EmitDelay)
00834 {
00835 if (*currEmitPeriod != 0)
00836 {
00839 *phaseIt = std::min(*phaseIt, *currEmitPeriod + ellapsedTime + _EmitDelay);
00840
00841 uint numEmissions = (uint) ::floorf((*phaseIt - _EmitDelay) / *currEmitPeriod);
00842 *numEmitIt += numEmissions;
00843 *phaseIt -= *currEmitPeriod * numEmissions;
00844 float deltaT = std::max(*phaseIt - _EmitDelay, 0.f);
00845
00846 uint emitterIndex = phaseIt - _Phase.begin();
00847 if (*numEmitIt > _MaxEmissionCount)
00848 {
00849 numEmissions -= *numEmitIt - _MaxEmissionCount;
00850 *numEmitIt = _MaxEmissionCount;
00851 }
00853 numEmissions = GenEmitterPositions(_Owner,
00854 _EmittedType,
00855 emitterIndex,
00856 numEmissions,
00857 deltaT,
00858 *currEmitPeriod,
00859 emitterPositions
00860 );
00861 uint k = numEmissions;
00863 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00864 do
00865 {
00866 --k;
00867 processEmitConsistent(emitterPositions[k],
00868 emitterIndex,
00869 nbToGenerate,
00870 deltaT,
00871 ellapsedTime,
00872 realEllapsedTimeRatio);
00873 deltaT += *currEmitPeriod;
00874 }
00875 while (k);
00876 }
00877 else
00878 {
00879 const uint32 emitterIndex = phaseIt - (_Phase.begin());
00880 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00881 processEmit(emitterIndex, nbToGenerate);
00882 ++*numEmitIt;
00883 }
00884 }
00885 }
00886 ++phaseIt;
00887 currEmitPeriod += currEmitPeriodPtrInc;
00888 ++numEmitIt;
00889 }
00890 while (phaseIt != endPhaseIt);
00891 }
00892 }
00893
00894 leftToDo -= toProcess;
00895 }
00896 while (leftToDo);
00897 }
00898
00900 void CPSEmitter::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEllapsedTime)
00901 {
00902 if (pass == PSToolRender)
00903 {
00904 showTool();
00905 return;
00906 }
00907 if (pass != PSEmit || !_EmittedType) return;
00908 const uint32 size = _Owner->getSize();
00909 if (!size) return;
00910
00911 if (ellapsedTime == 0.f) return;
00912
00913
00914 switch (_EmissionType)
00915 {
00916 case CPSEmitter::once :
00917 {
00918 TPSAttribTime::iterator timeIt = _Phase.begin()
00919 , timeEndIt = _Phase.end();
00920
00921 while (timeIt != timeEndIt)
00922 {
00923 if (*timeIt == 0.f)
00924 {
00925 const uint32 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, timeIt - _Phase.begin()) : _GenNb;
00926 processEmit(timeIt - _Phase.begin(), nbToGenerate);
00927 *timeIt = 1.f;
00928 }
00929 ++timeIt;
00930 }
00931 }
00932 break;
00933 case (CPSEmitter::regular):
00934 {
00935 if (!_ConsistentEmission)
00936 {
00937 processRegularEmission(ellapsedTime);
00938 }
00939 else
00940 {
00941 processRegularEmissionConsistent(ellapsedTime, realEllapsedTime / ellapsedTime);
00942 }
00943 }
00944 break;
00945 default: break;
00946 }
00947 }
00948
00950 void CPSEmitter::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00951 {
00952 nlassert(_Phase.getSize() != _Phase.getMaxSize());
00953
00954 _Phase.insert(0.f);
00955 if (_MaxEmissionCount != 0)
00956 {
00957 _NumEmission.insert(0);
00958 }
00959 if (_PeriodScheme && _PeriodScheme->hasMemory()) _PeriodScheme->newElement(emitterLocated, emitterIndex);
00960 if (_GenNbScheme && _GenNbScheme->hasMemory()) _GenNbScheme->newElement(emitterLocated, emitterIndex);
00961
00962 }
00963
00965 void CPSEmitter::deleteElement(uint32 index)
00966 {
00967
00968 if (_EmissionType == CPSEmitter::onDeath && _EmittedType)
00969 {
00970 const uint32 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, index) : _GenNb;
00971 processEmit(index, nbToGenerate);
00972 }
00973
00974 if (_PeriodScheme && _PeriodScheme->hasMemory()) _PeriodScheme->deleteElement(index);
00975 if (_GenNbScheme && _GenNbScheme->hasMemory()) _GenNbScheme->deleteElement(index);
00976 _Phase.remove(index);
00977 if (_MaxEmissionCount != 0)
00978 {
00979 _NumEmission.remove(index);
00980 }
00981 }
00982
00984 void CPSEmitter::resize(uint32 size)
00985 {
00986 nlassert(size < (1 << 16));
00987 if (_PeriodScheme && _PeriodScheme->hasMemory()) _PeriodScheme->resize(size, _Owner->getSize());
00988 if (_GenNbScheme && _GenNbScheme->hasMemory()) _GenNbScheme->resize(size, _Owner->getSize());
00989 _Phase.resize(size);
00990 if (_MaxEmissionCount != 0)
00991 {
00992 _NumEmission.resize(size);
00993 }
00994 }
00995
00997 void CPSEmitter::bounceOccured(uint32 index)
00998 {
00999
01000 if (_EmissionType == CPSEmitter::onBounce)
01001 {
01002 const uint32 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, index) : _GenNb;
01003 processEmit(index, nbToGenerate);
01004 }
01005 }
01006
01008 void CPSEmitter::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01009 {
01010
01012 sint ver = f.serialVersion(4);
01013 CPSLocatedBindable::serial(f);
01014
01015 f.serialPolyPtr(_EmittedType);
01016 f.serial(_Phase);
01017 f.serial(_SpeedInheritanceFactor);
01018 f.serial(_SpeedBasisEmission);
01019
01020 f.serialEnum(_EmissionType);
01021
01022
01023 bool trueB = true, falseB = false;
01024
01025 if (!f.isReading())
01026 {
01027 switch (_EmissionType)
01028 {
01029 case CPSEmitter::regular:
01030 if (_PeriodScheme)
01031 {
01032 f.serial(trueB);
01033 f.serialPolyPtr(_PeriodScheme);
01034 }
01035 else
01036 {
01037 f.serial(falseB);
01038 f.serial(_Period);
01039 }
01040 if (ver >= 3)
01041 {
01042 f.serial(_EmitDelay, _MaxEmissionCount);
01043 }
01044 break;
01045 default:
01046 break;
01047 }
01048 if (_GenNbScheme)
01049 {
01050 f.serial(trueB);
01051 f.serialPolyPtr(_GenNbScheme);
01052 }
01053 else
01054 {
01055 f.serial(falseB);
01056 f.serial(_GenNb);
01057 }
01058 }
01059 else
01060 {
01061 bool useScheme;
01062 switch (_EmissionType)
01063 {
01064 case CPSEmitter::regular:
01065 {
01066 f.serial(useScheme);
01067 if (useScheme)
01068 {
01069 delete _PeriodScheme;
01070 f.serialPolyPtr(_PeriodScheme);
01071 }
01072 else
01073 {
01074 f.serial(_Period);
01075 }
01076 if (ver >= 3)
01077 {
01078 f.serial(_EmitDelay, _MaxEmissionCount);
01079 updateMaxCountVect();
01080 }
01081 }
01082 break;
01083 default:
01084 break;
01085 }
01086
01087 f.serial(useScheme);
01088 if (useScheme)
01089 {
01090 delete _GenNbScheme;
01091 f.serialPolyPtr(_GenNbScheme);
01092 }
01093 else
01094 {
01095 f.serial(_GenNb);
01096 }
01097 }
01098 if (ver > 1)
01099 {
01100 f.serial(_EmitDirBasis);
01101 }
01102 if (ver >= 4)
01103 {
01104 f.serial(_ConsistentEmission);
01105 }
01106 }
01107
01109 void CPSEmitter::updateMaxCountVect()
01110 {
01111 if (!_MaxEmissionCount)
01112 {
01113 _NumEmission.resize(0);
01114 }
01115 else
01116 {
01117 nlassert(_Owner);
01118 _NumEmission.resize(_Owner->getMaxSize());
01119 while (_NumEmission.getSize() != 0)
01120 {
01121 _NumEmission.remove(0);
01122 }
01123 while (_NumEmission.getSize() != _Owner->getSize())
01124 {
01125 _NumEmission.insert(0);
01126 }
01127 }
01128 }
01129
01131 void CPSEmitter::setMaxEmissionCount(uint8 count)
01132 {
01133 if (count == _MaxEmissionCount) return;
01134 _MaxEmissionCount = count;
01135 updateMaxCountVect();
01136 }
01137
01138
01139
01141
01143
01144 void CPSModulatedEmitter::serialEmitteeSpeedScheme(NLMISC::IStream &f) throw(NLMISC::EStream)
01145 {
01146 bool useScheme;
01147 if (!f.isReading())
01148 {
01149 useScheme = useEmitteeSpeedScheme();
01150 }
01151 f.serial(useScheme);
01152 if (useScheme)
01153 {
01154 f.serialPolyPtr(_EmitteeSpeedScheme);
01155 }
01156 else
01157 {
01158 f.serial(_EmitteeSpeed);
01159 }
01160 }
01161
01162
01163
01165
01167
01169
01170 {
01171
01172 nlassert(_EmittedType);
01173
01174 CVector v( ((rand() % 1000) - 500) / 500.0f
01175 , ((rand() % 1000) - 500) / 500.0f
01176 , ((rand() % 1000) - 500) / 500.0f);
01177 v.normalize();
01178 v *= _EmitteeSpeedScheme ? _EmitteeSpeedScheme->get(_Owner, index) : _EmitteeSpeed;
01179
01180 pos = srcPos;
01181 speed = v;
01182 }
01183
01185 void CPSEmitterOmni::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01186 {
01187 f.serialVersion(1);
01188 CPSEmitter::serial(f);
01189 CPSModulatedEmitter::serialEmitteeSpeedScheme(f);
01190 }
01191
01193 void CPSEmitterOmni::newElement(CPSLocated *emitter, uint32 emitterIndex)
01194 {
01195 CPSEmitter::newElement(emitter, emitterIndex);
01196 newEmitteeSpeedElement(emitter, emitterIndex);
01197 }
01198
01200 void CPSEmitterOmni::deleteElement(uint32 index)
01201 {
01202 CPSEmitter::deleteElement(index);
01203 deleteEmitteeSpeedElement(index);
01204 }
01205
01207 void CPSEmitterOmni::resize(uint32 capacity)
01208 {
01209 nlassert(capacity < (1 << 16));
01210 CPSEmitter::resize(capacity);
01211 resizeEmitteeSpeed(capacity);
01212 }
01213
01215 void CPSEmitterDirectionnal::emit(const NLMISC::CVector &srcPos, uint32 index, CVector &pos, CVector &speed)
01216 {
01217
01218 nlassert(_EmittedType);
01219
01220
01221 speed = (_EmitteeSpeedScheme ? _EmitteeSpeedScheme->get(_Owner, index) : _EmitteeSpeed) * _Dir;
01222 pos = srcPos;
01223 }
01224
01226 void CPSEmitterDirectionnal::newElement(CPSLocated *emitter, uint32 emitterIndex)
01227 {
01228 CPSEmitter::newElement(emitter, emitterIndex);
01229 newEmitteeSpeedElement(emitter, emitterIndex);
01230 }
01231
01233 void CPSEmitterDirectionnal::deleteElement(uint32 index)
01234 {
01235 CPSEmitter::deleteElement(index);
01236 deleteEmitteeSpeedElement(index);
01237 }
01238
01240 void CPSEmitterDirectionnal::resize(uint32 capacity)
01241 {
01242 nlassert(capacity < (1 << 16));
01243 CPSEmitter::resize(capacity);
01244 resizeEmitteeSpeed(capacity);
01245 }
01246
01248 void CPSEmitterDirectionnal::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01249 {
01250 f.serialVersion(1);
01251 CPSEmitter::serial(f);
01252 CPSModulatedEmitter::serialEmitteeSpeedScheme(f);
01253 f.serial(_Dir);
01254 }
01255
01257
01259
01261
01262 {
01263 f.serialVersion(1);
01264 CPSEmitter::serial(f);
01265 CPSModulatedEmitter::serialEmitteeSpeedScheme(f);
01266 f.serial(_Basis);
01267 f.serial(_Width);
01268 f.serial(_Height);
01269 f.serial(_Dir);
01270
01271 }
01272
01274 void CPSEmitterRectangle::emit(const NLMISC::CVector &srcPos, uint32 index, CVector &pos, CVector &speed)
01275 {
01276 CVector N = _Basis[index].X ^ _Basis[index].Y;
01277 pos = srcPos + ((rand() % 32000) * (1.f / 16000) - 1.f) * _Width[index] * _Basis[index].X
01278 + ((rand() % 32000) * (1.f / 16000) - 1.f) * _Height[index] * _Basis[index].Y;
01279 speed = (_EmitteeSpeedScheme ? _EmitteeSpeedScheme->get(_Owner, index) : _EmitteeSpeed)
01280 * (_Dir.x * _Basis[index].X+ _Dir.y * _Basis[index].Y + _Dir.z * N);
01281 }
01282
01284 void CPSEmitterRectangle::setMatrix(uint32 index, const CMatrix &m)
01285 {
01286 _Owner->getPos()[index] = m.getPos();
01287
01288
01289 _Basis[index].X = m.getI();
01290 _Basis[index].Y = m.getJ();
01291 }
01292
01294 CMatrix CPSEmitterRectangle::getMatrix(uint32 index) const
01295 {
01296 CMatrix m;
01297 m.setPos(_Owner->getPos()[index]);
01298 m.setRot(_Basis[index].X, _Basis[index].Y, _Basis[index].X ^ _Basis[index].Y, true);
01299 return m;
01300 }
01301
01303 void CPSEmitterRectangle::setScale(uint32 index, float scale)
01304 {
01305 _Width[index] = scale;
01306 _Height[index] = scale;
01307 }
01308
01310 void CPSEmitterRectangle::setScale(uint32 index, const CVector &s)
01311 {
01312 _Width[index] = s.x;
01313 _Height[index] = s.y;
01314 }
01315
01317 CVector CPSEmitterRectangle::getScale(uint32 index) const
01318 {
01319 return CVector(_Width[index], _Height[index], 1.f);
01320 }
01321
01323 void CPSEmitterRectangle::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
01324 {
01325 CPSEmitter::newElement(emitterLocated, emitterIndex);
01326 newEmitteeSpeedElement(emitterLocated, emitterIndex);
01327 _Basis.insert(CPlaneBasis(CVector::K));
01328 _Width.insert(1.f);
01329 _Height.insert(1.f);
01330 }
01331
01333 void CPSEmitterRectangle::deleteElement(uint32 index)
01334 {
01335 CPSEmitter::deleteElement(index);
01336 deleteEmitteeSpeedElement(index);
01337 _Basis.remove(index);
01338 _Width.remove(index);
01339 _Height.remove(index);
01340 }
01341
01343 void CPSEmitterRectangle::resize(uint32 size)
01344 {
01345 nlassert(size < (1 << 16));
01346 CPSEmitter::resize(size);
01347 resizeEmitteeSpeed(size);
01348 _Basis.resize(size);
01349 _Width.resize(size);
01350 _Height.resize(size);
01351 }
01352
01354 void CPSEmitterRectangle::showTool(void)
01355 {
01356 nlassert(_Owner);
01357 const uint size = _Owner->getSize();
01358 if (!size) return;
01359 setupDriverModelMatrix();
01360 CMatrix mat;
01361
01362 CPSLocated *loc;
01363 uint32 index;
01364 CPSLocatedBindable *lb;
01365 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
01366
01367 for (uint k = 0; k < size; ++k)
01368 {
01369 const CVector &I = _Basis[k].X;
01370 const CVector &J = _Basis[k].Y;
01371 mat.setRot(I, J , I ^J);
01372 mat.setPos(_Owner->getPos()[k]);
01373 CPSUtil::displayBasis(getDriver() ,getLocatedMat(), mat, 1.f, *getFontGenerator(), *getFontManager());
01374 setupDriverModelMatrix();
01375
01376 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
01377
01378
01379
01380 const CVector &pos = _Owner->getPos()[k];
01381 CPSUtil::display3DQuad(*getDriver(), pos + I * _Width[k] + J * _Height[k]
01382 , pos + I * _Width[k] - J * _Height[k]
01383 , pos - I * _Width[k] - J * _Height[k]
01384 , pos - I * _Width[k] + J * _Height[k], col);
01385 }
01386 }
01387
01388
01389
01391
01393
01395
01396 {
01397 f.serialVersion(1);
01398 CPSEmitterDirectionnal::serial(f);
01399 f.serial(_Radius);
01400 }
01401
01403 void CPSEmitterConic::setDir(const CVector &v)
01404 {
01405 CPSEmitterDirectionnal::setDir(v);
01406
01407 }
01408
01410 void CPSEmitterConic::emit(const NLMISC::CVector &srcPos, uint32 index, CVector &pos, CVector &speed)
01411 {
01412
01413 nlassert(_EmittedType);
01414
01415
01416
01417
01418 static const double divRand = (2.0 / RAND_MAX);
01419
01420 CVector dir((float) (rand() * divRand - 1)
01421 , (float) (rand() * divRand - 1)
01422 , (float) (rand() * divRand - 1) );
01423
01424 const float n =dir.norm();
01425
01426 dir *= _Radius / n;
01427
01428 dir -= (_Dir * dir) * _Dir;
01429 dir += _Dir;
01430 dir.normalize();
01431
01432
01433 speed = (_EmitteeSpeedScheme ? _EmitteeSpeedScheme->get(_Owner, index) : _EmitteeSpeed)
01434 * dir;
01435 pos = srcPos;
01436 }
01437
01439
01441
01443
01444 {
01445 static const double divRand = (2.0 / RAND_MAX);
01446 CVector dir((float) (rand() * divRand - 1), (float) (rand() * divRand - 1) , (float) (rand() * divRand - 1) );
01447 dir.normalize();
01448 pos = srcPos + _Radius[index] * dir;
01449 speed = (_EmitteeSpeedScheme ? _EmitteeSpeedScheme->get(_Owner, index) : _EmitteeSpeed) * dir;
01450 }
01451
01452
01454 void CPSSphericalEmitter::showTool(void)
01455 {
01456 CPSLocated *loc;
01457 uint32 index;
01458 CPSLocatedBindable *lb;
01459 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
01460
01461
01462 TPSAttribFloat::const_iterator radiusIt = _Radius.begin();
01463 TPSAttribVector::const_iterator posIt = _Owner->getPos().begin(), endPosIt = _Owner->getPos().end();
01464 setupDriverModelMatrix();
01465 for (uint k = 0; posIt != endPosIt; ++posIt, ++radiusIt, ++k)
01466 {
01467 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
01468 CPSUtil::displaySphere(*getDriver(), *radiusIt, *posIt, 5, col);
01469 }
01470 }
01471
01472
01474 void CPSSphericalEmitter::setMatrix(uint32 index, const CMatrix &m)
01475 {
01476 nlassert(index < _Radius.getSize());
01477
01478 _Owner->getPos()[index] = m.getPos();
01479
01480 }
01481
01483 CMatrix CPSSphericalEmitter::getMatrix(uint32 index) const
01484 {
01485 nlassert(index < _Radius.getSize());
01486 CMatrix m;
01487 m.identity();
01488 m.translate(_Owner->getPos()[index]);
01489 return m;
01490 }
01491
01493 void CPSSphericalEmitter::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01494 {
01495 f.serialVersion(1);
01496 CPSEmitter::serial(f);
01497 CPSModulatedEmitter::serialEmitteeSpeedScheme(f);
01498 f.serial(_Radius);
01499 }
01500
01502 void CPSSphericalEmitter::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
01503 {
01504 CPSEmitter::newElement(emitterLocated, emitterIndex);
01505 newEmitteeSpeedElement(emitterLocated, emitterIndex);
01506 _Radius.insert(1.f);
01507 }
01508
01510 void CPSSphericalEmitter::deleteElement(uint32 index)
01511 {
01512 CPSEmitter::deleteElement(index);
01513 deleteEmitteeSpeedElement(index);
01514 _Radius.remove(index);
01515 }
01516
01518 void CPSSphericalEmitter::resize(uint32 size)
01519 {
01520 nlassert(size < (1 << 16));
01521 CPSEmitter::resize(size);
01522 resizeEmitteeSpeed(size);
01523 _Radius.resize(size);
01524 }
01525
01527
01529
01531
01532 {
01533 f.serialVersion(1);
01534 CPSEmitterDirectionnal::serial(f);
01535 }
01536
01538 void CPSRadialEmitter::emit(const NLMISC::CVector &srcPos, uint32 index, NLMISC::CVector &pos, NLMISC::CVector &speed)
01539 {
01540
01541 nlassert(_EmittedType);
01542
01543 static const double divRand = (2.0 / RAND_MAX);
01544 CVector dir((float) (rand() * divRand - 1)
01545 , (float) (rand() * divRand - 1)
01546 , (float) (rand() * divRand - 1) );
01547 dir -= (dir * _Dir) * _Dir;
01548 dir.normalize();
01549
01550 speed = (_EmitteeSpeedScheme ? _EmitteeSpeedScheme->get(_Owner, index) : _EmitteeSpeed) * dir;
01551 pos = srcPos;
01552 }
01553
01554
01555
01556 }