1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "nel/3d/particle_system.h"
25 #include "nel/3d/ps_located.h"
26 #include "nel/3d/driver.h"
27 #include "nel/3d/vertex_buffer.h"
28 #include "nel/3d/material.h"
29 #include "nel/3d/index_buffer.h"
30 #include "nel/3d/nelu.h"
31 #include "nel/3d/ps_util.h"
32 #include "nel/3d/ps_particle.h"
33 #include "nel/3d/ps_emitter.h"
34 #include "nel/3d/ps_sound.h"
35 #include "nel/3d/particle_system_shape.h"
36 #include "nel/3d/ps_located.h"
37 #include "nel/misc/aabbox.h"
38 #include "nel/misc/file.h"
39 #include "nel/misc/stream.h"
42 #include "nel/3d/particle_system_model.h"
46 #define CHECK_INTEGRITY checkIntegrity();
48 #define CHECK_INTEGRITY
60 uint32
CParticleSystem::NbParticlesDrawn
= 0;
61 UPSSoundServer
* CParticleSystem::_SoundServer
= NULL
;
62 CParticleSystem::TGlobalValuesMap
CParticleSystem::_GlobalValuesMap
;
63 CParticleSystem::TGlobalVectorValuesMap
CParticleSystem::_GlobalVectorValuesMap
;
66 TAnimationTime
CParticleSystem::EllapsedTime
= 0.f
;
67 TAnimationTime
CParticleSystem::InverseTotalEllapsedTime
= 0.f
;
68 TAnimationTime
CParticleSystem::RealEllapsedTime
= 0.f
;
69 float CParticleSystem::RealEllapsedTimeRatio
= 1.f
;
70 bool CParticleSystem::InsideSimLoop
= false;
71 bool CParticleSystem::InsideRemoveLoop
= false;
72 bool CParticleSystem::InsideNewElementsLoop
= false;;
73 std::vector
<NLMISC::CVector
> CParticleSystem::_SpawnPos
;
77 //bool FilterPS[10] = { false, false, false, false, false, false, false, false, false, false };
81 uint
CParticleSystem::_NumInstances
= 0;
85 static const float PS_MIN_TIMEOUT
= 1.f
; // the test that check if there are no particles left
86 #if defined(NL_DEBUG) || defined(NL_PS_DEBUG)
87 bool CParticleSystem::_SerialIdentifiers
= true;
89 bool CParticleSystem::_SerialIdentifiers
= false;
91 bool CParticleSystem::_ForceDisplayBBox
= false;
92 CParticleSystemModel
*CParticleSystem::OwnerModel
= NULL
;
98 ///////////////////////////////////
99 // CPaticleSystem implementation //
100 ///////////////////////////////////
103 /// the default max distance of view for particle systems
104 const float PSDefaultMaxViewDist
= 300.f
;
109 CParticleSystem::CParticleSystem() : _Driver(NULL
),
110 _FontGenerator(NULL
),
112 _UserCoordSystemInfo(NULL
),
115 _CurrEditedElementLocated(NULL
),
116 _CurrEditedElementLocatedBindable(NULL
),
117 _CurrEditedElementIndex(0),
119 _TimeThreshold(0.15f
),
121 _MaxNbIntegrations(2),
123 _OneMinusCurrentLODRatio(0),
124 _MaxViewDist(PSDefaultMaxViewDist
),
125 _MaxDistLODBias(0.05f
),
126 _InvMaxViewDist(1.f
/ PSDefaultMaxViewDist
),
127 _InvCurrentViewDist(1.f
/ PSDefaultMaxViewDist
),
128 _AutoLODEmitRatio(0.f
),
130 _DelayBeforeDieTest(-1.f
),
132 _AnimType(AnimInCluster
),
133 _UserParamGlobalValue(NULL
),
134 _BypassGlobalUserParam(0),
135 _PresetBehaviour(UserBehaviour
),
136 _ColorAttenuationScheme(NULL
),
137 _GlobalColor(NLMISC::CRGBA::White
),
138 _GlobalColorLighted(NLMISC::CRGBA::White
),
139 _LightingColor(NLMISC::CRGBA::White
),
140 _UserColor(NLMISC::CRGBA::White
),
143 _AccurateIntegration(true),
145 _DestroyModelWhenOutOfRange(false),
146 _DestroyWhenOutOfFrustum(false),
149 _KeepEllapsedTimeForLifeUpdate(false),
150 _AutoLODSkipParticles(false),
151 _EnableLoadBalancing(true),
152 _EmitThreshold(true),
153 _BypassIntegrationStepLimit(false),
154 _ForceGlobalColorLighting(false),
155 _AutoComputeDelayBeforeDeathTest(true),
157 _HiddenAtCurrentFrame(true),
158 _HiddenAtPreviousFrame(true),
159 _AutoLODStartDistPercent(0.1f
),
160 _AutoLODDegradationExponent(1)
162 NL_PS_FUNC_MAIN(CParticleSystem_CParticleSystem
)
163 std::fill(_UserParam
, _UserParam
+ MaxPSUserParam
, 0.0f
);
171 std::vector
<NLMISC::CSmartPtr
<CParticleSystem::CSpawnVect
> > CParticleSystem::_Spawns
; // spawns for the current system being processed
172 std::vector
<uint
> CParticleSystem::_ParticleToRemove
;
173 std::vector
<sint
> CParticleSystem::_ParticleRemoveListIndex
;
178 ///=======================================================================================
179 /// immediatly shut down all the sound in this system
180 void CParticleSystem::stopSound()
182 NL_PS_FUNC_MAIN(CParticleSystem_stopSound
)
183 for (uint k
= 0; k
< this->getNbProcess(); ++k
)
185 CPSLocated
*psl
= dynamic_cast<NL3D::CPSLocated
*>(this->getProcess(k
));
188 for (uint l
= 0; l
< psl
->getNbBoundObjects(); ++l
)
190 if (psl
->getBoundObject(l
)->getType() == PSSound
)
192 static_cast<CPSSound
*>(psl
->getBoundObject(l
))->stopSound();
199 ///=======================================================================================
200 void CParticleSystem::reactivateSound()
202 NL_PS_FUNC_MAIN(CParticleSystem_reactivateSound
)
203 for (uint k
= 0; k
< this->getNbProcess(); ++k
)
205 CPSLocated
*psl
= dynamic_cast<NL3D::CPSLocated
*>(this->getProcess(k
));
208 for (uint l
= 0; l
< psl
->getNbBoundObjects(); ++l
)
210 if (psl
->getBoundObject(l
)->getType() == PSSound
)
212 static_cast<CPSSound
*>(psl
->getBoundObject(l
))->reactivateSound();
220 ///=======================================================================================
221 void CParticleSystem::enableLoadBalancing(bool enabled
/*=true*/)
223 NL_PS_FUNC_MAIN(CParticleSystem_enableLoadBalancing
)
226 //notifyMaxNumFacesChanged();
228 _EnableLoadBalancing
= enabled
;
231 ///=======================================================================================
233 void CParticleSystem::notifyMaxNumFacesChanged(void)
235 if (!_EnableLoadBalancing) return;
236 _MaxNumFacesWanted = 0;
237 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
239 _MaxNumFacesWanted += (*it)->querryMaxWantedNumFaces();
244 ///=======================================================================================
245 void CParticleSystem::updateNumWantedTris()
247 NL_PS_FUNC_MAIN(CParticleSystem_updateNumWantedTris
)
249 for (TProcessVect::iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
251 _NumWantedTris
+= (*it
)->getNumWantedTris();
255 ///=======================================================================================
256 float CParticleSystem::getWantedNumTris(float dist
)
258 NL_PS_FUNC_MAIN(CParticleSystem_getWantedNumTris
)
259 if (!_EnableLoadBalancing
) return 0; // no contribution to the load balancing
260 if (dist
> _MaxViewDist
) return 0;
261 float retValue
= ((1.f
- dist
* _InvMaxViewDist
) * _NumWantedTris
);
262 ///nlassertex(retValue >= 0 && retValue < 10000, ("dist = %f, _MaxViewDist = %f, _MaxNumFacesWanted = %d, retValue = %f", dist, _MaxViewDist, _MaxNumFacesWanted, retValue));
267 ///=======================================================================================
268 void CParticleSystem::setNumTris(uint numFaces
)
270 NL_PS_FUNC_MAIN(CParticleSystem_setNumTris
)
271 if (_EnableLoadBalancing
)
273 float modelDist
= (getSysMat().getPos() - _InvertedViewMat
.getPos()).norm();
274 /*uint numFaceWanted = (uint) getWantedNumTris(modelDist);*/
276 const float epsilon
= 10E-5f
;
279 uint wantedNumTri
= (uint
) getWantedNumTris(modelDist
);
280 if (numFaces
>= wantedNumTri
|| wantedNumTri
== 0 || _NumWantedTris
== 0 || modelDist
< epsilon
)
282 _InvCurrentViewDist
= _InvMaxViewDist
;
287 _InvCurrentViewDist
= (_NumWantedTris
- numFaces
) / (_NumWantedTris
* modelDist
);
292 // always take full detail when there's no load balancing
293 _InvCurrentViewDist
= _InvMaxViewDist
;
298 ///=======================================================================================
300 CParticleSystem::~CParticleSystem()
302 NL_PS_FUNC_MAIN(CParticleSystem_CParticleSystemDtor
)
303 for (TProcessVect::iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
307 if (_ColorAttenuationScheme
)
308 delete _ColorAttenuationScheme
;
309 if (_UserParamGlobalValue
)
310 delete _UserParamGlobalValue
;
311 delete _UserCoordSystemInfo
;
317 ///=======================================================================================
318 void CParticleSystem::setViewMat(const NLMISC::CMatrix
&m
)
320 NL_PS_FUNC_MAIN(CParticleSystem_setViewMat
)
322 _InvertedViewMat
= m
.inverted();
325 ///=======================================================================================
326 bool CParticleSystem::hasEmitters() const
328 NL_PS_FUNC_MAIN(CParticleSystem_hasEmitters
)
329 for (TProcessVect::const_iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
331 if ((*it
)->hasEmitters()) return true;
336 ///=======================================================================================
337 bool CParticleSystem::hasParticles() const
339 NL_PS_FUNC_MAIN(CParticleSystem_hasParticles
)
340 for (TProcessVect::const_iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
342 if ((*it
)->hasParticles()) return true;
347 ///=======================================================================================
348 bool CParticleSystem::hasTemporaryParticles() const
350 NL_PS_FUNC_MAIN(CParticleSystem_hasTemporaryParticles
)
351 for (TProcessVect::const_iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
353 if ((*it
)->isLocated())
355 CPSLocated
*loc
= static_cast<CPSLocated
*>(*it
);
356 if (loc
->hasParticles()) return true;
362 ///=======================================================================================
363 void CParticleSystem::stepLocated(TPSProcessPass pass
)
365 NL_PS_FUNC_MAIN(CParticleSystem_stepLocated
)
366 for (TProcessVect::iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
372 ///=======================================================================================
376 float CParticleSystem::getDistFromViewer() const
378 NL_PS_FUNC_MAIN(CParticleSystem_getDistFromViewer
)
379 const CVector d
= getSysMat().getPos() - _InvertedViewMat
.getPos();
383 ///=======================================================================================
387 float CParticleSystem::updateLODRatio()
389 NL_PS_FUNC_MAIN(CParticleSystem_updateLODRatio
)
390 float dist
= getDistFromViewer();
391 _OneMinusCurrentLODRatio
= 1.f
- (dist
* _InvCurrentViewDist
);
392 NLMISC::clamp(_OneMinusCurrentLODRatio
, 0.f
, 1.f
);
396 ///=======================================================================================
397 inline void CParticleSystem::updateColor(float distFromViewer
)
399 NL_PS_FUNC_MAIN(CParticleSystem_updateColor
)
400 if (_ColorAttenuationScheme
)
402 float ratio
= distFromViewer
* _InvMaxViewDist
;
403 NLMISC::clamp(ratio
, 0.f
, 1.f
);
404 _GlobalColor
= _ColorAttenuationScheme
->get(ratio
);
408 _GlobalColor
= NLMISC::CRGBA::White
;
410 _GlobalColor
.modulateFromColor(_GlobalColor
, _UserColor
);
411 _GlobalColorLighted
.modulateFromColor(_GlobalColor
, _LightingColor
);
416 static void displaySysPos(IDriver *drv, const CVector &pos, CRGBA col)
419 drv->setupModelMatrix(CMatrix::Identity);
420 CPSUtil::displayArrow(drv, pos, CVector::K, 1.f, CRGBA::White, col);
425 ///=======================================================================================
426 void CParticleSystem::step(TPass pass
, TAnimationTime ellapsedTime
, CParticleSystemShape
&shape
, CParticleSystemModel
&model
)
428 NL_PS_FUNC_MAIN(CParticleSystem_step
)
431 if (!_CoordSystemInfo
.Matrix
)
433 nlwarning("3D: BUG: CParticleSystem::step -> !_CoordSystemInfo.Matrix");
436 nlassert(_CoordSystemInfo
.Matrix
); // matrix not set for position of system
437 if (_UserCoordSystemInfo
)
439 nlassert(_CoordSystemInfo
.Matrix
);
444 EllapsedTime
= RealEllapsedTime
= ellapsedTime
;
445 RealEllapsedTimeRatio
= 1.f
;
446 /// When shared, the LOD ratio must be computed there
449 float dist
= updateLODRatio();
454 updateColor(getDistFromViewer());
458 // update global color
459 stepLocated(PSSolidRender
);
463 EllapsedTime
= RealEllapsedTime
= ellapsedTime
;
464 RealEllapsedTimeRatio
= 1.f
;
465 /// When shared, the LOD ratio must be computed there
466 /// When shared, the LOD ratio must be computed there
469 float dist
= updateLODRatio();
474 updateColor(getDistFromViewer());
478 // update global color
479 stepLocated(PSBlendRender
);
480 if (_ForceDisplayBBox
)
484 getDriver()->setupModelMatrix(*_CoordSystemInfo
.Matrix
);
485 CPSUtil::displayBBox(getDriver(), box
);
489 EllapsedTime
= RealEllapsedTime
= ellapsedTime
;
490 RealEllapsedTimeRatio
= 1.f
;
491 stepLocated(PSToolRender
);
495 if (ellapsedTime
<= 0.f
) return;
496 // update user param from global value if needed, unless this behaviour is bypassed has indicated by a flag in _BypassGlobalUserParam
497 if (_UserParamGlobalValue
)
499 nlctassert(MaxPSUserParam
< 8); // there should be less than 8 parameters because of mask stored in a byte
500 uint8 bypassMask
= 1;
501 for(uint k
= 0; k
< MaxPSUserParam
; ++k
)
503 if (_UserParamGlobalValue
[k
] && !(_BypassGlobalUserParam
& bypassMask
)) // if there is a global value for this param and if the update is not bypassed
505 _UserParam
[k
] = _UserParamGlobalValue
[k
]->second
;
512 EllapsedTime
= ellapsedTime
;
514 if (_AccurateIntegration
)
516 if (EllapsedTime
> _TimeThreshold
)
518 nbPass
= (uint32
) ceilf(EllapsedTime
/ _TimeThreshold
);
519 if (!_BypassIntegrationStepLimit
&& nbPass
> _MaxNbIntegrations
)
521 nbPass
= _MaxNbIntegrations
;
524 EllapsedTime
= _TimeThreshold
;
525 nlassert(_TimeThreshold
!= 0);
526 InverseTotalEllapsedTime
= 1.f
/ (_TimeThreshold
* nbPass
);
530 EllapsedTime
= ellapsedTime
/ nbPass
;
531 InverseTotalEllapsedTime
= ellapsedTime
!= 0 ? 1.f
/ ellapsedTime
: 0.f
;
536 EllapsedTime
= ellapsedTime
/ nbPass
;
537 InverseTotalEllapsedTime
= ellapsedTime
!= 0 ? 1.f
/ ellapsedTime
: 0.f
;
542 InverseTotalEllapsedTime
= ellapsedTime
!= 0 ? 1.f
/ ellapsedTime
: 0.f
;
547 InverseTotalEllapsedTime
= ellapsedTime
!= 0 ? 1.f
/ ellapsedTime
: 0.f
;
552 if (_AutoLOD
&& !_Sharing
)
554 float currLODRatio
= 1.f
- _OneMinusCurrentLODRatio
;
555 if (currLODRatio
<= _AutoLODStartDistPercent
)
557 _AutoLODEmitRatio
= 1.f
; // no LOD applied
561 float lodValue
= (currLODRatio
- 1.f
) / (_AutoLODStartDistPercent
- 1.f
);
562 NLMISC::clamp(lodValue
, 0.f
, 1.f
);
563 float finalValue
= lodValue
;
564 for(uint l
= 1; l
< _AutoLODDegradationExponent
; ++l
)
566 finalValue
*= lodValue
;
568 _AutoLODEmitRatio
= (1.f
- _MaxDistLODBias
) * finalValue
+ _MaxDistLODBias
;
569 if (_AutoLODEmitRatio
< 0.f
) _AutoLODEmitRatio
= 0.f
;
575 // set start position. Used by emitters that emit from Local basis to world
576 if (!_HiddenAtPreviousFrame
&& !_HiddenAtCurrentFrame
)
578 _CoordSystemInfo
.CurrentDeltaPos
= _CoordSystemInfo
.OldPos
- _CoordSystemInfo
.Matrix
->getPos();
579 if (_UserCoordSystemInfo
)
581 CCoordSystemInfo
&csi
= _UserCoordSystemInfo
->CoordSystemInfo
;
582 csi
.CurrentDeltaPos
= csi
.OldPos
- csi
.Matrix
->getPos();
587 _CoordSystemInfo
.CurrentDeltaPos
= NLMISC::CVector::Null
;
588 _CoordSystemInfo
.OldPos
= _CoordSystemInfo
.Matrix
->getPos();
589 if (_UserCoordSystemInfo
)
591 CCoordSystemInfo
&csi
= _UserCoordSystemInfo
->CoordSystemInfo
;
592 csi
.CurrentDeltaPos
= NLMISC::CVector::Null
;
593 csi
.OldPos
= csi
.Matrix
->getPos();
596 //displaySysPos(_Driver, _CurrentDeltaPos + _OldSysMat.getPos(), CRGBA::Red);
599 RealEllapsedTime
= _KeepEllapsedTimeForLifeUpdate
? (ellapsedTime
/ nbPass
)
601 RealEllapsedTimeRatio
= RealEllapsedTime
/ EllapsedTime
;
602 /*PSMaxET = std::max(PSMaxET, ellapsedTime);
603 PSMaxNBPass = std::max(PSMaxNBPass, nbPass);*/
607 // Sort by emission depth. We assume that the ps is a directed acyclic graph (so no loop will be encountered)
608 if (shape
._ProcessOrder
.empty())
610 getSortingByEmitterPrecedence(shape
._ProcessOrder
);
612 // nodes sorted by degree
613 InsideSimLoop
= true;
614 // make enough room for spawns
615 uint numProcess
= (uint
)_ProcessVect
.size();
616 if (numProcess
> _Spawns
.size())
618 uint oldSize
= (uint
)_Spawns
.size();
619 _Spawns
.resize(numProcess
);
620 for(uint k
= oldSize
; k
< numProcess
; ++k
)
622 _Spawns
[k
] = new CSpawnVect
;
625 for(uint k
= 0; k
< numProcess
; ++k
)
627 if (!_ProcessVect
[k
]->isLocated()) continue;
628 CPSLocated
*loc
= static_cast<CPSLocated
*>(_ProcessVect
[k
]);
629 if (loc
->hasLODDegradation())
631 loc
->doLODDegradation();
633 _Spawns
[k
]->MaxNumSpawns
= loc
->getMaxSize();
639 // position of the system at the end of the integration
640 _CoordSystemInfo
.CurrentDeltaPos
+= (_CoordSystemInfo
.Matrix
->getPos() - _CoordSystemInfo
.OldPos
) * (EllapsedTime
* InverseTotalEllapsedTime
);
641 if (_UserCoordSystemInfo
)
643 CCoordSystemInfo
&csi
= _UserCoordSystemInfo
->CoordSystemInfo
;
644 csi
.CurrentDeltaPos
+= (csi
.Matrix
->getPos() - csi
.OldPos
) * (EllapsedTime
* InverseTotalEllapsedTime
);
647 for(uint k
= 0; k
< shape
._ProcessOrder
.size(); ++k
)
649 if (!_ProcessVect
[shape
._ProcessOrder
[k
]]->isLocated()) continue;
650 CPSLocated
*loc
= static_cast<CPSLocated
*>(_ProcessVect
[shape
._ProcessOrder
[k
]]);
651 if (_ParticleRemoveListIndex
.size() < loc
->getMaxSize())
653 _ParticleRemoveListIndex
.resize(loc
->getMaxSize(), -1);
655 if (loc
->getSize() != 0)
660 if (loc
->hasCollisionInfos())
662 loc
->resetCollisions(loc
->getSize());
664 // compute motion (including collisions)
665 if (!loc
->isParametricMotionEnabled()) loc
->computeMotion();
666 // Update life and mark particles that must be removed
668 // Spawn particles. Emitters date is updated only after so we check in CPSLocated::postNewElement
669 // if the emitter was still alive at this date, otherwise we discard the post
670 loc
->computeSpawns(0, false);
671 if (loc
->hasCollisionInfos()) loc
->updateCollisions();
672 // Remove too old particles, making room for new ones
673 if (!_ParticleToRemove
.empty())
675 loc
->removeOldParticles();
681 if (!_Spawns
[shape
._ProcessOrder
[k
]]->SpawnInfos
.empty())
683 uint insertionIndex
= loc
->getSize(); // index at which new particles will be inserted
684 // add new particles that where posted by ancestor emitters, and also mark those that must already be deleted
685 loc
->addNewlySpawnedParticles();
686 if (insertionIndex
!= loc
->getSize())
688 // Compute motion for spawned particles. This is useful only if particle can collide because
689 if (loc
->hasCollisionInfos())
691 loc
->resetCollisions(loc
->getSize());
692 loc
->computeNewParticleMotion(insertionIndex
);
694 loc
->computeSpawns(insertionIndex
, true);
695 if (loc
->hasCollisionInfos()) loc
->updateCollisions();
696 // Remove too old particles among the newly created ones.
697 if (!_ParticleToRemove
.empty())
699 loc
->removeOldParticles();
706 if (!loc
->isParametricMotionEnabled()) loc
->computeForces();
708 _SystemDate
+= RealEllapsedTime
;
709 for (TProcessVect::iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
712 if ((*it
)->isLocated())
714 CPSLocated
*loc
= static_cast<CPSLocated
*>(*it
);
720 (*it
)->step(PSMotion
);
727 // perform parametric motion if present
728 for (TProcessVect::iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
730 if ((*it
)->isParametricMotionEnabled()) (*it
)->performParametricMotion(_SystemDate
);
734 updateNumWantedTris();
736 InsideSimLoop
= false;
740 // memorize position of matrix for next frame (becomes old position)
741 _CoordSystemInfo
.OldPos
= _CoordSystemInfo
.Matrix
->getPos();
742 if (_UserCoordSystemInfo
)
744 CCoordSystemInfo
&csi
= _UserCoordSystemInfo
->CoordSystemInfo
;
745 csi
.OldPos
= csi
.Matrix
->getPos();
748 _HiddenAtPreviousFrame
= _HiddenAtCurrentFrame
;
752 RealEllapsedTimeRatio
= 0.f
;
757 ///=======================================================================================
758 void CParticleSystem::serial(NLMISC::IStream
&f
)
761 NL_PS_FUNC_MAIN(CParticleSystem_serial
)
762 sint version
= f
.serialVersion(19);
764 // version 19: sysmat no more serialized (useless)
765 // version 18: _AutoComputeDelayBeforeDeathTest
766 // version 17: _ForceGlobalColorLighting flag
767 // version 16: _BypassIntegrationStepLimit flag
768 // version 14: emit threshold
769 // version 13: max dist lod bias for auto-LOD
770 // version 12: global userParams
771 // version 11: enable load balancing flag
772 // version 9: Sharing flag added
773 // Auto-lod parameters
774 // New integration flag
775 // Global color attenuation
776 // version 8: Replaced the attribute '_PerformMotionWhenOutOfFrustum' by a _AnimType field which allow more precise control
778 //f.serial(_ViewMat);
780 // patch for old fx : force to recompute duration when fx is saved to avoid prbs
783 if (_AutoComputeDelayBeforeDeathTest
)
785 _DelayBeforeDieTest
= evalDuration();
791 NLMISC::CMatrix dummy
;
797 delete _ColorAttenuationScheme
;
798 // delete previous multimap
800 // delete previously attached process
801 TProcessVect::iterator it
;
802 for (it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
807 _ProcessVect
.clear();
809 f
.serialContPolyPtr(_ProcessVect
);
811 _FontGenerator
= NULL
;
813 if (_UserParamGlobalValue
)
814 delete _UserParamGlobalValue
;
815 _UserParamGlobalValue
= NULL
;
816 _BypassGlobalUserParam
= 0;
817 // see if some process need to access the user matrix
818 delete _UserCoordSystemInfo
;
819 _UserCoordSystemInfo
= NULL
;
820 for (TProcessVect::iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
822 addRefForUserSysCoordInfo((*it
)->getUserMatrixUsageCount());
827 f
.serialContPolyPtr(_ProcessVect
);
830 if (version
> 1) // name of the system
832 if (f
.isReading() && !getSerializeIdentifierFlag())
834 // just skip the name
837 f
.seek(len
, NLMISC::IStream::current
);
845 if (version
> 2) // infos about integration, and LOD
847 bool accurateIntegration
= _AccurateIntegration
; // read from bitfield
848 f
.serial(accurateIntegration
);
849 _AccurateIntegration
= accurateIntegration
;
850 if (_AccurateIntegration
)
852 bool canSlowDown
= _CanSlowDown
;
853 f
.serial(canSlowDown
);
854 _CanSlowDown
= canSlowDown
;
855 f
.serial(_TimeThreshold
, _MaxNbIntegrations
);
857 f
.serial(_InvMaxViewDist
, _LODRatio
);
858 _MaxViewDist
= 1.f
/ _InvMaxViewDist
;
859 _InvCurrentViewDist
= _InvMaxViewDist
;
862 if (version
> 3) // tell whether the system must compute his bbox, hold a precomputed bbox
864 bool computeBBox
= _ComputeBBox
;
865 f
.serial(computeBBox
);
866 _ComputeBBox
= computeBBox
;
869 f
.serial(_PreComputedBBox
);
873 if (version
> 4) // lifetime information
875 bool destroyModelWhenOutOfRange
= _DestroyModelWhenOutOfRange
; // read from bitfield
876 f
.serial(destroyModelWhenOutOfRange
);
877 _DestroyModelWhenOutOfRange
= destroyModelWhenOutOfRange
;
878 f
.serialEnum(_DieCondition
);
879 if (_DieCondition
!= none
)
881 f
.serial(_DelayBeforeDieTest
);
887 bool destroyWhenOutOfFrustum
= _DestroyWhenOutOfFrustum
; // read from bitfield
888 f
.serial(destroyWhenOutOfFrustum
);
889 _DestroyWhenOutOfFrustum
= destroyWhenOutOfFrustum
;
892 if (version
> 6 && version
< 8)
894 bool performMotionWOOF
;
897 f
.serial(performMotionWOOF
);
898 performMotionWhenOutOfFrustum(performMotionWOOF
);
902 performMotionWOOF
= doesPerformMotionWhenOutOfFrustum();
903 f
.serial(performMotionWOOF
);
909 f
.serialEnum(_AnimType
);
910 f
.serialEnum(_PresetBehaviour
);
915 bool sharing
= _Sharing
; // read from bitfield
918 bool autoLOD
= _AutoLOD
; // read from bitfield
924 f
.serial(_AutoLODStartDistPercent
, _AutoLODDegradationExponent
);
925 bool autoLODSkipParticles
= _AutoLODSkipParticles
; // read from bitfield
926 f
.serial(autoLODSkipParticles
);
927 _AutoLODSkipParticles
= autoLODSkipParticles
;
929 bool keepEllapsedTimeForLifeUpdate
= _KeepEllapsedTimeForLifeUpdate
;
930 f
.serial(keepEllapsedTimeForLifeUpdate
);
931 _KeepEllapsedTimeForLifeUpdate
= keepEllapsedTimeForLifeUpdate
;
932 f
.serialPolyPtr(_ColorAttenuationScheme
);
937 bool enableLoadBalancing
= _EnableLoadBalancing
; // read from bitfield
938 f
.serial(enableLoadBalancing
);
939 _EnableLoadBalancing
= enableLoadBalancing
;
944 // serial infos about global user params
945 nlctassert(MaxPSUserParam
< 8); // In this version mask of used global user params are stored in a byte..
952 std::string globalValueName
;
954 for(uint k
= 0; k
< MaxPSUserParam
; ++k
)
958 f
.serial(globalValueName
);
959 bindGlobalValueToUserParam(globalValueName
.c_str(), k
);
968 if (_UserParamGlobalValue
)
970 for(uint k
= 0; k
< MaxPSUserParam
; ++k
)
972 if (_UserParamGlobalValue
[k
]) mask
|= (1 << k
);
976 if (_UserParamGlobalValue
)
978 for(uint k
= 0; k
< MaxPSUserParam
; ++k
)
980 if (_UserParamGlobalValue
[k
])
982 std::string valueName
= _UserParamGlobalValue
[k
]->first
;
991 if (_AutoLOD
&& !_Sharing
)
993 f
.serial(_MaxDistLODBias
);
998 bool emitThreshold
= _EmitThreshold
; // read from bitfiled
999 f
.serial(emitThreshold
);
1000 _EmitThreshold
= emitThreshold
;
1005 bool bypassIntegrationStepLimit
= _BypassIntegrationStepLimit
; // read from bitfield
1006 f
.serial(bypassIntegrationStepLimit
);
1007 _BypassIntegrationStepLimit
= bypassIntegrationStepLimit
;
1012 bool forceGlobalColorLighting
= _ForceGlobalColorLighting
; // read from bitfield
1013 f
.serial(forceGlobalColorLighting
);
1014 _ForceGlobalColorLighting
= forceGlobalColorLighting
;
1019 bool autoComputeDelayBeforeDeathTest
= _AutoComputeDelayBeforeDeathTest
; // read from bitfield
1020 f
.serial(autoComputeDelayBeforeDeathTest
);
1021 _AutoComputeDelayBeforeDeathTest
= autoComputeDelayBeforeDeathTest
;
1025 nlassert(f
.isReading());
1026 // for all previously created system, force to eval the system duration in an automatyic way
1027 setDelayBeforeDeathConditionTest(-1.f
);
1028 _AutoComputeDelayBeforeDeathTest
= true;
1033 //notifyMaxNumFacesChanged();
1034 updateNumWantedTris();
1035 activatePresetBehaviour(_PresetBehaviour
); // apply behaviour changes
1036 updateProcessIndices();
1040 //if (f.isReading())
1047 ///=======================================================================================
1048 bool CParticleSystem::attach(CParticleSystemProcess
*ptr
)
1050 NL_PS_FUNC_MAIN(CParticleSystem_attach
)
1052 nlassert(std::find(_ProcessVect
.begin(), _ProcessVect
.end(), ptr
) == _ProcessVect
.end() ); // can't attach twice
1053 //nlassert(ptr->getOwner() == NULL);
1054 _ProcessVect
.push_back(ptr
);
1055 ptr
->setOwner(this);
1056 ptr
->setIndex((uint32
)_ProcessVect
.size() - 1);
1057 //notifyMaxNumFacesChanged();
1058 if (getBypassMaxNumIntegrationSteps())
1063 nlwarning("<void CParticleSystem::attach> Can't attach object : this causes the system to last forever, and it has been flagged with 'BypassMaxNumIntegrationSteps'. Object is not attached");
1067 systemDurationChanged();
1071 ///=======================================================================================
1072 void CParticleSystem::remove(CParticleSystemProcess
*ptr
)
1074 NL_PS_FUNC_MAIN(CParticleSystem_remove
)
1075 TProcessVect::iterator it
= std::find(_ProcessVect
.begin(), _ProcessVect
.end(), ptr
);
1076 nlassert(it
!= _ProcessVect
.end() );
1077 ptr
->setOwner(NULL
);
1078 _ProcessVect
.erase(it
);
1080 systemDurationChanged();
1081 updateProcessIndices();
1084 ///=======================================================================================
1085 void CParticleSystem::forceComputeBBox(NLMISC::CAABBox
&aabbox
)
1087 NL_PS_FUNC_MAIN(CParticleSystem_forceComputeBBox
)
1088 bool foundOne
= false;
1089 NLMISC::CAABBox tmpBox
;
1090 for (TProcessVect::const_iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
1092 if ((*it
)->computeBBox(tmpBox
))
1094 // rotate the aabbox so that it is in the correct basis
1095 const CMatrix
&convMat
= CPSLocated::getConversionMatrix(*this, PSFXWorldMatrix
, (*it
)->getMatrixMode());
1096 tmpBox
= NLMISC::CAABBox::transformAABBox(convMat
, tmpBox
);
1100 aabbox
= NLMISC::CAABBox::computeAABBoxUnion(aabbox
, tmpBox
);
1112 aabbox
.setCenter(NLMISC::CVector::Null
);
1113 aabbox
.setHalfSize(NLMISC::CVector::Null
);
1117 ///=======================================================================================
1118 void CParticleSystem::computeBBox(NLMISC::CAABBox
&aabbox
)
1120 NL_PS_FUNC_MAIN(CParticleSystem_computeBBox
)
1121 if (!_ComputeBBox
|| !_BBoxTouched
)
1123 aabbox
= _PreComputedBBox
;
1126 forceComputeBBox(aabbox
);
1127 _BBoxTouched
= false;
1128 _PreComputedBBox
= aabbox
;
1131 ///=======================================================================================
1132 void CParticleSystem::setSysMat(const CMatrix
*m
)
1134 NL_PS_FUNC_MAIN(CParticleSystem_setSysMat
)
1135 _CoordSystemInfo
.Matrix
= m
;
1136 if (_SystemDate
== 0.f
)
1138 _CoordSystemInfo
.OldPos
= m
? m
->getPos() : CVector::Null
;
1141 _CoordSystemInfo
.InvMatrix
= _CoordSystemInfo
.Matrix
->inverted();
1144 ///=======================================================================================
1145 void CParticleSystem::setUserMatrix(const NLMISC::CMatrix
*m
)
1147 NL_PS_FUNC_MAIN(CParticleSystem_setUserMatrix
)
1148 if (!_UserCoordSystemInfo
) return; // no process in the system references the user matrix
1149 CCoordSystemInfo
&csi
= _UserCoordSystemInfo
->CoordSystemInfo
;
1151 if (_SystemDate
== 0.f
)
1153 csi
.OldPos
= m
? m
->getPos() : getSysMat().getPos(); // _CoordSystemInfo.Matrix is relevant if at least one call to setSysMat has been performed before
1156 csi
.InvMatrix
= csi
.Matrix
->inverted();
1157 // build conversion matrix between father user matrix & fx matrix
1158 // TODO : lazy evaluation for this ?
1159 _UserCoordSystemInfo
->UserBasisToFXBasis
= _CoordSystemInfo
.InvMatrix
* *(csi
.Matrix
);
1160 _UserCoordSystemInfo
->FXBasisToUserBasis
= csi
.InvMatrix
* getSysMat();
1163 ///=======================================================================================
1164 bool CParticleSystem::hasOpaqueObjects(void) const
1166 NL_PS_FUNC_MAIN(CParticleSystem_hasOpaqueObjects
)
1167 /// for each process
1168 for (TProcessVect::const_iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
1170 if ((*it
)->isLocated())
1172 CPSLocated
*loc
= static_cast<CPSLocated
*>(*it
);
1173 for (uint k
= 0; k
< loc
->getNbBoundObjects(); ++k
)
1175 CPSLocatedBindable
*lb
= loc
->getBoundObject(k
);
1176 if (lb
->getType() == PSParticle
)
1178 if (((CPSParticle
*) lb
)->hasOpaqueFaces()) return true;
1186 ///=======================================================================================
1187 bool CParticleSystem::hasTransparentObjects(void) const
1189 NL_PS_FUNC_MAIN(CParticleSystem_hasTransparentObjects
)
1190 /// for each process
1191 for (TProcessVect::const_iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
1193 if ((*it
)->isLocated())
1195 CPSLocated
*loc
= static_cast<CPSLocated
*>(*it
);
1196 for (uint k
= 0; k
< loc
->getNbBoundObjects(); ++k
)
1198 CPSLocatedBindable
*lb
= loc
->getBoundObject(k
);
1199 if (lb
->getType() == PSParticle
)
1201 if (((CPSParticle
*) lb
)->hasTransparentFaces()) return true;
1209 ///=======================================================================================
1210 bool CParticleSystem::hasLightableObjects() const
1212 NL_PS_FUNC_MAIN(CParticleSystem_hasLightableObjects
)
1213 if (_ForceGlobalColorLighting
) return true;
1214 /// for each process
1215 for (TProcessVect::const_iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
1217 if ((*it
)->isLocated())
1219 CPSLocated
*loc
= static_cast<CPSLocated
*>(*it
);
1220 for (uint k
= 0; k
< loc
->getNbBoundObjects(); ++k
)
1222 CPSLocatedBindable
*lb
= loc
->getBoundObject(k
);
1223 if (lb
->getType() == PSParticle
)
1225 if (((CPSParticle
*) lb
)->hasLightableFaces()) return true;
1226 if (((CPSParticle
*) lb
)->usesGlobalColorLighting()) return true;
1234 ///=======================================================================================
1235 void CParticleSystem::getLODVect(NLMISC::CVector
&v
, float &offset
, TPSMatrixMode matrixMode
)
1237 NL_PS_FUNC_MAIN(CParticleSystem_getLODVect
)
1240 case PSFXWorldMatrix
:
1242 const CVector tv
= getInvertedSysMat().mulVector(_InvertedViewMat
.getJ());
1243 const CVector org
= getInvertedSysMat() * _InvertedViewMat
.getPos();
1244 v
= _InvCurrentViewDist
* tv
;
1248 case PSIdentityMatrix
:
1250 v
= _InvCurrentViewDist
* _InvertedViewMat
.getJ();
1251 offset
= - _InvertedViewMat
.getPos() * v
;
1256 const CVector tv
= getInvertedUserMatrix().mulVector(_InvertedViewMat
.getJ());
1257 const CVector org
= getInvertedUserMatrix() * _InvertedViewMat
.getPos();
1258 v
= _InvCurrentViewDist
* tv
;
1268 ///=======================================================================================
1269 TPSLod
CParticleSystem::getLOD(void) const
1271 NL_PS_FUNC_MAIN(CParticleSystem_getLOD
)
1272 const float dist
= fabsf(_InvCurrentViewDist
* (getSysMat().getPos() - _InvertedViewMat
.getPos()) * _InvertedViewMat
.getJ());
1273 return dist
> _LODRatio
? PSLod2
: PSLod1
;
1277 ///=======================================================================================
1278 void CParticleSystem::registerLocatedBindableExternID(uint32 id
, CPSLocatedBindable
*lb
)
1280 NL_PS_FUNC_MAIN(CParticleSystem_registerLocatedBindableExternID
)
1282 nlassert(lb
->getOwner() && lb
->getOwner()->getOwner() == this); // the located bindable must belong to that system
1284 // check that this lb hasn't been inserted yet
1285 TLBMap::iterator lbd
= _LBMap
.lower_bound(id
), ubd
= _LBMap
.upper_bound(id
);
1286 nlassert(std::find(lbd
, ubd
, TLBMap::value_type (id
, lb
)) == ubd
);
1287 nlassert(std::find(lbd
, ubd
, TLBMap::value_type (id
, lb
)) == ubd
);
1290 _LBMap
.insert(TLBMap::value_type (id
, lb
) );
1293 ///=======================================================================================
1294 void CParticleSystem::unregisterLocatedBindableExternID(CPSLocatedBindable
*lb
)
1296 NL_PS_FUNC_MAIN(CParticleSystem_unregisterLocatedBindableExternID
)
1298 nlassert(lb
->getOwner() && lb
->getOwner()->getOwner() == this); // the located bindable must belong to that system
1299 uint32 id
= lb
->getExternID();
1301 TLBMap::iterator lbd
= _LBMap
.lower_bound(id
), ubd
= _LBMap
.upper_bound(id
);
1302 TLBMap::iterator el
= std::find(lbd
, ubd
, TLBMap::value_type (id
, lb
));
1303 nlassert(el
!= ubd
);
1307 ///=======================================================================================
1308 uint
CParticleSystem::getNumLocatedBindableByExternID(uint32 id
) const
1310 NL_PS_FUNC_MAIN(CParticleSystem_getNumLocatedBindableByExternID
)
1311 return (uint
)_LBMap
.count(id
);
1314 ///=======================================================================================
1315 CPSLocatedBindable
*CParticleSystem::getLocatedBindableByExternID(uint32 id
, uint index
)
1317 NL_PS_FUNC_MAIN(CParticleSystem_getLocatedBindableByExternID
)
1318 if (index
>= _LBMap
.count(id
))
1322 TLBMap::const_iterator el
= _LBMap
.lower_bound(id
);
1324 while (left
--) ++el
;
1329 ///=======================================================================================
1330 const CPSLocatedBindable
*CParticleSystem::getLocatedBindableByExternID(uint32 id
, uint index
) const
1332 NL_PS_FUNC_MAIN(CParticleSystem_getLocatedBindableByExternID
)
1333 if (index
>= _LBMap
.count(id
))
1337 TLBMap::const_iterator el
= _LBMap
.lower_bound(id
);
1339 while (left
--) ++el
;
1343 ///=======================================================================================
1344 bool CParticleSystem::merge(CParticleSystemShape
*pss
)
1346 NL_PS_FUNC_MAIN(CParticleSystem_merge
)
1349 CParticleSystem
*duplicate
= pss
->instanciatePS(*this->_Scene
); // duplicate the p.s. to merge
1350 // now we transfer the located of the duplicated ps to this object...
1351 for (TProcessVect::iterator it
= duplicate
->_ProcessVect
.begin(); it
!= duplicate
->_ProcessVect
.end(); ++it
)
1355 for (TProcessVect::iterator clearIt
= duplicate
->_ProcessVect
.begin(); clearIt
!= it
; ++it
)
1357 detach(getIndexOf(**it
));
1359 nlwarning("<CParticleSystem::merge> Can't do the merge : this causes the system to last forever, and it has been flagged with 'BypassMaxNumIntegrationSteps'. Merge is not done.");
1364 if (getBypassMaxNumIntegrationSteps())
1368 for (TProcessVect::iterator it
= duplicate
->_ProcessVect
.begin(); it
!= duplicate
->_ProcessVect
.end(); ++it
)
1370 detach(getIndexOf(**it
));
1372 nlwarning("<CParticleSystem::merge> Can't do the merge : this causes the system to last forever, and it has been flagged with 'BypassMaxNumIntegrationSteps'. Merge is not done.");
1377 duplicate
->_ProcessVect
.clear();
1379 systemDurationChanged();
1384 ///=======================================================================================
1385 void CParticleSystem::activatePresetBehaviour(TPresetBehaviour behaviour
)
1387 NL_PS_FUNC_MAIN(CParticleSystem_activatePresetBehaviour
)
1391 setDestroyModelWhenOutOfRange(false);
1392 setDestroyCondition(none
);
1393 destroyWhenOutOfFrustum(false);
1394 setAnimType(AnimVisible
);
1395 setBypassMaxNumIntegrationSteps(false);
1396 _KeepEllapsedTimeForLifeUpdate
= false;
1398 case RunningEnvironmentFX
:
1399 setDestroyModelWhenOutOfRange(false);
1400 setDestroyCondition(none
);
1401 destroyWhenOutOfFrustum(false);
1402 setAnimType(AnimInCluster
);
1403 setBypassMaxNumIntegrationSteps(false);
1404 _KeepEllapsedTimeForLifeUpdate
= false;
1407 setDestroyModelWhenOutOfRange(true);
1408 setDestroyCondition(noMoreParticles
);
1409 destroyWhenOutOfFrustum(false);
1410 setAnimType(AnimAlways
);
1411 setBypassMaxNumIntegrationSteps(true);
1412 _KeepEllapsedTimeForLifeUpdate
= false;
1414 case LoopingSpellFX
:
1415 setDestroyModelWhenOutOfRange(false);
1416 setDestroyCondition(noMoreParticles
);
1417 destroyWhenOutOfFrustum(false);
1418 // setAnimType(AnimInCluster); // TODO : AnimAlways could be better ?
1419 setAnimType(AnimVisible
);
1420 setBypassMaxNumIntegrationSteps(false);
1421 _KeepEllapsedTimeForLifeUpdate
= false;
1424 setDestroyModelWhenOutOfRange(true);
1425 setDestroyCondition(noMoreParticles
);
1426 destroyWhenOutOfFrustum(true);
1427 setAnimType(AnimVisible
);
1428 setBypassMaxNumIntegrationSteps(false);
1429 _KeepEllapsedTimeForLifeUpdate
= false;
1431 case MovingLoopingFX
:
1432 setDestroyModelWhenOutOfRange(false);
1433 setDestroyCondition(none
);
1434 destroyWhenOutOfFrustum(false);
1435 setAnimType(AnimVisible
);
1436 setBypassMaxNumIntegrationSteps(false);
1437 _KeepEllapsedTimeForLifeUpdate
= true;
1439 case SpawnedEnvironmentFX
:
1440 setDestroyModelWhenOutOfRange(true);
1441 setDestroyCondition(noMoreParticles
);
1442 destroyWhenOutOfFrustum(false);
1443 setAnimType(AnimAlways
);
1444 setBypassMaxNumIntegrationSteps(false);
1445 _KeepEllapsedTimeForLifeUpdate
= false;
1448 setDestroyModelWhenOutOfRange(false);
1449 setDestroyCondition(none
);
1450 destroyWhenOutOfFrustum(false);
1451 setAnimType(AnimAlways
);
1452 setBypassMaxNumIntegrationSteps(false);
1453 _KeepEllapsedTimeForLifeUpdate
= true;
1456 setDestroyModelWhenOutOfRange(false);
1457 setDestroyCondition(noMoreParticles
);
1458 destroyWhenOutOfFrustum(false);
1459 setAnimType(AnimVisible
);
1460 setBypassMaxNumIntegrationSteps(false);
1461 _KeepEllapsedTimeForLifeUpdate
= true;
1465 _PresetBehaviour
= behaviour
;
1469 ///=======================================================================================
1470 CParticleSystemProcess
*CParticleSystem::detach(uint index
)
1472 NL_PS_FUNC_MAIN(CParticleSystem_detach
)
1473 nlassert(index
< _ProcessVect
.size());
1474 CParticleSystemProcess
*proc
= _ProcessVect
[index
];
1475 // release references other process may have to this system
1476 for(TProcessVect::iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
1478 (*it
)->releaseRefTo(proc
);
1480 // erase from the vector
1481 _ProcessVect
.erase(_ProcessVect
.begin() + index
);
1482 proc
->setOwner(NULL
);
1484 systemDurationChanged();
1485 // not part of this system any more
1489 ///=======================================================================================
1490 bool CParticleSystem::isProcess(const CParticleSystemProcess
*process
) const
1492 NL_PS_FUNC_MAIN(CParticleSystem_isProcess
)
1493 for(TProcessVect::const_iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
1495 if (*it
== process
) return true;
1500 ///=======================================================================================
1501 uint
CParticleSystem::getIndexOf(const CParticleSystemProcess
&process
) const
1503 NL_PS_FUNC_MAIN(CParticleSystem_getIndexOf
)
1505 nlassert(isProcess(&process
));
1507 return process
.getIndex();
1510 ///=======================================================================================
1511 uint
CParticleSystem::getNumID() const
1513 NL_PS_FUNC_MAIN(CParticleSystem_getNumID
)
1514 return (uint
)_LBMap
.size();
1517 ///=======================================================================================
1518 uint32
CParticleSystem::getID(uint index
) const
1520 NL_PS_FUNC_MAIN(CParticleSystem_getID
)
1521 TLBMap::const_iterator it
= _LBMap
.begin();
1522 for(uint k
= 0; k
< index
; ++k
)
1524 if (it
== _LBMap
.end()) return 0;
1530 ///=======================================================================================
1531 void CParticleSystem::getIDs(std::vector
<uint32
> &dest
) const
1533 NL_PS_FUNC_MAIN(CParticleSystem_getIDs
)
1534 dest
.resize(_LBMap
.size());
1536 for(TLBMap::const_iterator it
= _LBMap
.begin(); it
!= _LBMap
.end(); ++it
)
1538 dest
[k
] = it
->first
;
1543 ///=======================================================================================
1544 void CParticleSystem::interpolateFXPosDelta(NLMISC::CVector
&dest
, TAnimationTime deltaT
)
1546 NL_PS_FUNC_MAIN(CParticleSystem_interpolateFXPosDelta
)
1547 nlassert(_CoordSystemInfo
.Matrix
);
1548 dest
= _CoordSystemInfo
.CurrentDeltaPos
- (deltaT
* InverseTotalEllapsedTime
) * (_CoordSystemInfo
.Matrix
->getPos() - _CoordSystemInfo
.OldPos
);
1551 ///=======================================================================================
1552 void CParticleSystem::interpolateUserPosDelta(NLMISC::CVector
&dest
, TAnimationTime deltaT
)
1554 NL_PS_FUNC_MAIN(CParticleSystem_interpolateUserPosDelta
)
1555 if (!_UserCoordSystemInfo
)
1557 interpolateFXPosDelta(dest
, deltaT
);
1561 CCoordSystemInfo
&csi
= _UserCoordSystemInfo
->CoordSystemInfo
;
1562 dest
= csi
.CurrentDeltaPos
- (deltaT
* InverseTotalEllapsedTime
) * (csi
.Matrix
->getPos() - csi
.OldPos
);
1566 ///=======================================================================================
1567 void CParticleSystem::bindGlobalValueToUserParam(const std::string
&globalValueName
, uint userParamIndex
)
1569 NL_PS_FUNC_MAIN(CParticleSystem_bindGlobalValueToUserParam
)
1570 nlassert(userParamIndex
< MaxPSUserParam
);
1571 if (globalValueName
.empty()) // disable a user param global value
1573 if (!_UserParamGlobalValue
) return;
1574 _UserParamGlobalValue
[userParamIndex
] = NULL
;
1575 for(uint k
= 0; k
< MaxPSUserParam
; ++k
)
1577 if (_UserParamGlobalValue
[k
] != NULL
) return;
1579 // no more entry used
1580 delete _UserParamGlobalValue
;
1581 _UserParamGlobalValue
= NULL
;
1583 else // enable a user param global value
1585 if (!_UserParamGlobalValue
)
1587 // no table has been allocated yet, so create one
1588 _UserParamGlobalValue
= new const TGlobalValuesMap::value_type
*[MaxPSUserParam
];
1589 std::fill(_UserParamGlobalValue
, _UserParamGlobalValue
+ MaxPSUserParam
, (TGlobalValuesMap::value_type
*) NULL
);
1591 // has the global value be created yet ?
1592 TGlobalValuesMap::const_iterator it
= _GlobalValuesMap
.find(globalValueName
);
1593 if (it
!= _GlobalValuesMap
.end())
1595 // yes, make a reference on it
1596 _UserParamGlobalValue
[userParamIndex
] = &(*it
);
1600 // create a new entry
1601 std::pair
<TGlobalValuesMap::iterator
, bool> itPair
= _GlobalValuesMap
.insert(TGlobalValuesMap::value_type(globalValueName
, 0.f
));
1602 _UserParamGlobalValue
[userParamIndex
] = &(*(itPair
.first
));
1607 ///=======================================================================================
1608 void CParticleSystem::setGlobalValue(const std::string
&name
, float value
)
1610 NL_PS_FUNC(CParticleSystem_setGlobalValue
)
1611 nlassert(!name
.empty());
1612 NLMISC::clamp(value
, 0.f
, 1.f
);
1613 _GlobalValuesMap
[name
] = value
;
1616 ///=======================================================================================
1617 float CParticleSystem::getGlobalValue(const std::string
&name
)
1619 NL_PS_FUNC(CParticleSystem_getGlobalValue
)
1620 TGlobalValuesMap::const_iterator it
= _GlobalValuesMap
.find(name
);
1621 if (it
!= _GlobalValuesMap
.end()) return it
->second
;
1622 return 0.f
; // not a known value
1625 ///=======================================================================================
1626 std::string
CParticleSystem::getGlobalValueName(uint userParamIndex
) const
1628 NL_PS_FUNC_MAIN(CParticleSystem_getGlobalValueName
)
1629 nlassert(userParamIndex
< MaxPSUserParam
);
1630 if (!_UserParamGlobalValue
) return "";
1631 if (!_UserParamGlobalValue
[userParamIndex
]) return "";
1632 return _UserParamGlobalValue
[userParamIndex
]->first
;
1635 ///=======================================================================================
1636 void CParticleSystem::setGlobalVectorValue(const std::string
&name
, const NLMISC::CVector
&value
)
1638 NL_PS_FUNC(CParticleSystem_setGlobalVectorValue
)
1639 nlassert(!name
.empty());
1640 _GlobalVectorValuesMap
[name
] = value
;
1644 ///=======================================================================================
1645 NLMISC::CVector
CParticleSystem::getGlobalVectorValue(const std::string
&name
)
1647 NL_PS_FUNC(CParticleSystem_getGlobalVectorValue
)
1648 nlassert(!name
.empty());
1649 TGlobalVectorValuesMap::const_iterator it
= _GlobalVectorValuesMap
.find(name
);
1650 if (it
!= _GlobalVectorValuesMap
.end()) return it
->second
;
1651 return NLMISC::CVector::Null
; // not a known value
1654 ///=======================================================================================
1655 CParticleSystem::CGlobalVectorValueHandle
CParticleSystem::getGlobalVectorValueHandle(const std::string
&name
)
1657 NL_PS_FUNC(CParticleSystem_getGlobalVectorValueHandle
)
1658 nlassert(!name
.empty());
1659 TGlobalVectorValuesMap::iterator it
= _GlobalVectorValuesMap
.find(name
);
1660 if (it
== _GlobalVectorValuesMap
.end())
1662 it
= _GlobalVectorValuesMap
.insert(TGlobalVectorValuesMap::value_type(name
, NLMISC::CVector::Null
)).first
;
1664 CGlobalVectorValueHandle handle
;
1665 handle
._Value
= &it
->second
;
1666 handle
._Name
= &it
->first
;
1670 ///=======================================================================================
1671 void CParticleSystem::setMaxDistLODBias(float lodBias
)
1673 NL_PS_FUNC_MAIN(CParticleSystem_setMaxDistLODBias
)
1674 NLMISC::clamp(lodBias
, 0.f
, 1.f
);
1675 _MaxDistLODBias
= lodBias
;
1678 ///=======================================================================================
1679 bool CParticleSystem::canFinish(CPSLocatedBindable
**lastingForeverObj
/*= NULL*/) const
1681 NL_PS_FUNC_MAIN(CParticleSystem_canFinish
)
1682 if (hasLoop(lastingForeverObj
)) return false;
1683 for(uint k
= 0; k
< _ProcessVect
.size(); ++k
)
1685 if (_ProcessVect
[k
]->isLocated())
1687 CPSLocated
*loc
= static_cast<CPSLocated
*>(_ProcessVect
[k
]);
1688 if (loc
->getLastForever())
1690 for(uint l
= 0; l
< loc
->getNbBoundObjects(); ++l
)
1692 CPSEmitter
*em
= dynamic_cast<CPSEmitter
*>(loc
->getBoundObject(l
));
1693 if (em
&& em
->testEmitForever())
1695 if (lastingForeverObj
) *lastingForeverObj
= em
;
1698 CPSParticle
*p
= dynamic_cast<CPSParticle
*>(loc
->getBoundObject(l
));
1701 if (lastingForeverObj
) *lastingForeverObj
= p
;
1702 return false; // particles shouldn't live forever, too
1711 ///=======================================================================================
1712 bool CParticleSystem::hasLoop(CPSLocatedBindable
**loopingObj
/*= NULL*/) const
1714 NL_PS_FUNC_MAIN(CParticleSystem_hasLoop
)
1715 // we want to check for loop like A emit B emit A
1716 // NB : there's room for a smarter algo here, but should not be useful for now
1717 for(uint k
= 0; k
< _ProcessVect
.size(); ++k
)
1719 if (_ProcessVect
[k
]->isLocated())
1721 CPSLocated
*loc
= static_cast<CPSLocated
*>(_ProcessVect
[k
]);
1722 for(uint l
= 0; l
< loc
->getNbBoundObjects(); ++l
)
1724 CPSEmitter
*em
= dynamic_cast<CPSEmitter
*>(loc
->getBoundObject(l
));
1727 if (em
->checkLoop())
1729 if (loopingObj
) *loopingObj
= em
;
1739 ///=======================================================================================
1740 void CParticleSystem::systemDurationChanged()
1742 NL_PS_FUNC_MAIN(CParticleSystem_systemDurationChanged
)
1743 if (getAutoComputeDelayBeforeDeathConditionTest())
1745 setDelayBeforeDeathConditionTest(-1.f
);
1749 ///=======================================================================================
1750 void CParticleSystem::setAutoComputeDelayBeforeDeathConditionTest(bool computeAuto
)
1752 NL_PS_FUNC_MAIN(CParticleSystem_setAutoComputeDelayBeforeDeathConditionTest
)
1753 if (computeAuto
== _AutoComputeDelayBeforeDeathTest
) return;
1754 _AutoComputeDelayBeforeDeathTest
= computeAuto
;
1755 if (computeAuto
) setDelayBeforeDeathConditionTest(-1.f
);
1758 ///=======================================================================================
1759 TAnimationTime
CParticleSystem::getDelayBeforeDeathConditionTest() const
1761 NL_PS_FUNC_MAIN(CParticleSystem_getDelayBeforeDeathConditionTest
)
1762 if (_DelayBeforeDieTest
< 0.f
)
1764 _DelayBeforeDieTest
= evalDuration();
1766 return std::max(PS_MIN_TIMEOUT
, _DelayBeforeDieTest
);
1769 ///=======================================================================================
1770 // struct to eval duration of an emitter chain
1771 struct CToVisitEmitter
1773 float Duration
; // cumuled duration of this emitter parent emitters
1774 const CPSLocated
*Located
;
1777 ///=======================================================================================
1778 float CParticleSystem::evalDuration() const
1780 NL_PS_FUNC_MAIN(CParticleSystem_evalDuration
)
1781 std::vector
<const CPSLocated
*> visitedEmitter
;
1782 std::vector
<CToVisitEmitter
> toVisitEmitter
;
1783 float maxDuration
= 0.f
;
1784 for(uint k
= 0; k
< _ProcessVect
.size(); ++k
)
1786 if (_ProcessVect
[k
]->isLocated())
1788 bool emitterFound
= false;
1789 const CPSLocated
*loc
= static_cast<const CPSLocated
*>(_ProcessVect
[k
]);
1790 for(uint l
= 0; l
< loc
->getNbBoundObjects(); ++l
)
1792 const CPSLocatedBindable
*bind
= loc
->getBoundObject(l
);
1793 if (loc
->getSize() > 0)
1795 switch(bind
->getType())
1799 if (loc
->getLastForever())
1805 maxDuration
= std::max(maxDuration
, loc
->evalMaxDuration());
1813 CToVisitEmitter tve
;
1816 toVisitEmitter
.push_back(tve
);
1817 emitterFound
= true;
1824 visitedEmitter
.clear();
1825 while (!toVisitEmitter
.empty())
1827 const CPSLocated
*loc
= toVisitEmitter
.back().Located
;
1828 float duration
= toVisitEmitter
.back().Duration
;
1829 toVisitEmitter
.pop_back();
1830 visitedEmitter
.push_back(loc
);
1831 bool emitterFound
= false;
1832 for(uint m
= 0; m
< loc
->getNbBoundObjects(); ++m
)
1834 const CPSLocatedBindable
*bind
= loc
->getBoundObject(m
);
1835 if (bind
->getType() == PSEmitter
)
1837 const CPSEmitter
*em
= NLMISC::safe_cast
<const CPSEmitter
*>(loc
->getBoundObject(m
));
1838 const CPSLocated
*emittedType
= em
->getEmittedType();
1839 // continue if there's no loop
1840 if (std::find(visitedEmitter
.begin(), visitedEmitter
.end(), emittedType
) == visitedEmitter
.end())
1842 if (emittedType
!= NULL
)
1844 emitterFound
= true;
1845 CToVisitEmitter tve
;
1846 tve
.Located
= emittedType
;
1847 // if emitter has limited lifetime, use it
1848 if (!loc
->getLastForever())
1850 tve
.Duration
= duration
+ loc
->evalMaxDuration();
1854 // try to eval duration depending on type
1855 switch(em
->getEmissionType())
1857 case CPSEmitter::regular
:
1859 if (em
->getMaxEmissionCount() != 0)
1861 float period
= em
->getPeriodScheme() ? em
->getPeriodScheme()->getMaxValue() : em
->getPeriod();
1862 tve
.Duration
= duration
+ em
->getEmitDelay() + period
* em
->getMaxEmissionCount();
1866 tve
.Duration
= duration
+ em
->getEmitDelay();
1870 case CPSEmitter::onDeath
:
1871 case CPSEmitter::once
:
1872 case CPSEmitter::onBounce
:
1873 case CPSEmitter::externEmit
:
1874 tve
.Duration
= duration
; // can't eval duration ..
1880 toVisitEmitter
.push_back(tve
);
1887 if (!loc
->getLastForever())
1889 duration
+= loc
->evalMaxDuration();
1891 maxDuration
= std::max(maxDuration
, duration
);
1899 ///=======================================================================================
1900 bool CParticleSystem::isDestroyConditionVerified() const
1902 NL_PS_FUNC_MAIN(CParticleSystem_isDestroyConditionVerified
)
1903 if (getDestroyCondition() != CParticleSystem::none
)
1905 if (getSystemDate() > getDelayBeforeDeathConditionTest())
1907 switch (getDestroyCondition())
1909 case CParticleSystem::noMoreParticles
: return !hasParticles();
1910 case CParticleSystem::noMoreParticlesAndEmitters
: return !hasParticles() && !hasEmitters();
1911 default: nlassert(0); return false;
1918 ///=======================================================================================
1919 void CParticleSystem::setSystemDate(float date
)
1921 NL_PS_FUNC_MAIN(CParticleSystem_setSystemDate
)
1922 if (date
== _SystemDate
) return;
1924 for(uint k
= 0; k
< _ProcessVect
.size(); ++k
)
1926 _ProcessVect
[k
]->systemDateChanged();
1930 ///=======================================================================================
1931 void CParticleSystem::registerSoundServer(UPSSoundServer
*soundServer
)
1933 NL_PS_FUNC(CParticleSystem_registerSoundServer
)
1934 if (soundServer
== _SoundServer
) return;
1937 CParticleSystemManager::stopSoundForAllManagers();
1939 _SoundServer
= soundServer
;
1942 CParticleSystemManager::reactivateSoundForAllManagers();
1946 ///=======================================================================================
1947 void CParticleSystem::activateEmitters(bool active
)
1949 NL_PS_FUNC_MAIN(CParticleSystem_activateEmitters
)
1950 for(uint k
= 0; k
< getNbProcess(); ++k
)
1952 if (getProcess(k
)->isLocated())
1954 CPSLocated
*loc
= static_cast<CPSLocated
*>(getProcess(k
));
1957 for(uint l
= 0; l
< loc
->getNbBoundObjects(); ++l
)
1959 if (loc
->getBoundObject(l
)->getType() == PSEmitter
)
1960 loc
->getBoundObject(l
)->setActive(active
);
1967 ///=======================================================================================
1968 bool CParticleSystem::hasActiveEmitters() const
1970 NL_PS_FUNC_MAIN(CParticleSystem_hasActiveEmitters
)
1971 for(uint k
= 0; k
< getNbProcess(); ++k
)
1973 if (getProcess(k
)->isLocated())
1975 const CPSLocated
*loc
= static_cast<const CPSLocated
*>(getProcess(k
));
1978 for(uint l
= 0; l
< loc
->getNbBoundObjects(); ++l
)
1980 if (loc
->getBoundObject(l
)->getType() == PSEmitter
)
1982 if (loc
->getBoundObject(l
)->isActive()) return true;
1991 ///=======================================================================================
1992 bool CParticleSystem::hasEmittersTemplates() const
1994 NL_PS_FUNC_MAIN(CParticleSystem_hasEmittersTemplates
)
1995 for(uint k
= 0; k
< getNbProcess(); ++k
)
1997 if (getProcess(k
)->isLocated())
1999 const CPSLocated
*loc
= static_cast<const CPSLocated
*>(getProcess(k
));
2002 for(uint l
= 0; l
< loc
->getNbBoundObjects(); ++l
)
2004 if (loc
->getBoundObject(l
)->getType() == PSEmitter
)
2015 ///=======================================================================================
2016 void CParticleSystem::matchArraySize()
2018 NL_PS_FUNC_MAIN(CParticleSystem_matchArraySize
)
2019 for(uint k
= 0; k
< getNbProcess(); ++k
)
2021 if (getProcess(k
)->isLocated())
2023 CPSLocated
*loc
= static_cast<CPSLocated
*>(getProcess(k
));
2024 loc
->resize(loc
->getSize()); // match the max size with the number of instances
2029 ///=======================================================================================
2030 uint
CParticleSystem::getMaxNumParticles() const
2032 NL_PS_FUNC_MAIN(CParticleSystem_getMaxNumParticles
)
2034 for(uint k
= 0; k
< getNbProcess(); ++k
)
2036 if (getProcess(k
)->isLocated())
2038 const CPSLocated
*loc
= static_cast<const CPSLocated
*>(getProcess(k
));
2041 for(uint l
= 0; l
< loc
->getNbBoundObjects(); ++l
)
2043 if (loc
->getBoundObject(l
)->getType() == PSParticle
)
2045 numParts
+= loc
->getMaxSize();
2054 ///=======================================================================================
2055 uint
CParticleSystem::getCurrNumParticles() const
2057 NL_PS_FUNC_MAIN(CParticleSystem_getCurrNumParticles
)
2059 for(uint k
= 0; k
< getNbProcess(); ++k
)
2061 if (getProcess(k
)->isLocated())
2063 const CPSLocated
*loc
= static_cast<const CPSLocated
*>(getProcess(k
));
2066 for(uint l
= 0; l
< loc
->getNbBoundObjects(); ++l
)
2068 if (loc
->getBoundObject(l
)->getType() == PSParticle
)
2070 numParts
+= loc
->getSize();
2079 ///=======================================================================================
2080 void CParticleSystem::getTargeters(const CPSLocated
*target
, std::vector
<CPSTargetLocatedBindable
*> &targeters
)
2082 NL_PS_FUNC_MAIN(CParticleSystem_getTargeters
)
2084 nlassert(isProcess(target
));
2086 for(uint k
= 0; k
< getNbProcess(); ++k
)
2088 if (getProcess(k
)->isLocated())
2090 CPSLocated
*loc
= static_cast<CPSLocated
*>(getProcess(k
));
2093 for(uint l
= 0; l
< loc
->getNbBoundObjects(); ++l
)
2095 CPSTargetLocatedBindable
*targeter
= dynamic_cast<CPSTargetLocatedBindable
*>(loc
->getBoundObject(l
));
2098 for(uint m
= 0; m
< targeter
->getNbTargets(); ++m
)
2100 if (targeter
->getTarget(m
) == target
)
2102 targeters
.push_back(targeter
);
2113 ///=======================================================================================
2114 void CParticleSystem::matrixModeChanged(CParticleSystemProcess
*proc
, TPSMatrixMode oldMode
, TPSMatrixMode newMode
)
2116 NL_PS_FUNC_MAIN(CParticleSystem_matrixModeChanged
)
2118 // check that the located belong to that system
2119 nlassert(isProcess(proc
));
2120 if (oldMode
!= PSUserMatrix
&& newMode
== PSUserMatrix
)
2122 addRefForUserSysCoordInfo();
2124 else if (oldMode
== PSUserMatrix
&& newMode
!= PSUserMatrix
)
2126 releaseRefForUserSysCoordInfo();
2130 ///=======================================================================================
2131 void CParticleSystem::addRefForUserSysCoordInfo(uint numRefs
)
2133 NL_PS_FUNC_MAIN(CParticleSystem_addRefForUserSysCoordInfo
)
2134 if (!numRefs
) return;
2135 if (!_UserCoordSystemInfo
)
2137 _UserCoordSystemInfo
= new CUserCoordSystemInfo
;
2139 nlassert(_UserCoordSystemInfo
);
2140 _UserCoordSystemInfo
->NumRef
+= numRefs
;
2144 ///=======================================================================================
2145 void CParticleSystem::releaseRefForUserSysCoordInfo(uint numRefs
)
2147 NL_PS_FUNC_MAIN(CParticleSystem_releaseRefForUserSysCoordInfo
)
2148 if (!numRefs
) return;
2149 nlassert(_UserCoordSystemInfo
);
2150 nlassert(numRefs
<= _UserCoordSystemInfo
->NumRef
);
2151 _UserCoordSystemInfo
->NumRef
-= numRefs
;
2152 if (_UserCoordSystemInfo
->NumRef
== 0)
2154 delete _UserCoordSystemInfo
;
2155 _UserCoordSystemInfo
= NULL
;
2159 ///=======================================================================================
2160 void CParticleSystem::checkIntegrity()
2162 NL_PS_FUNC_MAIN(CParticleSystem_checkIntegrity
)
2164 uint userMatrixUsageCount
= 0;
2165 for (TProcessVect::iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
2167 userMatrixUsageCount
+= (*it
)->getUserMatrixUsageCount();
2169 if (userMatrixUsageCount
== 0)
2171 nlassert(_UserCoordSystemInfo
== NULL
);
2175 nlassert(_UserCoordSystemInfo
!= NULL
);
2176 nlassert(_UserCoordSystemInfo
->NumRef
== userMatrixUsageCount
);
2178 for(uint k
= 0; k
< _ProcessVect
.size(); ++k
)
2180 nlassert(_ProcessVect
[k
]->getOwner() == this);
2184 ///=======================================================================================
2185 void CParticleSystem::enumTexs(std::vector
<NLMISC::CSmartPtr
<ITexture
> > &dest
, IDriver
&drv
)
2187 NL_PS_FUNC_MAIN(CParticleSystem_enumTexs
)
2188 for (TProcessVect::iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
2190 (*it
)->enumTexs(dest
, drv
);
2194 ///=======================================================================================
2195 void CParticleSystem::setZBias(float value
)
2197 NL_PS_FUNC_MAIN(CParticleSystem_setZBias
)
2198 for (TProcessVect::iterator it
= _ProcessVect
.begin(); it
!= _ProcessVect
.end(); ++it
)
2200 (*it
)->setZBias(value
);
2204 ///=======================================================================================
2205 void CParticleSystem::getSortingByEmitterPrecedence(std::vector
<uint
> &result
) const
2207 NL_PS_FUNC_MAIN(CParticleSystem_getSortingByEmitterPrecedence
)
2209 nlassert(!hasLoop()); // should be an acyclic graph, otherwise big problem....
2211 typedef std::list
<CParticleSystemProcess
*> TProcessList
;
2212 std::vector
<TProcessList
> degreeToNodes
;
2213 std::vector
<TProcessList::iterator
> nodeToIterator(_ProcessVect
.size());
2215 std::vector
<uint
> inDegree(_ProcessVect
.size(), 0); // degree for each node
2216 for(uint k
= 0; k
< _ProcessVect
.size(); ++k
)
2218 if (_ProcessVect
[k
]->isLocated())
2220 CPSLocated
*loc
= static_cast<CPSLocated
*>(_ProcessVect
[k
]);
2221 for(uint l
= 0; l
< loc
->getNbBoundObjects(); ++l
)
2223 if (loc
->getBoundObject(l
)->getType() == PSEmitter
)
2225 CPSEmitter
*pEmit
= NLMISC::safe_cast
<CPSEmitter
*>(loc
->getBoundObject(l
));
2226 if (pEmit
->getEmittedType())
2228 ++ inDegree
[getIndexOf(*pEmit
->getEmittedType())];
2234 // make enough room in degreeToNodes.
2235 for(uint k
= 0; k
< inDegree
.size(); ++k
)
2237 if (degreeToNodes
.size() <= inDegree
[k
])
2239 degreeToNodes
.resize(inDegree
[k
] + 1);
2242 // sort nodes by degree
2243 for(uint k
= 0; k
< inDegree
.size(); ++k
)
2245 // NB : could not do resize there because we keep iterators in the list, so it's done in the previous loop
2246 degreeToNodes
[inDegree
[k
]].push_front(_ProcessVect
[k
]);
2247 nodeToIterator
[k
] = degreeToNodes
[inDegree
[k
]].begin();
2251 #define DO_SBEP_CHECK \
2252 { for(uint k = 0; k < degreeToNodes.size(); ++k) \
2254 for(TProcessList::const_iterator it = degreeToNodes[k].begin(); it != degreeToNodes[k].end(); ++it) \
2256 nlassert(inDegree[(*it)->getIndex()] == k); \
2260 #define DO_SBEP_CHECK
2264 result
.reserve(_ProcessVect
.size());
2266 if (degreeToNodes
.empty()) return;
2267 // now, do the sort -> add each node with a degree of 0, and removes arc to their son (and insert in new good list according to their degree)
2268 while (!degreeToNodes
[0].empty())
2271 CParticleSystemProcess
*pr
= degreeToNodes
[0].front();
2272 degreeToNodes
[0].pop_front();
2273 result
.push_back(getIndexOf(*pr
));
2274 if (pr
->isLocated())
2276 CPSLocated
*loc
= static_cast<CPSLocated
*>(pr
);
2277 for(uint l
= 0; l
< loc
->getNbBoundObjects(); ++l
)
2279 if (loc
->getBoundObject(l
)->getType() == PSEmitter
)
2281 CPSEmitter
*pEmit
= NLMISC::safe_cast
<CPSEmitter
*>(loc
->getBoundObject(l
));
2282 // update degree of node
2283 if (pEmit
->getEmittedType())
2285 uint emittedLocIndex
= getIndexOf(*pEmit
->getEmittedType());
2286 uint degree
= inDegree
[emittedLocIndex
];
2287 nlassert(degree
!= 0);
2288 degreeToNodes
[degree
- 1].splice(degreeToNodes
[degree
- 1].begin(), degreeToNodes
[degree
], nodeToIterator
[emittedLocIndex
]);
2289 nodeToIterator
[emittedLocIndex
] = degreeToNodes
[degree
- 1].begin(); // update iterator
2290 -- inDegree
[emittedLocIndex
];
2299 ///=======================================================================================
2300 void CParticleSystem::updateProcessIndices()
2302 NL_PS_FUNC_MAIN(CParticleSystem_updateProcessIndices
)
2303 for(uint k
= 0; k
< _ProcessVect
.size(); ++k
)
2305 _ProcessVect
[k
]->setIndex(k
);
2310 ///=======================================================================================
2311 void CParticleSystem::dumpHierarchy()
2313 NL_PS_FUNC_MAIN(CParticleSystem_dumpHierarchy
)
2314 for(uint k
= 0; k
< _ProcessVect
.size(); ++k
)
2316 CPSLocated
*loc
= dynamic_cast<CPSLocated
*>(_ProcessVect
[k
]);
2319 nlinfo("Located k : %s @%p", loc
->getName().c_str(), loc
);
2320 for(uint l
= 0; l
< loc
->getNbBoundObjects(); ++l
)
2322 CPSEmitter
*emitter
= dynamic_cast<CPSEmitter
*>(loc
->getBoundObject(l
));
2325 nlinfo(" emitter %s : emit %s @%p", emitter
->getName().c_str(), emitter
->getEmittedType() ? emitter
->getEmittedType()->getName().c_str() : "none", emitter
->getEmittedType());
2332 ///=======================================================================================
2333 void CParticleSystem::onShow(bool shown
)
2335 NL_PS_FUNC_MAIN(CParticleSystem_onShow
)
2336 for(uint k
= 0; k
< _ProcessVect
.size(); ++k
)
2338 _ProcessVect
[k
]->onShow(shown
);