1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/3d/ps_emitter.h"
20 #include "nel/3d/material.h"
21 #include "nel/misc/line.h"
22 #include "nel/3d/dru.h"
23 #include "nel/3d/particle_system.h"
34 static const uint EMITTER_BUFF_SIZE
= 512; // number of emitter to be processed at once
35 static const float EMIT_PERIOD_THRESHOLD
= 1.f
/ 75.f
; // assuming the same behaviour than with a 75 hz rendering
36 bool CPSEmitter::_BypassEmitOnDeath
= false;
39 //////////////////////
40 // STATIC FUNCTIONS //
41 //////////////////////
42 /** In an arrey of float, all value that are 0.f are replaced by EMIT_PERIOD_THRESHOLD
43 * A period of 0 is allowed for emitter and means "emit at each frame"
44 * This is deprecated now, and this helps to avoid that behaviour
46 static void replaceNullPeriodsByThreshold(float *tab
, uint numElem
)
48 NL_PS_FUNC(replaceNullPeriodsByThreshold
)
49 const float *endTab
= tab
+ numElem
;
52 if (*tab
== 0.f
) *tab
= EMIT_PERIOD_THRESHOLD
;
57 ///////////////////////////////
58 // CPSEmitter implementation //
59 ///////////////////////////////
60 CPSEmitter::CPSEmitter() : _EmittedType(NULL
),
61 _SpeedInheritanceFactor(0.f
),
62 _EmissionType(regular
),
69 _SpeedBasisEmission(false),
70 _ConsistentEmission(true),
71 _BypassAutoLOD(false),
72 _UserMatrixModeForEmissionDirection(false),
74 _UserDirectionMatrixMode(PSFXWorldMatrix
)
76 NL_PS_FUNC(CPSEmitter_CPSEmitter
)
80 ///==========================================================================
81 CPSEmitter::~CPSEmitter()
83 NL_PS_FUNC(CPSEmitter_CPSEmitterDtor
)
86 // if a located is emitted, unregister us as an observer
89 _EmittedType
->unregisterDtorObserver(this);
93 ///==========================================================================
94 void CPSEmitter::releaseRefTo(const CParticleSystemProcess
*other
)
96 NL_PS_FUNC(CPSEmitter_releaseRefTo
)
97 if (_EmittedType
== other
)
103 void CPSEmitter::releaseAllRef()
105 NL_PS_FUNC(CPSEmitter_releaseAllRef
)
106 setEmittedType(NULL
);
110 ///==========================================================================
111 void CPSEmitter::setOwner(CPSLocated
*psl
)
113 NL_PS_FUNC(CPSEmitter_setOwner
)
114 CPSLocatedBindable::setOwner(psl
);
115 updateMaxCountVect();
119 ///==========================================================================
120 inline void CPSEmitter::processEmit(uint32 index
, sint nbToGenerate
)
122 NL_PS_FUNC(CPSEmitter_processEmit
)
123 NLMISC::CVector speed
, pos
;
125 if (!_SpeedBasisEmission
)
127 if (_SpeedInheritanceFactor
== 0.f
)
129 if (!_UserMatrixModeForEmissionDirection
)
131 while (nbToGenerate
> 0)
134 emit(_Owner
->getPos()[index
], index
, pos
, speed
);
135 _EmittedType
->postNewElement(pos
, speed
, *this->_Owner
, index
, _Owner
->getMatrixMode(), 0.f
);
140 while (nbToGenerate
> 0)
143 emit(_Owner
->getPos()[index
], index
, pos
, speed
);
144 _EmittedType
->postNewElement(pos
, speed
, *this->_Owner
, index
, _UserDirectionMatrixMode
, 0.f
);
150 while (nbToGenerate
--)
152 emit(_Owner
->getPos()[index
], index
, pos
, speed
);
153 _EmittedType
->postNewElement(pos
, speed
+ _SpeedInheritanceFactor
* _Owner
->getSpeed()[index
], *this->_Owner
, 0, _Owner
->getMatrixMode(), 0.f
);
160 CPSUtil::buildSchmidtBasis(_Owner
->getSpeed()[index
], m
);
161 if (_SpeedInheritanceFactor
== 0.f
)
163 while (nbToGenerate
> 0)
166 emit(_Owner
->getPos()[index
], index
, pos
, speed
);
167 _EmittedType
->postNewElement(pos
, m
* speed
, *this->_Owner
, index
, _Owner
->getMatrixMode(), 0.f
);
172 while (nbToGenerate
--)
174 emit(_Owner
->getPos()[index
], index
, pos
, speed
);
175 _EmittedType
->postNewElement(pos
, m
* speed
+ _SpeedInheritanceFactor
* _Owner
->getSpeed()[index
], *this->_Owner
, index
, _Owner
->getMatrixMode(), 0.f
);
182 ///==========================================================================
183 void CPSEmitter::processEmitOutsideSimLoop(uint32 index
,sint nbToGenerate
)
185 NL_PS_FUNC(CPSEmitter_processEmitOutsideSimLoop
)
186 NLMISC::CVector speed
, pos
;
188 if (!_SpeedBasisEmission
)
190 if (_SpeedInheritanceFactor
== 0.f
)
192 if (!_UserMatrixModeForEmissionDirection
)
194 while (nbToGenerate
> 0)
197 emit(_Owner
->getPos()[index
], index
, pos
, speed
);
198 _EmittedType
->newElement(pos
, speed
, this->_Owner
, index
, _Owner
->getMatrixMode(), true);
203 while (nbToGenerate
> 0)
206 emit(_Owner
->getPos()[index
], index
, pos
, speed
);
207 _EmittedType
->newElement(pos
, speed
, this->_Owner
, index
, _UserDirectionMatrixMode
);
213 while (nbToGenerate
--)
215 emit(_Owner
->getPos()[index
], index
, pos
, speed
);
216 _EmittedType
->newElement(pos
, speed
+ _SpeedInheritanceFactor
* _Owner
->getSpeed()[index
], this->_Owner
, 0, _Owner
->getMatrixMode(), true);
223 CPSUtil::buildSchmidtBasis(_Owner
->getSpeed()[index
], m
);
224 if (_SpeedInheritanceFactor
== 0.f
)
226 while (nbToGenerate
> 0)
229 emit(_Owner
->getPos()[index
], index
, pos
, speed
);
230 _EmittedType
->newElement(pos
, m
* speed
, this->_Owner
, index
, _Owner
->getMatrixMode(), true);
235 while (nbToGenerate
--)
237 emit(_Owner
->getPos()[index
], index
, pos
, speed
);
238 _EmittedType
->newElement(pos
, m
* speed
+ _SpeedInheritanceFactor
* _Owner
->getSpeed()[index
], this->_Owner
, index
, _Owner
->getMatrixMode(), true);
244 ///==========================================================================
245 inline void CPSEmitter::processEmitConsistent(const NLMISC::CVector
&emitterPos
,
248 TAnimationTime deltaT
)
250 NL_PS_FUNC(CPSEmitter_processEmitConsistent
)
251 static NLMISC::CVector speed
, pos
; /// speed and pos of emittee
253 if (!_SpeedBasisEmission
)
255 if (_SpeedInheritanceFactor
== 0.f
)
257 if (!_UserMatrixModeForEmissionDirection
)
259 while (nbToGenerate
> 0)
262 emit(emitterPos
, index
, pos
, speed
);
263 _EmittedType
->postNewElement(pos
, speed
, *this->_Owner
, index
, _Owner
->getMatrixMode(), deltaT
);
268 while (nbToGenerate
> 0)
271 emit(emitterPos
, index
, pos
, speed
);
272 _EmittedType
->postNewElement(pos
, speed
, *this->_Owner
, index
, _UserDirectionMatrixMode
, deltaT
);
278 while (nbToGenerate
--)
280 emit(emitterPos
, index
, pos
, speed
);
281 _EmittedType
->postNewElement(pos
, speed
+ _SpeedInheritanceFactor
* _Owner
->getSpeed()[index
], *this->_Owner
, index
, _Owner
->getMatrixMode(), deltaT
);
288 CPSUtil::buildSchmidtBasis(_Owner
->getSpeed()[index
], m
);
289 if (_SpeedInheritanceFactor
== 0.f
)
291 while (nbToGenerate
> 0)
294 emit(emitterPos
, index
, pos
, speed
);
295 _EmittedType
->postNewElement(pos
, m
* speed
, *this->_Owner
, index
, _Owner
->getMatrixMode(), deltaT
);
300 while (nbToGenerate
--)
302 emit(emitterPos
, index
, pos
, speed
);
303 _EmittedType
->postNewElement(pos
, m
* speed
+ _SpeedInheritanceFactor
* _Owner
->getSpeed()[index
], *this->_Owner
, index
, _Owner
->getMatrixMode(), deltaT
);
310 ///==========================================================================
311 bool CPSEmitter::setEmissionType(TEmissionType freqType
)
313 NL_PS_FUNC(CPSEmitter_setEmissionType
)
314 if (_Owner
&& _Owner
->getOwner())
316 CParticleSystem
*ps
= _Owner
->getOwner();
317 if (ps
->getBypassMaxNumIntegrationSteps())
321 nlwarning("<CPSEmitter::setEmissionType> The emitter should be inserted in a CPSLocated instance");
324 // check if the new value is valid
325 TEmissionType oldType
= _EmissionType
;
326 _EmissionType
= freqType
;
327 if (testEmitForever() == true)
329 _EmissionType
= oldType
;
330 std::string mess
= "<CPSEmitter::setEmissionType> can't set emission type to '" +
331 NLMISC::toString(freqType
) +
332 "' with the current configuration : the system has been flagged with \
333 'BypassMaxNumIntegrationSteps', and should have a finite duration. \
334 The flag is not set";
335 nlwarning(mess
.c_str());
340 ps
->systemDurationChanged();
342 _EmissionType
= freqType
;
346 ///==========================================================================
347 bool CPSEmitter::setEmittedType(CPSLocated
*et
)
349 NL_PS_FUNC(CPSEmitter_setEmittedType
)
352 _EmittedType
->unregisterDtorObserver(this);
356 et
->registerDtorObserver(this);
358 CPSLocated
*oldType
= _EmittedType
;
360 if (_Owner
&& _Owner
->getOwner())
362 CParticleSystem
*ps
= _Owner
->getOwner();
366 if (ps
->getBypassMaxNumIntegrationSteps())
368 ok
= ps
->canFinish();
376 setEmittedType(oldType
);
377 nlwarning("<CPSLocated::setEmittedType> Can't set new emitted type : this causes the system to last forever, and it has been flagged with 'BypassMaxNumIntegrationSteps'. New emitted type is not set");
381 ps
->systemDurationChanged();
386 ///==========================================================================
387 void CPSEmitter::notifyTargetRemoved(CPSLocated
*ptr
)
389 NL_PS_FUNC(CPSEmitter_notifyTargetRemoved
)
390 nlassert(ptr
== _EmittedType
&& _EmittedType
);
391 setEmittedType(NULL
);
394 ///==========================================================================
395 void CPSEmitter::setPeriod(float period
)
397 NL_PS_FUNC(CPSEmitter_setPeriod
)
400 delete _PeriodScheme
;
401 _PeriodScheme
= NULL
;
404 if (_Owner
&& _Owner
->getOwner())
406 _Owner
->getOwner()->systemDurationChanged();
410 ///==========================================================================
411 void CPSEmitter::setPeriodScheme(CPSAttribMaker
<float> *scheme
)
413 NL_PS_FUNC(CPSEmitter_setPeriodScheme
)
414 delete _PeriodScheme
;
415 _PeriodScheme
= scheme
;
416 if (_Owner
&& scheme
->hasMemory()) scheme
->resize(_Owner
->getMaxSize(), _Owner
->getSize());
417 if (_Owner
&& _Owner
->getOwner())
419 _Owner
->getOwner()->systemDurationChanged();
423 ///==========================================================================
424 void CPSEmitter::setGenNb(uint32 genNb
)
426 NL_PS_FUNC(CPSEmitter_setGenNb
)
435 ///==========================================================================
436 void CPSEmitter::setGenNbScheme(CPSAttribMaker
<uint32
> *scheme
)
438 NL_PS_FUNC(CPSEmitter_setGenNbScheme
)
440 _GenNbScheme
= scheme
;
441 if (_Owner
&& scheme
->hasMemory()) scheme
->resize(_Owner
->getMaxSize(), _Owner
->getSize());
444 ///==========================================================================
445 void CPSEmitter::showTool(void)
447 NL_PS_FUNC(CPSEmitter_showTool
)
448 uint32 size
= _Owner
->getSize();
450 setupDriverModelMatrix();
452 const CVector I
= computeI();
453 const CVector K
= computeK();
455 // ugly slow code, but not for runtime
456 for (uint k
= 0; k
< size
; ++k
)
458 // center of the current particle
459 const CVector p
= _Owner
->getPos()[k
];
460 const float sSize
=0.1f
;
461 std::vector
<NLMISC::CLine
> lines
;
463 l
.V0
= p
- sSize
* I
; l
.V1
= p
+ sSize
* I
; lines
.push_back(l
);
464 l
.V0
= p
- sSize
* K
; l
.V1
= p
+ sSize
* K
; lines
.push_back(l
);
465 l
.V0
= p
- sSize
* (I
+ K
); l
.V1
= p
+ sSize
* (I
+ K
); lines
.push_back(l
);
466 l
.V0
= p
- sSize
* (I
- K
); l
.V1
= p
+ sSize
* (I
- K
); lines
.push_back(l
);
469 mat
.setBlendFunc(CMaterial::one
, CMaterial::one
);
470 mat
.setZWrite(false);
471 mat
.setLighting(false);
473 mat
.setZFunc(CMaterial::less
);
478 CPSLocatedBindable
*lb
;
479 _Owner
->getOwner()->getCurrentEditedElement(loc
, index
, lb
);
481 mat
.setColor((lb
== NULL
|| this == lb
) && loc
== _Owner
&& index
== k
? CRGBA::Red
: CRGBA(127, 127, 127));
484 CDRU::drawLinesUnlit(lines
, mat
, *getDriver() );
488 ///==========================================================================
489 void CPSEmitter::singleEmit(uint32 index
, uint quantity
)
491 NL_PS_FUNC(CPSEmitter_singleEmit
)
493 const uint32 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
,0) : _GenNb
;
494 processEmitOutsideSimLoop(index
, quantity
* nbToGenerate
);
499 ///==========================================================================
500 void CPSEmitter::processRegularEmissionWithNoLOD(uint firstInstanceIndex
)
502 NL_PS_FUNC(CPSEmitter_processRegularEmissionWithNoLOD
)
504 nlassert(_Owner
->getOwner());
506 const bool emitThreshold
= _Owner
->getOwner()->isEmitThresholdEnabled();
508 const uint size
= _Owner
->getSize();
509 nlassert(firstInstanceIndex
< size
);
510 uint leftToDo
= size
- firstInstanceIndex
, toProcess
;
511 float emitPeriod
[EMITTER_BUFF_SIZE
];
512 const float *currEmitPeriod
;
513 uint currEmitPeriodPtrInc
= _PeriodScheme
? 1 : 0;
516 TPSAttribTime::iterator phaseIt
= _Phase
.begin() + firstInstanceIndex
, endPhaseIt
;
517 TPSAttribUInt8::iterator numEmitIt
= _NumEmission
.begin() + firstInstanceIndex
;
519 // we don't use an iterator here
520 // because it could be invalidated if size change (a located could generate itself)
523 toProcess
= leftToDo
< EMITTER_BUFF_SIZE
? leftToDo
: EMITTER_BUFF_SIZE
;
529 // NB : we ask to clamp entry because life counter of emitter are incremented, then spawn is called, and only after that dead emitters are removed
530 // so we may have a life counter that is > to 1
531 currEmitPeriod
= (float *) (_PeriodScheme
->make(_Owner
, size
- leftToDo
, emitPeriod
, sizeof(float), toProcess
, true, 1 << 16, true));
535 /** Test if 'make' filled our buffer. If this is not the case, we assume that values where precomputed, and that
536 * all null period have already been replaced by the threshold
538 if (currEmitPeriod
== emitPeriod
)
540 // if there possibility to have 0 in the scheme ?
541 if (_PeriodScheme
->getMinValue() <= 0.f
&& _PeriodScheme
->getMaxValue() >= 0.f
)
543 replaceNullPeriodsByThreshold(emitPeriod
, toProcess
);
550 if (_Period
!= 0.f
|| !emitThreshold
)
552 currEmitPeriod
= &_Period
;
556 currEmitPeriod
= &EMIT_PERIOD_THRESHOLD
;
560 endPhaseIt
= phaseIt
+ toProcess
;
562 if (_MaxEmissionCount
== 0) // no emission count limit
564 /// is there an emission delay ?
565 if (_EmitDelay
== 0.f
) // no emission delay
569 *phaseIt
+= CParticleSystem::EllapsedTime
;
570 if ( *phaseIt
>= *currEmitPeriod
) // phase is greater than period -> must emit
572 if (*currEmitPeriod
!= 0)
574 *phaseIt
-= ::floorf(*phaseIt
/ *currEmitPeriod
) * *currEmitPeriod
;
576 const uint32 k
= (uint32
)(phaseIt
- _Phase
.begin());
577 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, k
) : _GenNb
;
578 processEmit(k
, nbToGenerate
);
582 currEmitPeriod
+= currEmitPeriodPtrInc
;
584 while (phaseIt
!= endPhaseIt
);
586 else // there's an emission delay
590 *phaseIt
+= CParticleSystem::EllapsedTime
;
591 if ( *phaseIt
>= *currEmitPeriod
+ _EmitDelay
) // phase is greater than period -> must emit
593 if (*currEmitPeriod
!= 0)
595 *phaseIt
-= ::floorf((*phaseIt
- _EmitDelay
) / *currEmitPeriod
) * *currEmitPeriod
;
597 const uint32 k
= (uint32
)(phaseIt
- _Phase
.begin());
598 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, k
) : _GenNb
;
599 processEmit(k
, nbToGenerate
);
603 currEmitPeriod
+= currEmitPeriodPtrInc
;
605 while (phaseIt
!= endPhaseIt
);
608 else // there's an emission count limit
610 /// is there an emission delay ?
611 if (_EmitDelay
== 0.f
) // no emission delay
615 if (*numEmitIt
< _MaxEmissionCount
)
617 *phaseIt
+= CParticleSystem::EllapsedTime
;
618 if ( *phaseIt
>= *currEmitPeriod
) // phase is greater than period -> must emit
620 if (*currEmitPeriod
!= 0)
622 *phaseIt
-= ::floorf(*phaseIt
/ *currEmitPeriod
) * *currEmitPeriod
;
624 const uint32 k
= (uint32
)(phaseIt
- _Phase
.begin());
625 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, k
) : _GenNb
;
626 processEmit(k
, nbToGenerate
);
631 currEmitPeriod
+= currEmitPeriodPtrInc
;
634 while (phaseIt
!= endPhaseIt
);
636 else // there's an emission delay
640 if (*numEmitIt
< _MaxEmissionCount
)
642 *phaseIt
+= CParticleSystem::EllapsedTime
;
643 if ( *phaseIt
>= *currEmitPeriod
+ _EmitDelay
) // phase is greater than period -> must emit
645 if (*currEmitPeriod
!= 0)
647 *phaseIt
-= ::floorf((*phaseIt
- _EmitDelay
) / *currEmitPeriod
) * *currEmitPeriod
;
649 const uint32 k
= (uint32
)(phaseIt
- _Phase
.begin());
650 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, k
) : _GenNb
;
651 processEmit(k
, nbToGenerate
);
656 currEmitPeriod
+= currEmitPeriodPtrInc
;
659 while (phaseIt
!= endPhaseIt
);
663 leftToDo
-= toProcess
;
669 ///==========================================================================
670 void CPSEmitter::processRegularEmission(uint firstInstanceIndex
, float emitLOD
)
672 NL_PS_FUNC(CPSEmitter_processRegularEmission
)
674 nlassert(_Owner
->getOwner());
676 const bool emitThreshold
= _Owner
->getOwner()->isEmitThresholdEnabled();
678 const uint size
= _Owner
->getSize();
679 nlassert(firstInstanceIndex
< size
);
680 uint leftToDo
= size
- firstInstanceIndex
, toProcess
;
681 float emitPeriod
[EMITTER_BUFF_SIZE
];
682 const float *currEmitPeriod
;
683 uint currEmitPeriodPtrInc
= _PeriodScheme
? 1 : 0;
686 TPSAttribTime::iterator phaseIt
= _Phase
.begin() + firstInstanceIndex
, endPhaseIt
;
687 TPSAttribUInt8::iterator numEmitIt
= _NumEmission
.begin() + firstInstanceIndex
;
689 float ellapsedTimeLOD
= emitLOD
* CParticleSystem::EllapsedTime
;
690 uint maxEmissionCountLOD
= (uint8
) (_MaxEmissionCount
* emitLOD
);
691 maxEmissionCountLOD
= std::max(1u, maxEmissionCountLOD
);
693 // we don't use an iterator here
694 // because it could be invalidated if size change (a located could generate itself)
697 toProcess
= leftToDo
< EMITTER_BUFF_SIZE
? leftToDo
: EMITTER_BUFF_SIZE
;
703 // NB : we ask to clamp entry because life counter of emitter are incremented, then spawn is called, and only after that dead emitters are removed
704 // so we may have a life counter that is > to 1
705 currEmitPeriod
= (float *) (_PeriodScheme
->make(_Owner
, size
- leftToDo
, emitPeriod
, sizeof(float), toProcess
, true, 1 << 16, true));
709 /** Test if 'make' filled our buffer. If this is not the case, we assume that values where precomputed, and that
710 * all null period have already been replaced by the threshold
712 if (currEmitPeriod
== emitPeriod
)
714 // if there possibility to have 0 in the scheme ?
715 if (_PeriodScheme
->getMinValue() <= 0.f
&& _PeriodScheme
->getMaxValue() >= 0.f
)
717 replaceNullPeriodsByThreshold(emitPeriod
, toProcess
);
724 if (_Period
!= 0.f
|| !emitThreshold
)
726 currEmitPeriod
= &_Period
;
730 currEmitPeriod
= &EMIT_PERIOD_THRESHOLD
;
734 endPhaseIt
= phaseIt
+ toProcess
;
736 if (_MaxEmissionCount
== 0) // no emission count limit
738 /// is there an emission delay ?
739 if (_EmitDelay
== 0.f
) // no emission delay
743 *phaseIt
+= ellapsedTimeLOD
;
744 if ( *phaseIt
>= *currEmitPeriod
) // phase is greater than period -> must emit
746 if (*currEmitPeriod
!= 0)
748 *phaseIt
-= ::floorf(*phaseIt
/ *currEmitPeriod
) * *currEmitPeriod
;
750 const uint32 k
= (uint32
)(phaseIt
- _Phase
.begin());
751 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, k
) : _GenNb
;
754 nbToGenerate
= (sint32
) (emitLOD
* nbToGenerate
);
755 if (!nbToGenerate
) nbToGenerate
= 1;
756 processEmit(k
, nbToGenerate
);
761 currEmitPeriod
+= currEmitPeriodPtrInc
;
763 while (phaseIt
!= endPhaseIt
);
765 else // there's an emission delay
769 if (*phaseIt
< _EmitDelay
)
771 *phaseIt
+= CParticleSystem::EllapsedTime
;
772 if (*phaseIt
< _EmitDelay
)
775 currEmitPeriod
+= currEmitPeriodPtrInc
;
780 *phaseIt
= (*phaseIt
- _EmitDelay
) * emitLOD
+ _EmitDelay
;
785 *phaseIt
+= ellapsedTimeLOD
;
788 if ( *phaseIt
>= *currEmitPeriod
+ _EmitDelay
) // phase is greater than period -> must emit
790 if (*currEmitPeriod
!= 0)
792 *phaseIt
-= ::floorf((*phaseIt
- _EmitDelay
) / *currEmitPeriod
) * *currEmitPeriod
;
794 const uint32 k
= (uint32
)(phaseIt
- _Phase
.begin());
795 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, k
) : _GenNb
;
798 nbToGenerate
= (sint32
) (emitLOD
* nbToGenerate
);
799 if (!nbToGenerate
) nbToGenerate
= 1;
800 processEmit(k
, nbToGenerate
);
805 currEmitPeriod
+= currEmitPeriodPtrInc
;
807 while (phaseIt
!= endPhaseIt
);
810 else // there's an emission count limit
812 /// is there an emission delay ?
813 if (_EmitDelay
== 0.f
) // no emission delay
817 if (*numEmitIt
< maxEmissionCountLOD
)
819 *phaseIt
+= ellapsedTimeLOD
;
820 if ( *phaseIt
>= *currEmitPeriod
) // phase is greater than period -> must emit
822 if (*currEmitPeriod
!= 0)
824 *phaseIt
-= ::floorf(*phaseIt
/ *currEmitPeriod
) * *currEmitPeriod
;
826 const uint32 k
= (uint32
)(phaseIt
- _Phase
.begin());
827 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, k
) : _GenNb
;
830 nbToGenerate
= (sint32
) (emitLOD
* nbToGenerate
);
831 if (!nbToGenerate
) nbToGenerate
= 1;
832 processEmit(k
, nbToGenerate
);
839 *numEmitIt
= _MaxEmissionCount
;
842 currEmitPeriod
+= currEmitPeriodPtrInc
;
845 while (phaseIt
!= endPhaseIt
);
847 else // there's an emission delay
851 if (*numEmitIt
< maxEmissionCountLOD
)
853 if (*phaseIt
< _EmitDelay
)
855 *phaseIt
+= CParticleSystem::EllapsedTime
;
856 if (*phaseIt
< _EmitDelay
)
859 currEmitPeriod
+= currEmitPeriodPtrInc
;
861 currEmitPeriod
+= currEmitPeriodPtrInc
;
866 *phaseIt
= (*phaseIt
- _EmitDelay
) * emitLOD
+ _EmitDelay
;
871 *phaseIt
+= ellapsedTimeLOD
;
874 if ( *phaseIt
>= *currEmitPeriod
+ _EmitDelay
) // phase is greater than period -> must emit
876 if (*currEmitPeriod
!= 0)
878 *phaseIt
-= ::floorf((*phaseIt
- _EmitDelay
) / *currEmitPeriod
) * *currEmitPeriod
;
880 const uint32 k
= (uint32
)(phaseIt
- _Phase
.begin());
881 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, k
) : _GenNb
;
884 nbToGenerate
= (sint32
) (nbToGenerate
* emitLOD
);
885 if (!nbToGenerate
) nbToGenerate
= 1;
886 processEmit(k
, nbToGenerate
);
893 *numEmitIt
= _MaxEmissionCount
;
896 currEmitPeriod
+= currEmitPeriodPtrInc
;
899 while (phaseIt
!= endPhaseIt
);
903 leftToDo
-= toProcess
;
908 /// private : generate the various position of an emitter in the given tab for the given slice of time,
909 // depending on whether its motion is parametric or incremental. This is used to create emittees at the right position
915 uint
GenEmitterPositions(CPSLocated
*emitter
,
919 TAnimationTime deltaT
, /* fraction of time needed to reach the first emission */
921 std::vector
<NLMISC::CVector
> &dest
924 NL_PS_FUNC(GenEmitterPositions
)
925 const uint toProcess
= std::max(1U, std::min(numStep
, (uint
) emittee
->getMaxSize()));
926 dest
.resize(toProcess
);
929 if (!emitter
->isParametricMotionEnabled()) // standard case : take current pos and integrate
931 if (toProcess
== 1) // only one emission -> takes current pos
933 dest
[0] = emitter
->getPos()[emitterIndex
] - deltaT
* emitter
->getSpeed()[emitterIndex
];
937 std::vector
<NLMISC::CVector
>::iterator outIt
= dest
.end();
938 std::vector
<NLMISC::CVector
>::iterator endIt
= dest
.begin();
939 NLMISC::CVector pos
= emitter
->getPos()[emitterIndex
] - deltaT
* emitter
->getSpeed()[emitterIndex
];
940 NLMISC::CVector speed
= step
* emitter
->getSpeed()[emitterIndex
];
947 while (outIt
!= endIt
);
950 else // compute parametric trajectory
952 emitter
->integrateSingle(emitter
->getOwner()->getSystemDate() + CParticleSystem::RealEllapsedTime
- deltaT
,
964 /** The same as GenEmitterPositions, but with LOD taken in account.
966 static inline uint
GenEmitterPositionsWithLOD(CPSLocated
*emitter
,
970 TAnimationTime deltaT
, /* fraction of time needed to reach the first emission */
973 std::vector
<NLMISC::CVector
> &dest
976 NL_PS_FUNC(GenEmitterPositionsWithLOD
)
977 const uint toProcess
= std::max(1U, std::min(numStep
, (uint
) emittee
->getMaxSize()));
978 dest
.resize(toProcess
);
981 if (!emitter
->isParametricMotionEnabled()) // standard case : take current pos and integrate
983 if (toProcess
== 1) // only one emission -> takes current pos
985 dest
[0] = emitter
->getPos()[emitterIndex
] - deltaT
* emitter
->getSpeed()[emitterIndex
];
989 std::vector
<NLMISC::CVector
>::iterator outIt
= dest
.end();
990 std::vector
<NLMISC::CVector
>::iterator endIt
= dest
.begin();
991 NLMISC::CVector pos
= emitter
->getPos()[emitterIndex
] - deltaT
* emitter
->getSpeed()[emitterIndex
];
992 NLMISC::CVector speed
= step
* invLODRatio
* emitter
->getSpeed()[emitterIndex
];
999 while (outIt
!= endIt
);
1002 else // compute parametric trajectory
1004 emitter
->integrateSingle(emitter
->getOwner()->getSystemDate() - deltaT
- step
* toProcess
,
1015 ///==========================================================================
1016 void CPSEmitter::processRegularEmissionConsistent(uint firstInstanceIndex
, float emitLOD
, float inverseEmitLOD
)
1018 NL_PS_FUNC(CPSEmitter_processRegularEmissionConsistent
)
1019 /// hmm some code factorisation would do no harm, but we want to keep tests outside the loops as much as possible...
1022 nlassert(_Owner
->getOwner());
1024 const bool emitThreshold
= _Owner
->getOwner()->isEmitThresholdEnabled();
1028 static std::vector
<NLMISC::CVector
> emitterPositions
;
1029 // Positions for the emitter. They are computed by using a parametric trajectory or by using integration
1031 const uint size
= _Owner
->getSize();
1032 nlassert(firstInstanceIndex
< size
);
1033 uint leftToDo
= size
- firstInstanceIndex
, toProcess
;
1034 float emitPeriod
[EMITTER_BUFF_SIZE
];
1035 const float *currEmitPeriod
;
1036 uint currEmitPeriodPtrInc
= _PeriodScheme
? 1 : 0;
1037 sint32 nbToGenerate
;
1040 TPSAttribTime::iterator phaseIt
= _Phase
.begin() + firstInstanceIndex
, endPhaseIt
;
1041 TPSAttribUInt8::iterator numEmitIt
;
1042 if(firstInstanceIndex
< _NumEmission
.getSize())
1044 numEmitIt
= _NumEmission
.begin() + firstInstanceIndex
;
1048 numEmitIt
= _NumEmission
.end();
1052 float ellapsedTimeLOD
= CParticleSystem::EllapsedTime
* emitLOD
;
1053 uint maxEmissionCountLOD
= (uint8
) (_MaxEmissionCount
* emitLOD
);
1054 maxEmissionCountLOD
= std::max(1u, maxEmissionCountLOD
);
1055 // we don't use an iterator here
1056 // because it could be invalidated if size change (a located could generate itself)
1059 toProcess
= leftToDo
< EMITTER_BUFF_SIZE
? leftToDo
: EMITTER_BUFF_SIZE
;
1065 // NB : we ask to clamp entry because life counter of emitter are incremented, then spawn is called, and only after that dead emitters are removed
1066 // so we may have a life counter that is > to 1
1067 currEmitPeriod
= (float *) (_PeriodScheme
->make(_Owner
, size
- leftToDo
, emitPeriod
, sizeof(float), toProcess
, true, 1 << 16, true));
1071 /** Test if 'make' filled our buffer. If this is not the case, we assume that values where precomputed, and that
1072 * all null period have already been replaced by the threshold
1074 if (currEmitPeriod
== emitPeriod
)
1076 // if there possibility to have 0 in the scheme ?
1077 if (_PeriodScheme
->getMinValue() <= 0.f
&& _PeriodScheme
->getMaxValue() >= 0.f
)
1079 replaceNullPeriodsByThreshold(emitPeriod
, toProcess
);
1086 if (_Period
!= 0.f
|| !emitThreshold
)
1088 currEmitPeriod
= &_Period
;
1092 currEmitPeriod
= &EMIT_PERIOD_THRESHOLD
;
1096 endPhaseIt
= phaseIt
+ toProcess
;
1098 if (_MaxEmissionCount
== 0) // no emission count limit
1100 /// is there an emission delay ?
1101 if (_EmitDelay
== 0.f
) // no emission delay
1105 *phaseIt
+= ellapsedTimeLOD
;
1106 if ( *phaseIt
>= *currEmitPeriod
) // phase is greater than period -> must emit
1108 if (*currEmitPeriod
!= 0)
1110 /** Must ensure phase is valid if period decrease over time
1112 *phaseIt
= std::min(*phaseIt
, *currEmitPeriod
+ ellapsedTimeLOD
);
1114 /// compute the number of emissions
1115 uint numEmissions
= (uint
) ::floorf(*phaseIt
/ *currEmitPeriod
);
1116 *phaseIt
-= *currEmitPeriod
* numEmissions
;
1118 uint emitterIndex
= (uint
)(phaseIt
- _Phase
.begin());
1119 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1122 float deltaT
= std::max(0.f
, *phaseIt
);
1124 /// compute the position of the emitter for the needed dates
1125 numEmissions
= GenEmitterPositionsWithLOD(_Owner
,
1135 /// process each emission at the right pos at the right date
1136 nbToGenerate
= (sint32
) (emitLOD
* nbToGenerate
);
1137 if (!nbToGenerate
) nbToGenerate
= 1;
1138 uint k
= numEmissions
;
1139 float deltaTInc
= *currEmitPeriod
* inverseEmitLOD
;
1143 processEmitConsistent(emitterPositions
[k
],
1148 deltaT
+= deltaTInc
;
1155 const uint32 emitterIndex
= (uint32
)(phaseIt
- _Phase
.begin());
1156 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1159 nbToGenerate
= (sint32
) (emitLOD
* nbToGenerate
);
1160 if (!nbToGenerate
) nbToGenerate
= 1;
1161 processEmit(emitterIndex
, nbToGenerate
);
1167 currEmitPeriod
+= currEmitPeriodPtrInc
;
1169 while (phaseIt
!= endPhaseIt
);
1171 else // thhere's an emission delay
1175 if (*phaseIt
< _EmitDelay
)
1177 *phaseIt
+= CParticleSystem::EllapsedTime
;
1178 if (*phaseIt
< _EmitDelay
)
1181 currEmitPeriod
+= currEmitPeriodPtrInc
;
1186 *phaseIt
= (*phaseIt
- _EmitDelay
) * emitLOD
+ _EmitDelay
;
1191 *phaseIt
+= ellapsedTimeLOD
;
1194 if ( *phaseIt
>= *currEmitPeriod
+ _EmitDelay
) // phase is greater than period -> must emit
1196 if (*currEmitPeriod
!= 0)
1198 /** Must ensure phase is valid if period decrease over time
1200 *phaseIt
= std::min(*phaseIt
, *currEmitPeriod
+ ellapsedTimeLOD
+ _EmitDelay
);
1202 uint numEmissions
= (uint
) ::floorf((*phaseIt
- _EmitDelay
) / *currEmitPeriod
);
1203 *phaseIt
-= *currEmitPeriod
* numEmissions
;
1204 float deltaT
= std::max(*phaseIt
- _EmitDelay
, 0.f
);
1205 //nlassert(deltaT >= 0.f);
1206 /// process each emission at the right pos at the right date
1207 uint emitterIndex
= (uint
)(phaseIt
- _Phase
.begin());
1208 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1212 /// compute the position of the emitter for the needed date
1213 numEmissions
= GenEmitterPositionsWithLOD( _Owner
,
1223 nbToGenerate
= (sint32
) (emitLOD
* nbToGenerate
);
1224 if (!nbToGenerate
) nbToGenerate
= 1;
1225 uint k
= numEmissions
;
1226 float deltaTInc
= *currEmitPeriod
* inverseEmitLOD
;
1230 processEmitConsistent(emitterPositions
[k
],
1234 deltaT
+= deltaTInc
;
1241 const uint32 emitterIndex
= (uint32
)(phaseIt
- _Phase
.begin());
1242 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1245 nbToGenerate
= (sint32
) (emitLOD
* nbToGenerate
);
1246 if (!nbToGenerate
) nbToGenerate
= 1;
1247 processEmit(emitterIndex
, nbToGenerate
);
1253 currEmitPeriod
+= currEmitPeriodPtrInc
;
1255 while (phaseIt
!= endPhaseIt
);
1258 else // there's an emission count limit
1260 /// is there an emission delay ?
1261 if (_EmitDelay
== 0.f
) // no emission delay
1265 if (*numEmitIt
< maxEmissionCountLOD
)
1267 *phaseIt
+= ellapsedTimeLOD
;
1268 if ( *phaseIt
>= *currEmitPeriod
) // phase is greater than period -> must emit
1270 if (*currEmitPeriod
!= 0)
1272 /** Must ensure phase is valid if period decrease over time
1274 *phaseIt
= std::min(*phaseIt
, *currEmitPeriod
+ ellapsedTimeLOD
);
1276 uint numEmissions
= (uint
) ::floorf(*phaseIt
/ *currEmitPeriod
);
1277 *numEmitIt
+= numEmissions
;
1278 *phaseIt
-= *currEmitPeriod
* numEmissions
;
1279 float deltaT
= std::max(*phaseIt
, 0.f
);
1280 //nlassert(deltaT >= 0.f);
1281 uint emitterIndex
= (uint
)(phaseIt
- _Phase
.begin());
1282 if (*numEmitIt
> _MaxEmissionCount
) // make sure we don't go over the emission limit
1284 numEmissions
-= *numEmitIt
- _MaxEmissionCount
;
1285 *numEmitIt
= _MaxEmissionCount
;
1287 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1290 /// compute the position of the emitter for the needed date
1291 numEmissions
= GenEmitterPositionsWithLOD(_Owner
,
1300 uint k
= numEmissions
;
1301 /// process each emission at the right pos at the right date
1302 nbToGenerate
= (sint32
) (emitLOD
* nbToGenerate
);
1303 if (!nbToGenerate
) nbToGenerate
= 1;
1304 float deltaTInc
= *currEmitPeriod
* inverseEmitLOD
;
1308 processEmitConsistent(emitterPositions
[k
],
1313 deltaT
+= deltaTInc
;
1320 const uint32 emitterIndex
= (uint32
)(phaseIt
- _Phase
.begin());
1321 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1324 nbToGenerate
= (sint32
) (emitLOD
* nbToGenerate
);
1325 if (!nbToGenerate
) nbToGenerate
= 1;
1326 processEmit(emitterIndex
, nbToGenerate
);
1334 *numEmitIt
= _MaxEmissionCount
; // if the lod change, must ensure that the
1337 currEmitPeriod
+= currEmitPeriodPtrInc
;
1340 while (phaseIt
!= endPhaseIt
);
1342 else // there's an emission delay
1346 if (*numEmitIt
< maxEmissionCountLOD
)
1348 if (*phaseIt
< _EmitDelay
)
1350 *phaseIt
+= CParticleSystem::EllapsedTime
;
1351 if (*phaseIt
< _EmitDelay
)
1354 currEmitPeriod
+= currEmitPeriodPtrInc
;
1360 *phaseIt
= (*phaseIt
- _EmitDelay
) * emitLOD
+ _EmitDelay
;
1365 *phaseIt
+= ellapsedTimeLOD
;
1368 if ( *phaseIt
>= *currEmitPeriod
+ _EmitDelay
) // phase is greater than period -> must emit
1370 if (*currEmitPeriod
!= 0)
1372 /** Must ensure phase is valid if period decrease over time
1374 *phaseIt
= std::min(*phaseIt
, *currEmitPeriod
+ ellapsedTimeLOD
+ _EmitDelay
);
1376 uint numEmissions
= (uint
) ::floorf((*phaseIt
- _EmitDelay
) / *currEmitPeriod
);
1377 *numEmitIt
+= numEmissions
;
1378 *phaseIt
-= *currEmitPeriod
* numEmissions
;
1379 float deltaT
= std::max(*phaseIt
- _EmitDelay
, 0.f
);
1380 //nlassert(deltaT >= 0.f);
1381 uint emitterIndex
= (uint
)(phaseIt
- _Phase
.begin());
1382 if (*numEmitIt
> _MaxEmissionCount
) // make sure we don't go over the emission limit
1384 numEmissions
-= *numEmitIt
- _MaxEmissionCount
;
1385 *numEmitIt
= _MaxEmissionCount
;
1387 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1390 /// compute the position of the emitter for the needed date
1391 numEmissions
= GenEmitterPositionsWithLOD(_Owner
,
1400 uint k
= numEmissions
;
1401 /// process each emission at the right pos at the right date
1402 nbToGenerate
= (sint32
) (emitLOD
* nbToGenerate
);
1403 if (!nbToGenerate
) nbToGenerate
= 1;
1404 float deltaTInc
= *currEmitPeriod
* inverseEmitLOD
;
1408 processEmitConsistent(emitterPositions
[k
],
1412 deltaT
+= deltaTInc
;
1419 const uint32 emitterIndex
= (uint32
)(phaseIt
- _Phase
.begin());
1420 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1423 nbToGenerate
= (sint32
) (emitLOD
* nbToGenerate
);
1424 if (!nbToGenerate
) nbToGenerate
= 1;
1425 processEmit(emitterIndex
, nbToGenerate
);
1433 *numEmitIt
= _MaxEmissionCount
; // if the lod change, must ensure that the
1436 currEmitPeriod
+= currEmitPeriodPtrInc
;
1439 while (phaseIt
!= endPhaseIt
);
1443 leftToDo
-= toProcess
;
1448 ///==========================================================================
1449 void CPSEmitter::processRegularEmissionConsistentWithNoLOD(uint firstInstanceIndex
)
1451 NL_PS_FUNC(CPSEmitter_processRegularEmissionConsistentWithNoLOD
)
1452 /// hum, some code factorization would do no harm, but we want to keep tests outside the loops as much as possible...
1455 nlassert(_Owner
->getOwner());
1457 const bool emitThreshold
= _Owner
->getOwner()->isEmitThresholdEnabled();
1461 static std::vector
<NLMISC::CVector
> emitterPositions
;
1462 // Positions for the emitter. They are computed by using a parametric trajectory or by using integration
1464 const uint size
= _Owner
->getSize();
1465 nlassert(firstInstanceIndex
< size
);
1466 uint leftToDo
= size
- firstInstanceIndex
, toProcess
;
1467 float emitPeriod
[EMITTER_BUFF_SIZE
];
1468 const float *currEmitPeriod
;
1469 uint currEmitPeriodPtrInc
= _PeriodScheme
? 1 : 0;
1470 sint32 nbToGenerate
;
1473 TPSAttribTime::iterator phaseIt
= _Phase
.begin() + firstInstanceIndex
, endPhaseIt
;
1474 TPSAttribUInt8::iterator numEmitIt
;
1475 if (firstInstanceIndex
< _NumEmission
.getSize())
1476 numEmitIt
= _NumEmission
.begin() + firstInstanceIndex
;
1478 numEmitIt
= _NumEmission
.end();
1481 toProcess
= leftToDo
< EMITTER_BUFF_SIZE
? leftToDo
: EMITTER_BUFF_SIZE
;
1487 // NB : we ask to clamp entry because life counter of emitter are incremented, then spawn is called, and only after that dead emitters are removed
1488 // so we may have a life counter that is > to 1
1489 currEmitPeriod
= (float *) (_PeriodScheme
->make(_Owner
, size
- leftToDo
, emitPeriod
, sizeof(float), toProcess
, true, 1 << 16, true));
1493 /** Test if 'make' filled our buffer. If this is not the case, we assume that values where precomputed, and that
1494 * all null period have already been replaced by the threshold
1496 if (currEmitPeriod
== emitPeriod
)
1498 // if there possibility to have 0 in the scheme ?
1499 if (_PeriodScheme
->getMinValue() <= 0.f
&& _PeriodScheme
->getMaxValue() >= 0.f
)
1501 replaceNullPeriodsByThreshold(emitPeriod
, toProcess
);
1508 if (_Period
!= 0.f
|| !emitThreshold
)
1510 currEmitPeriod
= &_Period
;
1514 currEmitPeriod
= &EMIT_PERIOD_THRESHOLD
;
1518 endPhaseIt
= phaseIt
+ toProcess
;
1520 if (_MaxEmissionCount
== 0) // no emission count limit
1522 /// is there an emission delay ?
1523 if (_EmitDelay
== 0.f
) // no emission delay
1527 *phaseIt
+= CParticleSystem::EllapsedTime
;
1528 if ( *phaseIt
>= *currEmitPeriod
) // phase is greater than period -> must emit
1530 if (*currEmitPeriod
!= 0)
1532 /** Must ensure phase is valid if period decrease over time
1534 *phaseIt
= std::min(*phaseIt
, *currEmitPeriod
+ CParticleSystem::EllapsedTime
);
1536 /// compute the number of emissions
1537 uint numEmissions
= (uint
) ::floorf(*phaseIt
/ *currEmitPeriod
);
1538 *phaseIt
-= *currEmitPeriod
* numEmissions
;
1539 float deltaT
= std::max(0.f
, *phaseIt
);
1540 //nlassert(deltaT >= 0.f);
1541 uint emitterIndex
= (uint
)(phaseIt
- _Phase
.begin());
1543 /// compute the position of the emitter for the needed dates
1544 numEmissions
= GenEmitterPositions(_Owner
,
1553 /// process each emission at the right pos at the right date
1554 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1555 uint k
= numEmissions
;
1559 processEmitConsistent(emitterPositions
[k
],
1563 deltaT
+= *currEmitPeriod
;
1569 const uint32 emitterIndex
= (uint32
)(phaseIt
- _Phase
.begin());
1570 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1571 processEmit(emitterIndex
, nbToGenerate
);
1576 currEmitPeriod
+= currEmitPeriodPtrInc
;
1578 while (phaseIt
!= endPhaseIt
);
1580 else // thhere's an emission delay
1584 *phaseIt
+= CParticleSystem::EllapsedTime
;
1585 if ( *phaseIt
>= *currEmitPeriod
+ _EmitDelay
) // phase is greater than period -> must emit
1587 if (*currEmitPeriod
!= 0)
1589 /** Must ensure phase is valid if period decrease over time
1591 *phaseIt
= std::min(*phaseIt
, *currEmitPeriod
+ CParticleSystem::EllapsedTime
+ _EmitDelay
);
1593 uint numEmissions
= (uint
) ::floorf((*phaseIt
- _EmitDelay
) / *currEmitPeriod
);
1594 *phaseIt
-= *currEmitPeriod
* numEmissions
;
1595 float deltaT
= std::max(*phaseIt
- _EmitDelay
, 0.f
);
1596 //nlassert(deltaT >= 0.f);
1598 uint emitterIndex
= (uint
)(phaseIt
- _Phase
.begin());
1599 /// compute the position of the emitter for the needed date
1600 numEmissions
= GenEmitterPositions(_Owner
,
1608 /// process each emission at the right pos at the right date
1609 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1610 uint k
= numEmissions
;
1614 processEmitConsistent(emitterPositions
[k
],
1618 deltaT
+= *currEmitPeriod
;
1624 const uint32 emitterIndex
= (uint32
)(phaseIt
- _Phase
.begin());
1625 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1626 processEmit(emitterIndex
, nbToGenerate
);
1631 currEmitPeriod
+= currEmitPeriodPtrInc
;
1633 while (phaseIt
!= endPhaseIt
);
1636 else // there's an emission count limit
1638 /// is there an emission delay ?
1639 if (_EmitDelay
== 0.f
) // no emission delay
1643 if (*numEmitIt
< _MaxEmissionCount
)
1645 *phaseIt
+= CParticleSystem::EllapsedTime
;
1646 if ( *phaseIt
>= *currEmitPeriod
) // phase is greater than period -> must emit
1648 if (*currEmitPeriod
!= 0)
1650 /** Must ensure phase is valid if period decrease over time
1652 *phaseIt
= std::min(*phaseIt
, *currEmitPeriod
+ CParticleSystem::EllapsedTime
);
1654 uint numEmissions
= (uint
) ::floorf(*phaseIt
/ *currEmitPeriod
);
1655 *numEmitIt
+= numEmissions
;
1656 *phaseIt
-= *currEmitPeriod
* numEmissions
;
1657 float deltaT
= std::max(*phaseIt
, 0.f
);
1658 //nlassert(deltaT >= 0.f);
1659 uint emitterIndex
= (uint
)(phaseIt
- _Phase
.begin());
1660 if (*numEmitIt
> _MaxEmissionCount
) // make sure we don't go over the emission limit
1662 numEmissions
-= *numEmitIt
- _MaxEmissionCount
;
1663 *numEmitIt
= _MaxEmissionCount
;
1665 /// compute the position of the emitter for the needed date
1666 numEmissions
= GenEmitterPositions(_Owner
,
1674 uint k
= numEmissions
;
1675 /// process each emission at the right pos at the right date
1676 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1680 processEmitConsistent(emitterPositions
[k
],
1684 deltaT
+= *currEmitPeriod
;
1690 const uint32 emitterIndex
= (uint32
)(phaseIt
- _Phase
.begin());
1691 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1692 processEmit(emitterIndex
, nbToGenerate
);
1698 currEmitPeriod
+= currEmitPeriodPtrInc
;
1701 while (phaseIt
!= endPhaseIt
);
1703 else // there's an emission delay
1707 if (*numEmitIt
< _MaxEmissionCount
)
1709 *phaseIt
+= CParticleSystem::EllapsedTime
;
1710 if ( *phaseIt
>= *currEmitPeriod
+ _EmitDelay
) // phase is greater than period -> must emit
1712 if (*currEmitPeriod
!= 0)
1714 /** Must ensure phase is valid if period decrease over time
1716 *phaseIt
= std::min(*phaseIt
, *currEmitPeriod
+ CParticleSystem::EllapsedTime
+ _EmitDelay
);
1718 uint numEmissions
= (uint
) ::floorf((*phaseIt
- _EmitDelay
) / *currEmitPeriod
);
1719 *numEmitIt
+= numEmissions
;
1720 *phaseIt
-= *currEmitPeriod
* numEmissions
;
1721 float deltaT
= std::max(*phaseIt
- _EmitDelay
, 0.f
);
1722 //nlassert(deltaT >= 0.f);
1723 uint emitterIndex
= (uint
)(phaseIt
- _Phase
.begin());
1724 if (*numEmitIt
> _MaxEmissionCount
) // make sure we don't go over the emission limit
1726 numEmissions
-= *numEmitIt
- _MaxEmissionCount
;
1727 *numEmitIt
= _MaxEmissionCount
;
1729 /// compute the position of the emitter for the needed date
1730 numEmissions
= GenEmitterPositions(_Owner
,
1738 uint k
= numEmissions
;
1739 /// process each emission at the right pos at the right date
1740 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1744 processEmitConsistent(emitterPositions
[k
],
1748 deltaT
+= *currEmitPeriod
;
1754 const uint32 emitterIndex
= (uint32
)(phaseIt
- _Phase
.begin());
1755 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, emitterIndex
) : _GenNb
;
1756 processEmit(emitterIndex
, nbToGenerate
);
1762 currEmitPeriod
+= currEmitPeriodPtrInc
;
1765 while (phaseIt
!= endPhaseIt
);
1769 leftToDo
-= toProcess
;
1775 ///==========================================================================
1776 void CPSEmitter::step(TPSProcessPass pass
)
1778 NL_PS_FUNC(CPSEmitter_step
)
1779 if (pass
== PSToolRender
)
1785 ///==========================================================================
1786 void CPSEmitter::computeSpawns(uint firstInstanceIndex
)
1788 NL_PS_FUNC(CPSEmitter_computeSpawns
)
1789 if (!_EmittedType
) return;
1790 nlassert(CParticleSystem::InsideSimLoop
);
1791 const uint32 size
= _Owner
->getSize();
1793 if (CParticleSystem::EllapsedTime
== 0.f
) return; // do nothing when paused
1794 CParticleSystem
*ps
= _Owner
->getOwner();
1797 if (ps
->isAutoLODEnabled() && !ps
->isSharingEnabled() && !_BypassAutoLOD
)
1799 // temp test for auto lod
1800 emitLOD
= ps
->getAutoLODEmitRatio();
1806 nlassert(_EmissionType
== CPSEmitter::regular
);
1807 if (!_ConsistentEmission
)
1811 processRegularEmission(firstInstanceIndex
, emitLOD
);
1815 processRegularEmissionWithNoLOD(firstInstanceIndex
);
1824 processRegularEmissionConsistent(firstInstanceIndex
, emitLOD
, 1.f
/ emitLOD
);
1829 processRegularEmissionConsistentWithNoLOD(firstInstanceIndex
);
1835 ///==========================================================================
1836 void CPSEmitter::newElement(const CPSEmitterInfo
&info
)
1838 NL_PS_FUNC(CPSEmitter_newElement
)
1839 nlassert(_Phase
.getSize() != _Phase
.getMaxSize());
1842 if (_MaxEmissionCount
!= 0)
1844 _NumEmission
.insert(0);
1846 if (_PeriodScheme
&& _PeriodScheme
->hasMemory()) _PeriodScheme
->newElement(info
);
1847 if (_GenNbScheme
&& _GenNbScheme
->hasMemory()) _GenNbScheme
->newElement(info
);
1851 ///==========================================================================
1852 inline void CPSEmitter::deleteElementBase(uint32 index
)
1854 NL_PS_FUNC(CPSEmitter_deleteElementBase
)
1855 if (_PeriodScheme
&& _PeriodScheme
->hasMemory()) _PeriodScheme
->deleteElement(index
);
1856 if (_GenNbScheme
&& _GenNbScheme
->hasMemory()) _GenNbScheme
->deleteElement(index
);
1857 _Phase
.remove(index
);
1858 if (_MaxEmissionCount
!= 0)
1860 _NumEmission
.remove(index
);
1864 ///==========================================================================
1865 void CPSEmitter::deleteElement(uint32 index
)
1867 NL_PS_FUNC(CPSEmitter_deleteElement
)
1869 if (_EmissionType
== CPSEmitter::onDeath
&& _EmittedType
&& _Active
)
1871 if (!_BypassEmitOnDeath
)
1873 const uint32 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, index
) : _GenNb
;
1874 processEmitOutsideSimLoop(index
, nbToGenerate
);
1877 deleteElementBase(index
);
1880 ///==========================================================================
1881 void CPSEmitter::deleteElement(uint32 index
, TAnimationTime timeUntilNextSimStep
)
1883 NL_PS_FUNC(CPSEmitter_deleteElement
)
1884 if (_EmissionType
== CPSEmitter::onDeath
&& _EmittedType
&& _Active
)
1886 const uint32 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, index
) : _GenNb
;
1887 processEmitConsistent(_Owner
->getPos()[index
], index
, nbToGenerate
, timeUntilNextSimStep
);
1889 deleteElementBase(index
);
1893 ///==========================================================================
1894 void CPSEmitter::resize(uint32 size
)
1896 NL_PS_FUNC(CPSEmitter_resize
)
1897 nlassert(size
< (1 << 16));
1898 if (_PeriodScheme
&& _PeriodScheme
->hasMemory()) _PeriodScheme
->resize(size
, _Owner
->getSize());
1899 if (_GenNbScheme
&& _GenNbScheme
->hasMemory()) _GenNbScheme
->resize(size
, _Owner
->getSize());
1900 _Phase
.resize(size
);
1901 if (_MaxEmissionCount
!= 0)
1903 _NumEmission
.resize(size
);
1907 ///==========================================================================
1908 void CPSEmitter::bounceOccurred(uint32 index
, TAnimationTime timeToNextSimStep
)
1910 NL_PS_FUNC(CPSEmitter_bounceOccurred
)
1911 // TODO : avoid duplication with deleteElement
1912 if (_EmittedType
&& _EmissionType
== CPSEmitter::onBounce
)
1914 const uint32 nbToGenerate
= _GenNbScheme
? _GenNbScheme
->get(_Owner
, index
) : _GenNb
;
1915 processEmitConsistent(_Owner
->getPos()[index
], index
, nbToGenerate
, timeToNextSimStep
);
1919 ///==========================================================================
1920 void CPSEmitter::serial(NLMISC::IStream
&f
)
1922 NL_PS_FUNC(CPSEmitter_serial
)
1923 /// version 6 : the flag _EmitDirBasis no longer exist, it has been replaced by _UserMatrixModeForEmissionDirection
1925 /// version 5 : added _BypassAutoLOD
1926 /// version 4 : added consistent emissions
1927 sint ver
= f
.serialVersion(6);
1928 CPSLocatedBindable::serial(f
);
1930 f
.serialPolyPtr(_EmittedType
);
1932 f
.serial(_SpeedInheritanceFactor
);
1934 bool speedBasisEmission
= _SpeedBasisEmission
; // tmp copy because of bitfield serialization scheme
1935 f
.serial(speedBasisEmission
);
1936 _SpeedBasisEmission
= speedBasisEmission
;
1938 f
.serialEnum(_EmissionType
);
1940 // this is for use with serial
1941 bool trueB
= true, falseB
= false;
1945 switch (_EmissionType
)
1947 case CPSEmitter::regular
:
1951 f
.serialPolyPtr(_PeriodScheme
);
1960 f
.serial(_EmitDelay
, _MaxEmissionCount
);
1969 f
.serialPolyPtr(_GenNbScheme
);
1980 switch (_EmissionType
)
1982 case CPSEmitter::regular
:
1984 f
.serial(useScheme
);
1987 delete _PeriodScheme
;
1988 f
.serialPolyPtr(_PeriodScheme
);
1996 f
.serial(_EmitDelay
, _MaxEmissionCount
);
1997 updateMaxCountVect();
2005 f
.serial(useScheme
);
2008 delete _GenNbScheme
;
2009 f
.serialPolyPtr(_GenNbScheme
);
2016 if (ver
> 1 && ver
< 6)
2018 nlassert(f
.isReading());
2020 f
.serial(emitDirBasis
);
2023 _UserMatrixModeForEmissionDirection
= false;
2024 _UserDirectionMatrixMode
= PSFXWorldMatrix
;
2028 _UserMatrixModeForEmissionDirection
= true;
2031 _UserDirectionMatrixMode
= _Owner
->getMatrixMode() == PSFXWorldMatrix
? PSIdentityMatrix
: PSFXWorldMatrix
;
2035 _UserDirectionMatrixMode
= PSFXWorldMatrix
;
2041 bool consistentEmission
= _ConsistentEmission
; // tmp copy because of bitfield serialization scheme
2042 f
.serial(consistentEmission
);
2043 _ConsistentEmission
= consistentEmission
;
2047 bool byassAutoLOD
= _BypassAutoLOD
; // tmp copy because of bitfield serialization scheme
2048 f
.serial(byassAutoLOD
);
2049 _BypassAutoLOD
= byassAutoLOD
;
2053 bool userMatrixModeForEmissionDirection
= _UserMatrixModeForEmissionDirection
; // tmp copy because of bitfield serialization scheme
2054 f
.serial(userMatrixModeForEmissionDirection
);
2055 _UserMatrixModeForEmissionDirection
= userMatrixModeForEmissionDirection
;
2056 f
.serialEnum(_UserDirectionMatrixMode
);
2060 ///==========================================================================
2061 void CPSEmitter::updateMaxCountVect()
2063 NL_PS_FUNC(CPSEmitter_updateMaxCountVect
)
2064 if (!_MaxEmissionCount
|| !_Owner
)
2066 _NumEmission
.resize(0);
2070 _NumEmission
.resize(_Owner
->getMaxSize());
2071 while (_NumEmission
.getSize() != 0)
2073 _NumEmission
.remove(0);
2075 while (_NumEmission
.getSize() != _Owner
->getSize())
2077 _NumEmission
.insert(0);
2082 ///==========================================================================
2083 void CPSEmitter::setEmitDelay(float delay
)
2085 NL_PS_FUNC(CPSEmitter_setEmitDelay
)
2087 if (_Owner
&& _Owner
->getOwner())
2089 _Owner
->getOwner()->systemDurationChanged();
2093 ///==========================================================================
2094 bool CPSEmitter::setMaxEmissionCount(uint8 count
)
2096 NL_PS_FUNC(CPSEmitter_setMaxEmissionCount
)
2097 if (count
== _MaxEmissionCount
) return true;
2098 nlassert(_Owner
&& _Owner
->getOwner());
2099 CParticleSystem
*ps
= _Owner
->getOwner();
2100 if (ps
->getBypassMaxNumIntegrationSteps())
2102 uint8 oldEmissiontCount
= _MaxEmissionCount
;
2103 // should check that the new value is valid
2104 _MaxEmissionCount
= count
;
2105 if (testEmitForever())
2107 _MaxEmissionCount
= oldEmissiontCount
;
2108 nlwarning("<CPSEmitter::setMaxEmissionCount> can't set max emission count to %d \
2109 with the current configuration : the system has been flagged with \
2110 'BypassMaxNumIntegrationSteps', and should have a finite duration. \
2111 The new value is not set", (int) count
);
2115 ps
->systemDurationChanged();
2116 _MaxEmissionCount
= count
;
2117 updateMaxCountVect();
2121 ///==========================================================================
2122 bool CPSEmitter::checkLoop() const
2124 NL_PS_FUNC(CPSEmitter_checkLoop
)
2126 nlassert(_Owner
->getOwner());
2127 if (!_EmittedType
) return false;
2128 std::set
<const CPSLocated
*> seenLocated
; // the located we've already seen
2129 std::vector
<const CPSLocated
*> leftLoc(1); // the located that are left to see
2130 leftLoc
[0] = _EmittedType
;
2133 const CPSLocated
*curr
= leftLoc
.back();
2134 if (curr
== this->_Owner
) return true;
2136 seenLocated
.insert(curr
);
2137 for(uint32 k
= 0; k
< curr
->getNbBoundObjects(); ++k
)
2139 const CPSEmitter
*emitter
= dynamic_cast<const CPSEmitter
*>(curr
->getBoundObject(k
));
2140 if (emitter
&& emitter
->_EmittedType
)
2142 if (seenLocated
.find(emitter
->_EmittedType
) == seenLocated
.end()) // not already seen this one ?
2144 leftLoc
.push_back(emitter
->_EmittedType
);
2149 while (!leftLoc
.empty());
2153 ///==========================================================================
2154 bool CPSEmitter::testEmitForever() const
2156 NL_PS_FUNC(CPSEmitter_testEmitForever
)
2159 nlwarning("<CPSEmitter::testEmitForever> The emitter should be inserted in a CPSLocated instance for this call to work.");
2163 if (!_Owner
->getLastForever()) return false;
2164 switch(getEmissionType())
2166 case CPSEmitter::onBounce
:
2167 case CPSEmitter::externEmit
:
2168 case CPSEmitter::regular
:
2169 // it is ok only if a limited number of located is emitted
2170 if (getMaxEmissionCount() == 0) return true;
2172 case CPSEmitter::onDeath
: return true; // the emitter never dies, so ..
2173 case CPSEmitter::once
: return false;
2176 nlassert(0); // not a known type
2183 ////////////////////////////////////////////
2184 // implementation of CPSModulatedEmitter //
2185 ////////////////////////////////////////////
2187 void CPSModulatedEmitter::serialEmitteeSpeedScheme(NLMISC::IStream
&f
)
2189 NL_PS_FUNC(CPSModulatedEmitter_IStream
)
2193 useScheme
= useEmitteeSpeedScheme();
2195 f
.serial(useScheme
);
2198 f
.serialPolyPtr(_EmitteeSpeedScheme
);
2202 f
.serial(_EmitteeSpeed
);
2208 ////////////////////////////////////////////
2209 // implementation of CPSEmitterOmni //
2210 ////////////////////////////////////////////
2212 ///==========================================================================
2213 void CPSEmitterOmni::emit(const NLMISC::CVector
&srcPos
, uint32 index
, CVector
&pos
, CVector
&speed
)
2215 NL_PS_FUNC(CPSEmitterOmni_emit
)
2216 // TODO : verifier que ca marche si une particule s'emet elle-mem
2217 nlassert(_EmittedType
);
2219 CVector
v( ((rand() % 1000) - 500) / 500.0f
2220 , ((rand() % 1000) - 500) / 500.0f
2221 , ((rand() % 1000) - 500) / 500.0f
);
2223 v
*= _EmitteeSpeedScheme
? _EmitteeSpeedScheme
->get(_Owner
, index
) : _EmitteeSpeed
;
2230 ///==========================================================================
2231 void CPSEmitterOmni::serial(NLMISC::IStream
&f
)
2233 NL_PS_FUNC(CPSEmitterOmni_serial
)
2235 CPSEmitter::serial(f
);
2236 CPSModulatedEmitter::serialEmitteeSpeedScheme(f
);
2239 ///==========================================================================
2240 void CPSEmitterOmni::newElement(const CPSEmitterInfo
&info
)
2242 NL_PS_FUNC(CPSEmitterOmni_newElement
)
2243 CPSEmitter::newElement(info
);
2244 newEmitteeSpeedElement(info
);
2247 ///==========================================================================
2248 inline void CPSEmitterOmni::deleteElementBase(uint32 index
)
2250 NL_PS_FUNC(CPSEmitterOmni_deleteElementBase
)
2251 deleteEmitteeSpeedElement(index
);
2254 ///==========================================================================
2255 void CPSEmitterOmni::deleteElement(uint32 index
, TAnimationTime timeUntilNextSimStep
)
2257 NL_PS_FUNC(CPSEmitterOmni_deleteElement
)
2258 CPSEmitter::deleteElement(index
, timeUntilNextSimStep
);
2259 deleteElementBase(index
);
2262 ///==========================================================================
2263 void CPSEmitterOmni::deleteElement(uint32 index
)
2265 NL_PS_FUNC(CPSEmitterOmni_deleteElement
)
2266 CPSEmitter::deleteElement(index
);
2267 deleteElementBase(index
);
2270 ///==========================================================================
2271 void CPSEmitterOmni::resize(uint32 capacity
)
2273 NL_PS_FUNC(CPSEmitterOmni_resize
)
2274 nlassert(capacity
< (1 << 16));
2275 CPSEmitter::resize(capacity
);
2276 resizeEmitteeSpeed(capacity
);
2279 ///==========================================================================
2280 void CPSEmitterDirectionnal::emit(const NLMISC::CVector
&srcPos
, uint32 index
, CVector
&pos
, CVector
&speed
)
2282 NL_PS_FUNC(CPSEmitterDirectionnal_emit
)
2283 // TODO : verifier que ca marche si une particule s'emet elle-mem
2284 nlassert(_EmittedType
);
2287 speed
= (_EmitteeSpeedScheme
? _EmitteeSpeedScheme
->get(_Owner
, index
) : _EmitteeSpeed
) * _Dir
;
2291 ///==========================================================================
2292 void CPSEmitterDirectionnal::newElement(const CPSEmitterInfo
&info
)
2294 NL_PS_FUNC(CPSEmitterDirectionnal_newElement
)
2295 CPSEmitter::newElement(info
);
2296 newEmitteeSpeedElement(info
);
2300 ///==========================================================================
2301 inline void CPSEmitterDirectionnal::deleteElementBase(uint32 index
)
2303 NL_PS_FUNC(CPSEmitterDirectionnal_deleteElementBase
)
2304 deleteEmitteeSpeedElement(index
);
2307 ///==========================================================================
2308 void CPSEmitterDirectionnal::deleteElement(uint32 index
, TAnimationTime timeUntilNextSimStep
)
2310 NL_PS_FUNC(CPSEmitterDirectionnal_deleteElement
)
2311 CPSEmitter::deleteElement(index
, timeUntilNextSimStep
);
2312 deleteElementBase(index
);
2315 ///==========================================================================
2316 void CPSEmitterDirectionnal::deleteElement(uint32 index
)
2318 NL_PS_FUNC(CPSEmitterDirectionnal_deleteElement
)
2319 CPSEmitter::deleteElement(index
);
2320 deleteElementBase(index
);
2325 ///==========================================================================
2326 void CPSEmitterDirectionnal::resize(uint32 capacity
)
2328 NL_PS_FUNC(CPSEmitterDirectionnal_resize
)
2329 nlassert(capacity
< (1 << 16));
2330 CPSEmitter::resize(capacity
);
2331 resizeEmitteeSpeed(capacity
);
2334 ///==========================================================================
2335 void CPSEmitterDirectionnal::serial(NLMISC::IStream
&f
)
2337 NL_PS_FUNC(CPSEmitterDirectionnal_IStream
)
2339 CPSEmitter::serial(f
);
2340 CPSModulatedEmitter::serialEmitteeSpeedScheme(f
);
2344 ////////////////////////////////////////////
2345 // implementation of CPSEmitterRectangle //
2346 ////////////////////////////////////////////
2348 ///==========================================================================
2349 void CPSEmitterRectangle::serial(NLMISC::IStream
&f
)
2351 NL_PS_FUNC(CPSEmitterRectangle_IStream
)
2353 CPSEmitter::serial(f
);
2354 CPSModulatedEmitter::serialEmitteeSpeedScheme(f
);
2362 ///==========================================================================
2363 void CPSEmitterRectangle::emit(const NLMISC::CVector
&srcPos
, uint32 index
, CVector
&pos
, CVector
&speed
)
2365 NL_PS_FUNC(CPSEmitterRectangle_emit
)
2366 CVector N
= _Basis
[index
].X
^ _Basis
[index
].Y
;
2367 pos
= srcPos
+ ((rand() % 32000) * (1.f
/ 16000) - 1.f
) * _Width
[index
] * _Basis
[index
].X
2368 + ((rand() % 32000) * (1.f
/ 16000) - 1.f
) * _Height
[index
] * _Basis
[index
].Y
;
2369 speed
= (_EmitteeSpeedScheme
? _EmitteeSpeedScheme
->get(_Owner
, index
) : _EmitteeSpeed
)
2370 * (_Dir
.x
* _Basis
[index
].X
+ _Dir
.y
* _Basis
[index
].Y
+ _Dir
.z
* N
);
2373 ///==========================================================================
2374 void CPSEmitterRectangle::setMatrix(uint32 index
, const CMatrix
&m
)
2376 NL_PS_FUNC(CPSEmitterRectangle_setMatrix
)
2377 _Owner
->getPos()[index
] = m
.getPos();
2380 _Basis
[index
].X
= m
.getI();
2381 _Basis
[index
].Y
= m
.getJ();
2384 ///==========================================================================
2385 CMatrix
CPSEmitterRectangle::getMatrix(uint32 index
) const
2387 NL_PS_FUNC(CPSEmitterRectangle_getMatrix
)
2389 m
.setPos(_Owner
->getPos()[index
]);
2390 m
.setRot(_Basis
[index
].X
, _Basis
[index
].Y
, _Basis
[index
].X
^ _Basis
[index
].Y
, true);
2394 ///==========================================================================
2395 void CPSEmitterRectangle::setScale(uint32 index
, float scale
)
2397 NL_PS_FUNC(CPSEmitterRectangle_setScale
)
2398 _Width
[index
] = scale
;
2399 _Height
[index
] = scale
;
2402 ///==========================================================================
2403 void CPSEmitterRectangle::setScale(uint32 index
, const CVector
&s
)
2405 NL_PS_FUNC(CPSEmitterRectangle_setScale
)
2406 _Width
[index
] = s
.x
;
2407 _Height
[index
] = s
.y
;
2410 ///==========================================================================
2411 CVector
CPSEmitterRectangle::getScale(uint32 index
) const
2413 NL_PS_FUNC(CPSEmitterRectangle_getScale
)
2414 return CVector(_Width
[index
], _Height
[index
], 1.f
);
2417 ///==========================================================================
2418 void CPSEmitterRectangle::newElement(const CPSEmitterInfo
&info
)
2420 NL_PS_FUNC( CPSEmitterRectangle_newElement
)
2421 CPSEmitter::newElement(info
);
2422 newEmitteeSpeedElement(info
);
2423 _Basis
.insert(CPlaneBasis(CVector::K
));
2425 _Height
.insert(1.f
);
2428 ///==========================================================================
2429 inline void CPSEmitterRectangle::deleteElementBase(uint32 index
)
2431 NL_PS_FUNC(CPSEmitterRectangle_deleteElementBase
)
2432 deleteEmitteeSpeedElement(index
);
2433 _Basis
.remove(index
);
2434 _Width
.remove(index
);
2435 _Height
.remove(index
);
2438 ///==========================================================================
2439 void CPSEmitterRectangle::deleteElement(uint32 index
)
2441 NL_PS_FUNC(CPSEmitterRectangle_deleteElement
)
2442 CPSEmitter::deleteElement(index
);
2443 deleteElementBase(index
);
2446 ///==========================================================================
2447 void CPSEmitterRectangle::deleteElement(uint32 index
, TAnimationTime timeUntilNextSimStep
)
2449 NL_PS_FUNC(CPSEmitterRectangle_deleteElement
)
2450 CPSEmitter::deleteElement(index
, timeUntilNextSimStep
);
2451 deleteElementBase(index
);
2454 ///==========================================================================
2455 void CPSEmitterRectangle::resize(uint32 size
)
2457 NL_PS_FUNC(CPSEmitterRectangle_resize
)
2458 nlassert(size
< (1 << 16));
2459 CPSEmitter::resize(size
);
2460 resizeEmitteeSpeed(size
);
2461 _Basis
.resize(size
);
2462 _Width
.resize(size
);
2463 _Height
.resize(size
);
2466 ///==========================================================================
2467 void CPSEmitterRectangle::showTool(void)
2469 NL_PS_FUNC(CPSEmitterRectangle_showTool
)
2471 const uint size
= _Owner
->getSize();
2473 setupDriverModelMatrix();
2478 CPSLocatedBindable
*lb
;
2479 _Owner
->getOwner()->getCurrentEditedElement(loc
, index
, lb
);
2481 for (uint k
= 0; k
< size
; ++k
)
2483 const CVector
&I
= _Basis
[k
].X
;
2484 const CVector
&J
= _Basis
[k
].Y
;
2485 mat
.setRot(I
, J
, I
^J
);
2486 mat
.setPos(_Owner
->getPos()[k
]);
2487 CPSUtil::displayBasis(getDriver() ,getLocalToWorldMatrix(), mat
, 1.f
, *getFontGenerator(), *getFontManager());
2488 setupDriverModelMatrix();
2490 const CRGBA col
= ((lb
== NULL
|| this == lb
) && loc
== _Owner
&& index
== k
? CRGBA::Red
: CRGBA(127, 127, 127));
2494 const CVector
&pos
= _Owner
->getPos()[k
];
2495 CPSUtil::display3DQuad(*getDriver(), pos
+ I
* _Width
[k
] + J
* _Height
[k
]
2496 , pos
+ I
* _Width
[k
] - J
* _Height
[k
]
2497 , pos
- I
* _Width
[k
] - J
* _Height
[k
]
2498 , pos
- I
* _Width
[k
] + J
* _Height
[k
], col
);
2504 ////////////////////////////////////
2505 // CPSEmitterconic implementation //
2506 ////////////////////////////////////
2508 ///==========================================================================
2509 void CPSEmitterConic::serial(NLMISC::IStream
&f
)
2511 NL_PS_FUNC(CPSEmitterConic_serial
)
2513 CPSEmitterDirectionnal::serial(f
);
2517 ///==========================================================================
2518 void CPSEmitterConic::setDir(const CVector
&v
)
2520 NL_PS_FUNC(CPSEmitterConic_setDir
)
2521 CPSEmitterDirectionnal::setDir(v
);
2525 ///==========================================================================
2526 void CPSEmitterConic::emit(const NLMISC::CVector
&srcPos
, uint32 index
, CVector
&pos
, CVector
&speed
)
2528 NL_PS_FUNC(CPSEmitterConic_emit
)
2529 // TODO : optimize that
2530 nlassert(_EmittedType
);
2532 // we choose a custom direction like with omnidirectionnal emitter
2533 // then we force the direction vect to have the unit size
2535 static const double divRand
= (2.0 / RAND_MAX
);
2537 CVector
dir((float) (rand() * divRand
- 1)
2538 , (float) (rand() * divRand
- 1)
2539 , (float) (rand() * divRand
- 1) );
2541 const float n
=dir
.norm();
2545 dir
-= (_Dir
* dir
) * _Dir
;
2550 speed
= (_EmitteeSpeedScheme
? _EmitteeSpeedScheme
->get(_Owner
, index
) : _EmitteeSpeed
)
2555 ////////////////////////////////////////
2556 // CPSSphericalEmitter implementation //
2557 ////////////////////////////////////////
2559 ///==========================================================================
2560 void CPSSphericalEmitter::emit(const NLMISC::CVector
&srcPos
, uint32 index
, CVector
&pos
, CVector
&speed
)
2562 NL_PS_FUNC(CPSSphericalEmitter_emit
)
2563 static const double divRand
= (2.0 / RAND_MAX
);
2564 CVector
dir((float) (rand() * divRand
- 1), (float) (rand() * divRand
- 1) , (float) (rand() * divRand
- 1) );
2566 pos
= srcPos
+ _Radius
[index
] * dir
;
2567 speed
= (_EmitteeSpeedScheme
? _EmitteeSpeedScheme
->get(_Owner
, index
) : _EmitteeSpeed
) * dir
;
2571 ///==========================================================================
2572 void CPSSphericalEmitter::showTool(void)
2574 NL_PS_FUNC(CPSSphericalEmitter_showTool
)
2577 CPSLocatedBindable
*lb
;
2578 _Owner
->getOwner()->getCurrentEditedElement(loc
, index
, lb
);
2581 TPSAttribFloat::const_iterator radiusIt
= _Radius
.begin();
2582 TPSAttribVector::const_iterator posIt
= _Owner
->getPos().begin(), endPosIt
= _Owner
->getPos().end();
2583 setupDriverModelMatrix();
2584 for (uint k
= 0; posIt
!= endPosIt
; ++posIt
, ++radiusIt
, ++k
)
2586 const CRGBA col
= ((lb
== NULL
|| this == lb
) && loc
== _Owner
&& index
== k
? CRGBA::Red
: CRGBA(127, 127, 127));
2587 CPSUtil::displaySphere(*getDriver(), *radiusIt
, *posIt
, 5, col
);
2592 ///==========================================================================
2593 void CPSSphericalEmitter::setMatrix(uint32 index
, const CMatrix
&m
)
2595 NL_PS_FUNC(CPSSphericalEmitter_setMatrix
)
2596 nlassert(index
< _Radius
.getSize());
2598 _Owner
->getPos()[index
] = m
.getPos();
2602 ///==========================================================================
2603 CMatrix
CPSSphericalEmitter::getMatrix(uint32 index
) const
2605 NL_PS_FUNC(CPSSphericalEmitter_getMatrix
)
2606 nlassert(index
< _Radius
.getSize());
2609 m
.translate(_Owner
->getPos()[index
]);
2613 ///==========================================================================
2614 void CPSSphericalEmitter::serial(NLMISC::IStream
&f
)
2616 NL_PS_FUNC(CPSSphericalEmitter_serial
)
2618 CPSEmitter::serial(f
);
2619 CPSModulatedEmitter::serialEmitteeSpeedScheme(f
);
2623 ///==========================================================================
2624 void CPSSphericalEmitter::newElement(const CPSEmitterInfo
&info
)
2626 NL_PS_FUNC(CPSSphericalEmitter_newElement
)
2627 CPSEmitter::newElement(info
);
2628 newEmitteeSpeedElement(info
);
2629 _Radius
.insert(1.f
);
2632 ///==========================================================================
2633 inline void CPSSphericalEmitter::deleteElementBase(uint32 index
)
2635 NL_PS_FUNC(CPSSphericalEmitter_deleteElementBase
)
2636 deleteEmitteeSpeedElement(index
);
2637 _Radius
.remove(index
);
2640 ///==========================================================================
2641 void CPSSphericalEmitter::deleteElement(uint32 index
)
2643 NL_PS_FUNC(CPSSphericalEmitter_deleteElement
)
2644 CPSEmitter::deleteElement(index
);
2645 deleteElementBase(index
);
2648 ///==========================================================================
2649 void CPSSphericalEmitter::deleteElement(uint32 index
, TAnimationTime timeUntilNextSimStep
)
2651 NL_PS_FUNC(CPSSphericalEmitter_deleteElement
)
2652 CPSEmitter::deleteElement(index
, timeUntilNextSimStep
);
2653 deleteElementBase(index
);
2656 ///==========================================================================
2657 void CPSSphericalEmitter::resize(uint32 size
)
2659 NL_PS_FUNC(CPSSphericalEmitter_resize
)
2660 nlassert(size
< (1 << 16));
2661 CPSEmitter::resize(size
);
2662 resizeEmitteeSpeed(size
);
2663 _Radius
.resize(size
);
2666 /////////////////////////////////////
2667 // CPSRadialEmitter implementation //
2668 /////////////////////////////////////
2670 ///==========================================================================
2671 void CPSRadialEmitter::serial(NLMISC::IStream
&f
)
2673 NL_PS_FUNC(CPSRadialEmitter_serial
)
2675 CPSEmitterDirectionnal::serial(f
);
2678 ///==========================================================================
2679 void CPSRadialEmitter::emit(const NLMISC::CVector
&srcPos
, uint32 index
, NLMISC::CVector
&pos
, NLMISC::CVector
&speed
)
2681 NL_PS_FUNC(CPSRadialEmitter_emit
)
2682 // TODO : verify if it works when a particle emits itself
2683 nlassert(_EmittedType
);
2685 static const double divRand
= (2.0 / RAND_MAX
);
2686 CVector
dir((float) (rand() * divRand
- 1),
2687 (float) (rand() * divRand
- 1),
2688 (float) (rand() * divRand
- 1) );
2689 dir
-= (dir
* _Dir
) * _Dir
; //keep tangential direction
2691 speed
= (_EmitteeSpeedScheme
? _EmitteeSpeedScheme
->get(_Owner
, index
) : _EmitteeSpeed
) * dir
;
2696 ///===============================================================================
2697 void CPSEmitter::enableSpeedBasisEmission(bool enabled
/*=true*/)
2699 NL_PS_FUNC(CPSEmitter_enableSpeedBasisEmission
)
2700 bool wasUserMatNeeded
= isUserMatrixUsed();
2701 _SpeedBasisEmission
= enabled
;
2702 updatePSRefCountForUserMatrixUsage(isUserMatrixUsed(), wasUserMatNeeded
);
2705 ///===============================================================================
2706 void CPSEmitter::enableUserMatrixModeForEmissionDirection(bool enable
/*=true*/)
2708 NL_PS_FUNC(CPSEmitter_enableUserMatrixModeForEmissionDirection
)
2709 bool wasUserMatNeeded
= isUserMatrixUsed();
2710 _UserMatrixModeForEmissionDirection
= enable
;
2711 updatePSRefCountForUserMatrixUsage(isUserMatrixUsed(), wasUserMatNeeded
);
2714 ///===============================================================================
2715 void CPSEmitter::setUserMatrixModeForEmissionDirection(TPSMatrixMode matrixMode
)
2717 NL_PS_FUNC(CPSEmitter_setUserMatrixModeForEmissionDirection
)
2718 bool wasUserMatNeeded
= isUserMatrixUsed();
2719 _UserDirectionMatrixMode
= matrixMode
;
2720 updatePSRefCountForUserMatrixUsage(isUserMatrixUsed(), wasUserMatNeeded
);
2724 ///==========================================================================
2725 void CPSEmitter::updatePSRefCountForUserMatrixUsage(bool matrixIsNeededNow
, bool matrixWasNeededBefore
)
2727 NL_PS_FUNC(CPSEmitter_updatePSRefCountForUserMatrixUsage
)
2728 if (_Owner
&& _Owner
->getOwner())
2730 if (matrixIsNeededNow
&& !matrixWasNeededBefore
)
2732 _Owner
->getOwner()->addRefForUserSysCoordInfo();
2734 else if (!matrixIsNeededNow
&& matrixWasNeededBefore
)
2736 _Owner
->getOwner()->releaseRefForUserSysCoordInfo();
2741 ///==========================================================================
2742 bool CPSEmitter::isUserMatrixUsed() const
2744 NL_PS_FUNC(CPSEmitter_isUserMatrixUsed
)
2745 return !_SpeedBasisEmission
&& _UserMatrixModeForEmissionDirection
&& _UserDirectionMatrixMode
== PSUserMatrix
;
2748 ///==========================================================================
2749 bool CPSEmitter::getUserMatrixUsageCount() const
2751 NL_PS_FUNC(CPSEmitter_getUserMatrixUsageCount
)
2752 return isUserMatrixUsed() ? 1 : 0;
2757 ///==========================================================================
2758 void CPSEmitter::doEmitOnce(uint firstInstanceIndex
)
2760 NL_PS_FUNC(CPSEmitter_doEmitOnce
)
2761 if (!_EmittedType
) return;
2762 if (!_GenNbScheme
&& _GenNb
== 0) return;
2764 nlassert(CParticleSystem::InsideSimLoop
); // should only be called by the sim loop
2767 nlassert(_Owner
->getOwner());
2768 const CParticleSystem
*ps
= _Owner
->getOwner();
2769 if (ps
->isAutoLODEnabled() && !ps
->isSharingEnabled() && !_BypassAutoLOD
)
2771 // temp test for auto lod
2772 emitLOD
= ps
->getAutoLODEmitRatio();
2778 nlassert(emitLOD
>= 0.f
);
2781 const uint BATCH_SIZE
= 1024;
2782 uint32 numToEmit
[BATCH_SIZE
];
2783 uint k
= firstInstanceIndex
;
2784 nlassert(firstInstanceIndex
< _Owner
->getSize());
2785 uint leftToDo
= _Owner
->getSize() - firstInstanceIndex
;
2789 uint toProcess
= std::min((uint
) BATCH_SIZE
, leftToDo
);
2790 uint32
*numToEmitPtr
= (uint32
*) _GenNbScheme
->make(_Owner
, k
, numToEmit
, sizeof(uint32
), true);
2791 leftToDo
-= toProcess
;
2795 if (!_Owner
->isParametricMotionEnabled())
2797 startPos
= _Owner
->getPos()[k
] - _Owner
->getSpeed()[k
] * CParticleSystem::EllapsedTime
;
2801 startPos
= _Owner
->getParametricInfos()[k
].Pos
;
2803 float currTime
= _Owner
->getTime()[k
];
2804 _Owner
->getTime()[k
] = 0.f
; // when emit occurred, time was 0
2805 sint32 nbToGenerate
= (sint32
) (emitLOD
* *numToEmitPtr
);
2806 if (nbToGenerate
> 0)
2808 nbToGenerate
= std::min(nbToGenerate
, (sint32
) _EmittedType
->getMaxSize());
2809 processEmitConsistent(startPos
, k
, nbToGenerate
, _Owner
->getAgeInSeconds(k
) / CParticleSystem::RealEllapsedTimeRatio
);
2811 // restore time & pos
2812 _Owner
->getTime()[k
] = currTime
;
2821 sint nbToGenerate
= (sint
) (emitLOD
* _GenNb
);
2822 if (nbToGenerate
<= 0) nbToGenerate
= 1;
2823 nbToGenerate
= std::min(nbToGenerate
, (sint
) _EmittedType
->getMaxSize());
2824 for(uint k
= firstInstanceIndex
; k
< _Owner
->getSize(); ++k
)
2826 // retrieve previous position (because motion step is done before spawn step)
2828 if (!_Owner
->isParametricMotionEnabled())
2830 startPos
= _Owner
->getPos()[k
] - _Owner
->getSpeed()[k
] * CParticleSystem::EllapsedTime
;
2834 startPos
= _Owner
->getParametricInfos()[k
].Pos
;
2836 float currTime
= _Owner
->getTime()[k
];
2837 _Owner
->getTime()[k
] = 0.f
; // when emit occurred, time was 0
2838 processEmitConsistent(startPos
, k
, nbToGenerate
, _Owner
->getAgeInSeconds(k
) / CParticleSystem::RealEllapsedTimeRatio
);
2839 // restore time & pos
2840 _Owner
->getTime()[k
] = currTime
;
2845 ///==========================================================================
2846 void CPSEmitter::updateEmitTrigger()
2848 NL_PS_FUNC(CPSEmitter_updateEmitTrigger
)
2849 if (!_EmitTrigger
) return;
2851 nlassert(_Owner
->getOwner());
2852 const CParticleSystem
*ps
= _Owner
->getOwner();
2854 if (ps
->isAutoLODEnabled() && !ps
->isSharingEnabled() && !_BypassAutoLOD
)
2856 // temp test for auto lod
2857 emitLOD
= ps
->getAutoLODEmitRatio();
2865 const uint BATCH_SIZE
= 1024;
2866 uint32 numToEmit
[BATCH_SIZE
];
2868 uint leftToDo
= _Owner
->getSize();
2871 uint toProcess
= std::min(BATCH_SIZE
, leftToDo
);
2872 uint32
*numToEmitPtr
= (uint32
*) _GenNbScheme
->make(_Owner
, k
, numToEmit
, sizeof(uint32
), true);
2875 uint32 nbToGenerate
= (sint32
) (emitLOD
* *numToEmitPtr
);
2876 if (!nbToGenerate
) nbToGenerate
= 1;
2877 processEmit(k
, nbToGenerate
);
2882 leftToDo
-= toProcess
;
2887 uint nbToGenerate
= (sint32
) (emitLOD
* _GenNb
);
2888 if (!nbToGenerate
) nbToGenerate
= 1;
2889 for(uint k
= 0; k
< _Owner
->getSize(); ++k
)
2891 processEmit(k
, nbToGenerate
);
2894 _EmitTrigger
= false;
2904 std::string
toString(NL3D::CPSEmitter::TEmissionType type
)
2906 NL_PS_FUNC(toString_CPSEmitter_TEmissionType
)
2907 nlctassert(NL3D::CPSEmitter::numEmissionType
== 5); // If this ct assertion is raised, the content of TEmissionType has changed, so should change this function !
2910 case NL3D::CPSEmitter::regular
: return "regular";
2911 case NL3D::CPSEmitter::onDeath
: return "onDeath";
2912 case NL3D::CPSEmitter::once
: return "once";
2913 case NL3D::CPSEmitter::onBounce
: return "onBounce";
2914 case NL3D::CPSEmitter::externEmit
: return "externEmit";