00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "std3d.h"
00025
00026
00027
00028 #include "nel/3d/particle_system.h"
00029 #include "nel/3d/ps_located.h"
00030 #include "nel/3d/driver.h"
00031 #include "nel/3d/vertex_buffer.h"
00032 #include "nel/3d/material.h"
00033 #include "nel/3d/index_buffer.h"
00034 #include "nel/3d/nelu.h"
00035 #include "nel/3d/ps_util.h"
00036 #include "nel/3d/ps_particle.h"
00037 #include "nel/3d/ps_emitter.h"
00038 #include "nel/3d/ps_sound.h"
00039 #include "nel/3d/particle_system_shape.h"
00040 #include "nel/3d/ps_located.h"
00041 #include "nel/misc/aabbox.h"
00042 #include "nel/misc/file.h"
00043 #include "nel/misc/stream.h"
00044
00045
00046 #include "nel/3d/particle_system_model.h"
00047
00048
00049 #ifdef NL_DEBUG
00050 #define CHECK_INTEGRITY checkIntegrity();
00051 #else
00052 #define CHECK_INTEGRITY
00053 #endif
00054
00055
00056
00057
00058 namespace NL3D
00059 {
00060
00061 uint32 CParticleSystem::NbParticlesDrawn = 0;
00062 UPSSoundServer * CParticleSystem::_SoundServer = NULL;
00063 CParticleSystem::TGlobalValuesMap CParticleSystem::_GlobalValuesMap;
00064 CParticleSystem::TGlobalVectorValuesMap CParticleSystem::_GlobalVectorValuesMap;
00065
00066
00067 TAnimationTime CParticleSystem::EllapsedTime = 0.f;
00068 TAnimationTime CParticleSystem::InverseTotalEllapsedTime = 0.f;
00069 TAnimationTime CParticleSystem::RealEllapsedTime = 0.f;
00070 float CParticleSystem::RealEllapsedTimeRatio = 1.f;
00071 bool CParticleSystem::InsideSimLoop = false;
00072 bool CParticleSystem::InsideRemoveLoop = false;
00073 bool CParticleSystem::InsideNewElementsLoop = false;;
00074 std::vector<NLMISC::CVector> CParticleSystem::_SpawnPos;
00075
00076
00077
00078
00079
00080
00081 #ifdef NL_DEBUG
00082 uint CParticleSystem::_NumInstances = 0;
00083 #endif
00084
00085
00086 static const float PS_MIN_TIMEOUT = 1.f;
00087 #if defined(NL_DEBUG) || defined(NL_PS_DEBUG)
00088 bool CParticleSystem::_SerialIdentifiers = true;
00089 #else
00090 bool CParticleSystem::_SerialIdentifiers = false;
00091 #endif
00092 bool CParticleSystem::_ForceDisplayBBox = false;
00093 CParticleSystemModel *CParticleSystem::OwnerModel = NULL;
00094
00095
00096
00097
00098
00100
00102
00103
00105 const float PSDefaultMaxViewDist = 300.f;
00106
00107
00108
00109
00110 CParticleSystem::CParticleSystem() : _Driver(NULL),
00111 _FontGenerator(NULL),
00112 _FontManager(NULL),
00113 _UserCoordSystemInfo(NULL),
00114 _Date(0),
00115 _LastUpdateDate(-1),
00116 _CurrEditedElementLocated(NULL),
00117 _CurrEditedElementIndex(0),
00118 _Scene(NULL),
00119 _TimeThreshold(0.15f),
00120 _SystemDate(0.f),
00121 _MaxNbIntegrations(2),
00122 _LODRatio(0.5f),
00123 _OneMinusCurrentLODRatio(0),
00124 _MaxViewDist(PSDefaultMaxViewDist),
00125 _MaxDistLODBias(0.05f),
00126 _InvMaxViewDist(1.f / PSDefaultMaxViewDist),
00127 _InvCurrentViewDist(1.f / PSDefaultMaxViewDist),
00128 _AutoLODEmitRatio(0.f),
00129 _DieCondition(none),
00130 _DelayBeforeDieTest(-1.f),
00131 _NumWantedTris(0),
00132 _AnimType(AnimInCluster),
00133 _UserParamGlobalValue(NULL),
00134 _BypassGlobalUserParam(0),
00135 _PresetBehaviour(UserBehaviour),
00136 _AutoLODStartDistPercent(0.1f),
00137 _AutoLODDegradationExponent(1),
00138 _ColorAttenuationScheme(NULL),
00139 _GlobalColor(NLMISC::CRGBA::White),
00140 _GlobalColorLighted(NLMISC::CRGBA::White),
00141 _LightingColor(NLMISC::CRGBA::White),
00142 _UserColor(NLMISC::CRGBA::White),
00143 _ComputeBBox(true),
00144 _BBoxTouched(true),
00145 _AccurateIntegration(true),
00146 _CanSlowDown(true),
00147 _DestroyModelWhenOutOfRange(false),
00148 _DestroyWhenOutOfFrustum(false),
00149 _Sharing(false),
00150 _AutoLOD(false),
00151 _KeepEllapsedTimeForLifeUpdate(false),
00152 _AutoLODSkipParticles(false),
00153 _EnableLoadBalancing(true),
00154 _EmitThreshold(true),
00155 _BypassIntegrationStepLimit(false),
00156 _ForceGlobalColorLighting(false),
00157 _AutoComputeDelayBeforeDeathTest(true),
00158 _AutoCount(false),
00159 _HiddenAtCurrentFrame(true),
00160 _HiddenAtPreviousFrame(true)
00161
00162 {
00163 NL_PS_FUNC_MAIN(CParticleSystem_CParticleSystem)
00164 std::fill(_UserParam, _UserParam + MaxPSUserParam, 0.0f);
00165 #ifdef NL_DEBUG
00166 ++_NumInstances;
00167 #endif
00168
00169 }
00170
00171
00172 std::vector<NLMISC::CSmartPtr<CParticleSystem::CSpawnVect> > CParticleSystem::_Spawns;
00173 std::vector<uint> CParticleSystem::_ParticleToRemove;
00174 std::vector<sint> CParticleSystem::_ParticleRemoveListIndex;
00175
00176
00177
00178
00181 void CParticleSystem::stopSound()
00182 {
00183 NL_PS_FUNC_MAIN(CParticleSystem_stopSound)
00184 for (uint k = 0; k < this->getNbProcess(); ++k)
00185 {
00186 CPSLocated *psl = dynamic_cast<NL3D::CPSLocated *>(this->getProcess(k));
00187 if (psl)
00188 {
00189 for (uint l = 0; l < psl->getNbBoundObjects(); ++l)
00190 {
00191 if (psl->getBoundObject(l)->getType() == PSSound)
00192 {
00193 static_cast<CPSSound *>(psl->getBoundObject(l))->stopSound();
00194 }
00195 }
00196 }
00197 }
00198 }
00199
00201 void CParticleSystem::reactivateSound()
00202 {
00203 NL_PS_FUNC_MAIN(CParticleSystem_reactivateSound)
00204 for (uint k = 0; k < this->getNbProcess(); ++k)
00205 {
00206 CPSLocated *psl = dynamic_cast<NL3D::CPSLocated *>(this->getProcess(k));
00207 if (psl)
00208 {
00209 for (uint l = 0; l < psl->getNbBoundObjects(); ++l)
00210 {
00211 if (psl->getBoundObject(l)->getType() == PSSound)
00212 {
00213 static_cast<CPSSound *>(psl->getBoundObject(l))->reactivateSound();
00214 }
00215 }
00216 }
00217 }
00218 }
00219
00220
00222 void CParticleSystem::enableLoadBalancing(bool enabled )
00223 {
00224 NL_PS_FUNC_MAIN(CParticleSystem_enableLoadBalancing)
00225 if (enabled)
00226 {
00227
00228 }
00229 _EnableLoadBalancing = enabled;
00230 }
00231
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00246 void CParticleSystem::updateNumWantedTris()
00247 {
00248 NL_PS_FUNC_MAIN(CParticleSystem_updateNumWantedTris)
00249 _NumWantedTris = 0;
00250 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00251 {
00252 _NumWantedTris += (*it)->getNumWantedTris();
00253 }
00254 }
00255
00257 float CParticleSystem::getWantedNumTris(float dist)
00258 {
00259 NL_PS_FUNC_MAIN(CParticleSystem_getWantedNumTris)
00260 if (!_EnableLoadBalancing) return 0;
00261 if (dist > _MaxViewDist) return 0;
00262 float retValue = ((1.f - dist * _InvMaxViewDist) * _NumWantedTris);
00264 return retValue;
00265 }
00266
00267
00269 void CParticleSystem::setNumTris(uint numFaces)
00270 {
00271 NL_PS_FUNC_MAIN(CParticleSystem_setNumTris)
00272 if (_EnableLoadBalancing)
00273 {
00274 float modelDist = (getSysMat().getPos() - _InvertedViewMat.getPos()).norm();
00275
00276
00277 const float epsilon = 10E-5f;
00278
00279
00280 uint wantedNumTri = (uint) getWantedNumTris(modelDist);
00281 if (numFaces >= wantedNumTri || wantedNumTri == 0 || _NumWantedTris == 0 || modelDist < epsilon)
00282 {
00283 _InvCurrentViewDist = _InvMaxViewDist;
00284 }
00285 else
00286 {
00287
00288 _InvCurrentViewDist = (_NumWantedTris - numFaces) / (_NumWantedTris * modelDist);
00289 }
00290 }
00291 else
00292 {
00293
00294 _InvCurrentViewDist = _InvMaxViewDist;
00295 }
00296 }
00297
00298
00301 CParticleSystem::~CParticleSystem()
00302 {
00303 NL_PS_FUNC_MAIN(CParticleSystem_CParticleSystemDtor)
00304 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00305 {
00306 delete *it;
00307 }
00308 if (_ColorAttenuationScheme)
00309 delete _ColorAttenuationScheme;
00310 if (_UserParamGlobalValue)
00311 delete _UserParamGlobalValue;
00312 delete _UserCoordSystemInfo;
00313 #ifdef NL_DEBUG
00314 --_NumInstances;
00315 #endif
00316 }
00317
00319 void CParticleSystem::setViewMat(const NLMISC::CMatrix &m)
00320 {
00321 NL_PS_FUNC_MAIN(CParticleSystem_setViewMat)
00322 _ViewMat = m;
00323 _InvertedViewMat = m.inverted();
00324 }
00325
00327 bool CParticleSystem::hasEmitters(void) const
00328 {
00329 NL_PS_FUNC_MAIN(CParticleSystem_hasEmitters)
00330 for (TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00331 {
00332 if ((*it)->hasEmitters()) return true;
00333 }
00334 return false;
00335 }
00336
00338 bool CParticleSystem::hasParticles() const
00339 {
00340 NL_PS_FUNC_MAIN(CParticleSystem_hasParticles)
00341 for (TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00342 {
00343 if ((*it)->hasParticles()) return true;
00344 }
00345 return false;
00346 }
00347
00349 bool CParticleSystem::hasTemporaryParticles() const
00350 {
00351 NL_PS_FUNC_MAIN(CParticleSystem_hasTemporaryParticles)
00352 for (TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00353 {
00354 if ((*it)->isLocated())
00355 {
00356 CPSLocated *loc = static_cast<CPSLocated *>(*it);
00357 if (loc->hasParticles()) return true;
00358 }
00359 }
00360 return false;
00361 }
00362
00364 void CParticleSystem::stepLocated(TPSProcessPass pass)
00365 {
00366 NL_PS_FUNC_MAIN(CParticleSystem_stepLocated)
00367 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00368 {
00369 (*it)->step(pass);
00370 }
00371 }
00372
00374 #ifndef NL_DEBUG
00375 inline
00376 #endif
00377 float CParticleSystem::getDistFromViewer() const
00378 {
00379 NL_PS_FUNC_MAIN(CParticleSystem_getDistFromViewer)
00380 const CVector d = getSysMat().getPos() - _InvertedViewMat.getPos();
00381 return d.norm();
00382 }
00383
00385 #ifndef NL_DEBUG
00386 inline
00387 #endif
00388 float CParticleSystem::updateLODRatio()
00389 {
00390 NL_PS_FUNC_MAIN(CParticleSystem_updateLODRatio)
00391 float dist = getDistFromViewer();
00392 _OneMinusCurrentLODRatio = 1.f - (dist * _InvCurrentViewDist);
00393 NLMISC::clamp(_OneMinusCurrentLODRatio, 0.f, 1.f);
00394 return dist;
00395 }
00396
00398 inline void CParticleSystem::updateColor(float distFromViewer)
00399 {
00400 NL_PS_FUNC_MAIN(CParticleSystem_updateColor)
00401 if (_ColorAttenuationScheme)
00402 {
00403 float ratio = distFromViewer * _InvMaxViewDist;
00404 NLMISC::clamp(ratio, 0.f, 1.f);
00405 _GlobalColor = _ColorAttenuationScheme->get(ratio);
00406 }
00407 else
00408 {
00409 _GlobalColor = NLMISC::CRGBA::White;
00410 }
00411 _GlobalColor.modulateFromColor(_GlobalColor, _UserColor);
00412 _GlobalColorLighted.modulateFromColor(_GlobalColor, _LightingColor);
00413 }
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00427 void CParticleSystem::step(TPass pass, TAnimationTime ellapsedTime, CParticleSystemShape &shape, CParticleSystemModel &model)
00428 {
00429 NL_PS_FUNC_MAIN(CParticleSystem_step)
00430 CHECK_INTEGRITY
00431 OwnerModel = &model;
00432 nlassert(_CoordSystemInfo.Matrix);
00433 if (_UserCoordSystemInfo)
00434 {
00435 nlassert(_CoordSystemInfo.Matrix);
00436 }
00437 switch (pass)
00438 {
00439 case SolidRender:
00440 EllapsedTime = RealEllapsedTime = ellapsedTime;
00441 RealEllapsedTimeRatio = 1.f;
00443 if (_Sharing)
00444 {
00445 float dist = updateLODRatio();
00446 updateColor(dist);
00447 }
00448 else
00449 {
00450 updateColor(getDistFromViewer());
00451 }
00452
00453 ++_Date;
00454
00455 stepLocated(PSSolidRender);
00456
00457 break;
00458 case BlendRender:
00459 EllapsedTime = RealEllapsedTime = ellapsedTime;
00460 RealEllapsedTimeRatio = 1.f;
00463 if (_Sharing)
00464 {
00465 float dist = updateLODRatio();
00466 updateColor(dist);
00467 }
00468 else
00469 {
00470 updateColor(getDistFromViewer());
00471 }
00472
00473 ++_Date;
00474
00475 stepLocated(PSBlendRender);
00476 if (_ForceDisplayBBox)
00477 {
00478 NLMISC::CAABBox box;
00479 computeBBox(box);
00480 getDriver()->setupModelMatrix(*_CoordSystemInfo.Matrix);
00481 CPSUtil::displayBBox(getDriver(), box);
00482 }
00483 break;
00484 case ToolRender:
00485 EllapsedTime = RealEllapsedTime = ellapsedTime;
00486 RealEllapsedTimeRatio = 1.f;
00487 stepLocated(PSToolRender);
00488 break;
00489 case Anim:
00490 {
00491 if (ellapsedTime <= 0.f) return;
00492
00493 if (_UserParamGlobalValue)
00494 {
00495 nlctassert(MaxPSUserParam < 8);
00496 uint8 bypassMask = 1;
00497 for(uint k = 0; k < MaxPSUserParam; ++k)
00498 {
00499 if (_UserParamGlobalValue[k] && !(_BypassGlobalUserParam & bypassMask))
00500 {
00501 _UserParam[k] = _UserParamGlobalValue[k]->second;
00502 }
00503 bypassMask <<= 1;
00504 }
00505 }
00506
00507 uint nbPass = 1;
00508 EllapsedTime = ellapsedTime;
00509 _BBoxTouched = true;
00510 if (_AccurateIntegration)
00511 {
00512 if (EllapsedTime > _TimeThreshold)
00513 {
00514 nbPass = (uint32) ceilf(EllapsedTime / _TimeThreshold);
00515 if (!_BypassIntegrationStepLimit && nbPass > _MaxNbIntegrations)
00516 {
00517 nbPass = _MaxNbIntegrations;
00518 if (_CanSlowDown)
00519 {
00520 EllapsedTime = _TimeThreshold;
00521 nlassert(_TimeThreshold != 0);
00522 InverseTotalEllapsedTime = 1.f / (_TimeThreshold * nbPass);
00523 }
00524 else
00525 {
00526 EllapsedTime = ellapsedTime / nbPass;
00527 InverseTotalEllapsedTime = ellapsedTime != 0 ? 1.f / ellapsedTime : 0.f;
00528 }
00529 }
00530 else
00531 {
00532 EllapsedTime = ellapsedTime / nbPass;
00533 InverseTotalEllapsedTime = ellapsedTime != 0 ? 1.f / ellapsedTime : 0.f;
00534 }
00535 }
00536 else
00537 {
00538 InverseTotalEllapsedTime = ellapsedTime != 0 ? 1.f / ellapsedTime : 0.f;
00539 }
00540 }
00541 else
00542 {
00543 InverseTotalEllapsedTime = ellapsedTime != 0 ? 1.f / ellapsedTime : 0.f;
00544 }
00545 updateLODRatio();
00546 {
00547 MINI_TIMER(PSAnim3)
00548 if (_AutoLOD && !_Sharing)
00549 {
00550 float currLODRatio = 1.f - _OneMinusCurrentLODRatio;
00551 if (currLODRatio <= _AutoLODStartDistPercent)
00552 {
00553 _AutoLODEmitRatio = 1.f;
00554 }
00555 else
00556 {
00557 float lodValue = (currLODRatio - 1.f) / (_AutoLODStartDistPercent - 1.f);
00558 NLMISC::clamp(lodValue, 0.f, 1.f);
00559 float finalValue = lodValue;
00560 for(uint l = 1; l < _AutoLODDegradationExponent; ++l)
00561 {
00562 finalValue *= lodValue;
00563 }
00564 _AutoLODEmitRatio = (1.f - _MaxDistLODBias) * finalValue + _MaxDistLODBias;
00565 if (_AutoLODEmitRatio < 0.f) _AutoLODEmitRatio = 0.f;
00566 }
00567 }
00568 }
00569 {
00570 MINI_TIMER(PSAnim4)
00571
00572 if (!_HiddenAtPreviousFrame && !_HiddenAtCurrentFrame)
00573 {
00574 _CoordSystemInfo.CurrentDeltaPos = _CoordSystemInfo.OldPos - _CoordSystemInfo.Matrix->getPos();
00575 if (_UserCoordSystemInfo)
00576 {
00577 CCoordSystemInfo &csi = _UserCoordSystemInfo->CoordSystemInfo;
00578 csi.CurrentDeltaPos = csi.OldPos - csi.Matrix->getPos();
00579 }
00580 }
00581 else
00582 {
00583 _CoordSystemInfo.CurrentDeltaPos = NLMISC::CVector::Null;
00584 _CoordSystemInfo.OldPos = _CoordSystemInfo.Matrix->getPos();
00585 if (_UserCoordSystemInfo)
00586 {
00587 CCoordSystemInfo &csi = _UserCoordSystemInfo->CoordSystemInfo;
00588 csi.CurrentDeltaPos = NLMISC::CVector::Null;
00589 csi.OldPos = csi.Matrix->getPos();
00590 }
00591 }
00592
00593
00594 }
00595 RealEllapsedTime = _KeepEllapsedTimeForLifeUpdate ? (ellapsedTime / nbPass)
00596 : EllapsedTime;
00597 RealEllapsedTimeRatio = RealEllapsedTime / EllapsedTime;
00598
00599
00600
00601
00602
00603
00604 if (shape._ProcessOrder.empty())
00605 {
00606 getSortingByEmitterPrecedence(shape._ProcessOrder);
00607 }
00608
00609 InsideSimLoop = true;
00610
00611 uint numProcess = _ProcessVect.size();
00612 if (numProcess > _Spawns.size())
00613 {
00614 uint oldSize = _Spawns.size();
00615 _Spawns.resize(numProcess);
00616 for(uint k = oldSize; k < numProcess; ++k)
00617 {
00618 _Spawns[k] = new CSpawnVect;
00619 }
00620 }
00621 for(uint k = 0; k < numProcess; ++k)
00622 {
00623 if (!_ProcessVect[k]->isLocated()) continue;
00624 CPSLocated *loc = static_cast<CPSLocated *>(_ProcessVect[k]);
00625 if (loc->hasLODDegradation())
00626 {
00627 loc->doLODDegradation();
00628 }
00629 _Spawns[k]->MaxNumSpawns = loc->getMaxSize();
00630 }
00631 do
00632 {
00633 {
00634 MINI_TIMER(PSAnim5)
00635
00636 _CoordSystemInfo.CurrentDeltaPos += (_CoordSystemInfo.Matrix->getPos() - _CoordSystemInfo.OldPos) * (EllapsedTime * InverseTotalEllapsedTime);
00637 if (_UserCoordSystemInfo)
00638 {
00639 CCoordSystemInfo &csi = _UserCoordSystemInfo->CoordSystemInfo;
00640 csi.CurrentDeltaPos += (csi.Matrix->getPos() - csi.OldPos) * (EllapsedTime * InverseTotalEllapsedTime);
00641 }
00642 }
00643 for(uint k = 0; k < shape._ProcessOrder.size(); ++k)
00644 {
00645 if (!_ProcessVect[shape._ProcessOrder[k]]->isLocated()) continue;
00646 CPSLocated *loc = static_cast<CPSLocated *>(_ProcessVect[shape._ProcessOrder[k]]);
00647 if (_ParticleRemoveListIndex.size() < loc->getMaxSize())
00648 {
00649 _ParticleRemoveListIndex.resize(loc->getMaxSize(), -1);
00650 }
00651 if (loc->getSize() != 0)
00652 {
00653 #ifdef NL_DEBUG
00654 loc->checkLife();
00655 #endif
00656 if (loc->hasCollisionInfos())
00657 {
00658 loc->resetCollisions(loc->getSize());
00659 }
00660
00661 if (!loc->isParametricMotionEnabled()) loc->computeMotion();
00662
00663 loc->updateLife();
00664
00665
00666 loc->computeSpawns(0, false);
00667 if (loc->hasCollisionInfos()) loc->updateCollisions();
00668
00669 if (!_ParticleToRemove.empty())
00670 {
00671 loc->removeOldParticles();
00672 }
00673 #ifdef NL_DEBUG
00674 loc->checkLife();
00675 #endif
00676 }
00677 if (!_Spawns[shape._ProcessOrder[k]]->SpawnInfos.empty())
00678 {
00679 uint insertionIndex = loc->getSize();
00680
00681 loc->addNewlySpawnedParticles();
00682 if (insertionIndex != loc->getSize())
00683 {
00684
00685 if (loc->hasCollisionInfos())
00686 {
00687 loc->resetCollisions(loc->getSize());
00688 loc->computeNewParticleMotion(insertionIndex);
00689 }
00690 loc->computeSpawns(insertionIndex, true);
00691 if (loc->hasCollisionInfos()) loc->updateCollisions();
00692
00693 if (!_ParticleToRemove.empty())
00694 {
00695 loc->removeOldParticles();
00696 }
00697 #ifdef NL_DEBUG
00698 loc->checkLife();
00699 #endif
00700 }
00701 }
00702 if (!loc->isParametricMotionEnabled()) loc->computeForces();
00703 }
00704 _SystemDate += RealEllapsedTime;
00705 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00706 {
00707 #ifdef NL_DEBUG
00708 if ((*it)->isLocated())
00709 {
00710 CPSLocated *loc = static_cast<CPSLocated *>(*it);
00711 loc->checkLife();
00712 }
00713 #endif
00714 {
00715 MINI_TIMER(PSAnim2)
00716 (*it)->step(PSMotion);
00717 }
00718 }
00719 }
00720 while (--nbPass);
00721 {
00722 MINI_TIMER(PSAnim10)
00723
00724 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00725 {
00726 if ((*it)->isParametricMotionEnabled()) (*it)->performParametricMotion(_SystemDate);
00727 }
00728 }
00729
00730 updateNumWantedTris();
00731
00732 InsideSimLoop = false;
00733
00734 {
00735 MINI_TIMER(PSAnim11)
00736
00737 _CoordSystemInfo.OldPos = _CoordSystemInfo.Matrix->getPos();
00738 if (_UserCoordSystemInfo)
00739 {
00740 CCoordSystemInfo &csi = _UserCoordSystemInfo->CoordSystemInfo;
00741 csi.OldPos = csi.Matrix->getPos();
00742 }
00743
00744 _HiddenAtPreviousFrame = _HiddenAtCurrentFrame;
00745 }
00746 }
00747 }
00748 RealEllapsedTimeRatio = 0.f;
00749 CHECK_INTEGRITY
00750 }
00751
00752
00754 void CParticleSystem::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00755 {
00756 CHECK_INTEGRITY
00757 NL_PS_FUNC_MAIN(CParticleSystem_serial)
00758 sint version = f.serialVersion(19);
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777 if (!f.isReading())
00778 {
00779 if (_AutoComputeDelayBeforeDeathTest)
00780 {
00781 _DelayBeforeDieTest = evalDuration();
00782 }
00783 }
00784
00785 if (version < 19)
00786 {
00787 NLMISC::CMatrix dummy;
00788 f.serial(dummy);
00789 }
00790 f.serial(_Date);
00791 if (f.isReading())
00792 {
00793 delete _ColorAttenuationScheme;
00794
00795 _LBMap.clear();
00796
00797 TProcessVect::iterator it;
00798 for (it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00799 {
00800 delete (*it);
00801 }
00802
00803 _ProcessVect.clear();
00804
00805 f.serialContPolyPtr(_ProcessVect);
00806
00807 _FontGenerator = NULL;
00808 _FontManager = NULL;
00809 if (_UserParamGlobalValue)
00810 delete _UserParamGlobalValue;
00811 _UserParamGlobalValue = NULL;
00812 _BypassGlobalUserParam = 0;
00813
00814 delete _UserCoordSystemInfo;
00815 _UserCoordSystemInfo = NULL;
00816 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00817 {
00818 addRefForUserSysCoordInfo((*it)->getUserMatrixUsageCount());
00819 }
00820 }
00821 else
00822 {
00823 f.serialContPolyPtr(_ProcessVect);
00824 }
00825
00826 if (version > 1)
00827 {
00828 if (f.isReading() && !getSerializeIdentifierFlag())
00829 {
00830
00831 sint32 len;
00832 f.serial(len);
00833 f.seek(len, NLMISC::IStream::current);
00834 }
00835 else
00836 {
00837 f.serial(_Name);
00838 }
00839 }
00840
00841 if (version > 2)
00842 {
00843 bool accurateIntegration = _AccurateIntegration;
00844 f.serial(accurateIntegration);
00845 _AccurateIntegration = accurateIntegration;
00846 if (_AccurateIntegration)
00847 {
00848 bool canSlowDown = _CanSlowDown;
00849 f.serial(canSlowDown);
00850 _CanSlowDown = canSlowDown;
00851 f.serial(_TimeThreshold, _MaxNbIntegrations);
00852 }
00853 f.serial(_InvMaxViewDist, _LODRatio);
00854 _MaxViewDist = 1.f / _InvMaxViewDist;
00855 _InvCurrentViewDist = _InvMaxViewDist;
00856 }
00857
00858 if (version > 3)
00859 {
00860 bool computeBBox = _ComputeBBox;
00861 f.serial(computeBBox);
00862 _ComputeBBox = computeBBox;
00863 if (!computeBBox)
00864 {
00865 f.serial(_PreComputedBBox);
00866 }
00867 }
00868
00869 if (version > 4)
00870 {
00871 bool destroyModelWhenOutOfRange = _DestroyModelWhenOutOfRange;
00872 f.serial(destroyModelWhenOutOfRange);
00873 _DestroyModelWhenOutOfRange = destroyModelWhenOutOfRange;
00874 f.serialEnum(_DieCondition);
00875 if (_DieCondition != none)
00876 {
00877 f.serial(_DelayBeforeDieTest);
00878 }
00879 }
00880
00881 if (version > 5)
00882 {
00883 bool destroyWhenOutOfFrustum = _DestroyWhenOutOfFrustum;
00884 f.serial(destroyWhenOutOfFrustum);
00885 _DestroyWhenOutOfFrustum = destroyWhenOutOfFrustum;
00886 }
00887
00888 if (version > 6 && version < 8)
00889 {
00890 bool performMotionWOOF;
00891 if (f.isReading())
00892 {
00893 f.serial(performMotionWOOF);
00894 performMotionWhenOutOfFrustum(performMotionWOOF);
00895 }
00896 else
00897 {
00898 performMotionWOOF = doesPerformMotionWhenOutOfFrustum();
00899 f.serial(performMotionWOOF);
00900 }
00901 }
00902
00903 if (version > 7)
00904 {
00905 f.serialEnum(_AnimType);
00906 f.serialEnum(_PresetBehaviour);
00907 }
00908
00909 if (version > 8)
00910 {
00911 bool sharing = _Sharing;
00912 f.serial(sharing);
00913 _Sharing = sharing;
00914 bool autoLOD = _AutoLOD;
00915 f.serial(autoLOD);
00916 _AutoLOD = autoLOD;
00917
00918 if (_AutoLOD)
00919 {
00920 f.serial(_AutoLODStartDistPercent, _AutoLODDegradationExponent);
00921 bool autoLODSkipParticles = _AutoLODSkipParticles;
00922 f.serial(autoLODSkipParticles);
00923 _AutoLODSkipParticles = autoLODSkipParticles;
00924 }
00925 bool keepEllapsedTimeForLifeUpdate = _KeepEllapsedTimeForLifeUpdate;
00926 f.serial(keepEllapsedTimeForLifeUpdate);
00927 _KeepEllapsedTimeForLifeUpdate = keepEllapsedTimeForLifeUpdate;
00928 f.serialPolyPtr(_ColorAttenuationScheme);
00929 }
00930
00931 if (version >= 11)
00932 {
00933 bool enableLoadBalancing = _EnableLoadBalancing;
00934 f.serial(enableLoadBalancing);
00935 _EnableLoadBalancing = enableLoadBalancing;
00936 }
00937
00938 if (version >= 12)
00939 {
00940
00941 nlctassert(MaxPSUserParam < 8);
00942 if (f.isReading())
00943 {
00944 uint8 mask;
00945 f.serial(mask);
00946 if (mask)
00947 {
00948 std::string globalValueName;
00949 uint8 testMask = 1;
00950 for(uint k = 0; k < MaxPSUserParam; ++k)
00951 {
00952 if (mask & testMask)
00953 {
00954 f.serial(globalValueName);
00955 bindGlobalValueToUserParam(globalValueName.c_str(), k);
00956 }
00957 testMask <<= 1;
00958 }
00959 }
00960 }
00961 else
00962 {
00963 uint8 mask = 0;
00964 if (_UserParamGlobalValue)
00965 {
00966 for(uint k = 0; k < MaxPSUserParam; ++k)
00967 {
00968 if (_UserParamGlobalValue[k]) mask |= (1 << k);
00969 }
00970 }
00971 f.serial(mask);
00972 if (_UserParamGlobalValue)
00973 {
00974 for(uint k = 0; k < MaxPSUserParam; ++k)
00975 {
00976 if (_UserParamGlobalValue[k])
00977 {
00978 std::string valueName = _UserParamGlobalValue[k]->first;
00979 f.serial(valueName);
00980 }
00981 }
00982 }
00983 }
00984 }
00985 if (version >= 13)
00986 {
00987 if (_AutoLOD && !_Sharing)
00988 {
00989 f.serial(_MaxDistLODBias);
00990 }
00991 }
00992 if (version >= 14)
00993 {
00994 bool emitThreshold = _EmitThreshold;
00995 f.serial(emitThreshold);
00996 _EmitThreshold = emitThreshold;
00997 }
00998
00999 if (version >= 15)
01000 {
01001 bool bypassIntegrationStepLimit = _BypassIntegrationStepLimit;
01002 f.serial(bypassIntegrationStepLimit);
01003 _BypassIntegrationStepLimit = bypassIntegrationStepLimit;
01004 }
01005
01006 if (version >= 17)
01007 {
01008 bool forceGlobalColorLighting = _ForceGlobalColorLighting;
01009 f.serial(forceGlobalColorLighting);
01010 _ForceGlobalColorLighting = forceGlobalColorLighting;
01011 }
01012
01013 if (version >= 18)
01014 {
01015 bool autoComputeDelayBeforeDeathTest = _AutoComputeDelayBeforeDeathTest;
01016 f.serial(autoComputeDelayBeforeDeathTest);
01017 _AutoComputeDelayBeforeDeathTest = autoComputeDelayBeforeDeathTest;
01018 }
01019 else
01020 {
01021 nlassert(f.isReading());
01022
01023 setDelayBeforeDeathConditionTest(-1.f);
01024 _AutoComputeDelayBeforeDeathTest = true;
01025 }
01026
01027 if (f.isReading())
01028 {
01029
01030 updateNumWantedTris();
01031 activatePresetBehaviour(_PresetBehaviour);
01032 updateProcessIndices();
01033 }
01034 CHECK_INTEGRITY
01035
01036
01037
01038
01039
01040
01041 }
01042
01044 bool CParticleSystem::attach(CParticleSystemProcess *ptr)
01045 {
01046 NL_PS_FUNC_MAIN(CParticleSystem_attach)
01047 nlassert(ptr);
01048 nlassert(std::find(_ProcessVect.begin(), _ProcessVect.end(), ptr) == _ProcessVect.end() );
01049
01050 _ProcessVect.push_back(ptr);
01051 ptr->setOwner(this);
01052 ptr->setIndex(_ProcessVect.size() - 1);
01053
01054 if (getBypassMaxNumIntegrationSteps())
01055 {
01056 if (!canFinish())
01057 {
01058 remove(ptr);
01059 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");
01060 return false;
01061 }
01062 }
01063 systemDurationChanged();
01064 return true;
01065 }
01066
01068 void CParticleSystem::remove(CParticleSystemProcess *ptr)
01069 {
01070 NL_PS_FUNC_MAIN(CParticleSystem_remove)
01071 TProcessVect::iterator it = std::find(_ProcessVect.begin(), _ProcessVect.end(), ptr);
01072 nlassert(it != _ProcessVect.end() );
01073 ptr->setOwner(NULL);
01074 _ProcessVect.erase(it);
01075 delete ptr;
01076 systemDurationChanged();
01077 updateProcessIndices();
01078 }
01079
01081 void CParticleSystem::forceComputeBBox(NLMISC::CAABBox &aabbox)
01082 {
01083 NL_PS_FUNC_MAIN(CParticleSystem_forceComputeBBox)
01084 bool foundOne = false;
01085 NLMISC::CAABBox tmpBox;
01086 for (TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
01087 {
01088 if ((*it)->computeBBox(tmpBox))
01089 {
01090
01091 const CMatrix &convMat = CPSLocated::getConversionMatrix(*this, PSFXWorldMatrix, (*it)->getMatrixMode());
01092 tmpBox = NLMISC::CAABBox::transformAABBox(convMat, tmpBox);
01093
01094 if (foundOne)
01095 {
01096 aabbox = NLMISC::CAABBox::computeAABBoxUnion(aabbox, tmpBox);
01097 }
01098 else
01099 {
01100 aabbox = tmpBox;
01101 foundOne = true;
01102 }
01103 }
01104 }
01105
01106 if (!foundOne)
01107 {
01108 aabbox.setCenter(NLMISC::CVector::Null);
01109 aabbox.setHalfSize(NLMISC::CVector::Null);
01110 }
01111 }
01112
01114 void CParticleSystem::computeBBox(NLMISC::CAABBox &aabbox)
01115 {
01116 NL_PS_FUNC_MAIN(CParticleSystem_computeBBox)
01117 if (!_ComputeBBox || !_BBoxTouched)
01118 {
01119 aabbox = _PreComputedBBox;
01120 return;
01121 }
01122 forceComputeBBox(aabbox);
01123 _BBoxTouched = false;
01124 _PreComputedBBox = aabbox;
01125 }
01126
01128 void CParticleSystem::setSysMat(const CMatrix *m)
01129 {
01130 NL_PS_FUNC_MAIN(CParticleSystem_setSysMat)
01131 _CoordSystemInfo.Matrix = m;
01132 if (_SystemDate == 0.f)
01133 {
01134 _CoordSystemInfo.OldPos = m ? m->getPos() : CVector::Null;
01135 }
01136 if (!m) return;
01137 _CoordSystemInfo.InvMatrix = _CoordSystemInfo.Matrix->inverted();
01138 }
01139
01141 void CParticleSystem::setUserMatrix(const NLMISC::CMatrix *m)
01142 {
01143 NL_PS_FUNC_MAIN(CParticleSystem_setUserMatrix)
01144 if (!_UserCoordSystemInfo) return;
01145 CCoordSystemInfo &csi = _UserCoordSystemInfo->CoordSystemInfo;
01146 csi.Matrix = m;
01147 if (_SystemDate == 0.f)
01148 {
01149 csi.OldPos = m ? m->getPos() : getSysMat().getPos();
01150 }
01151 if (!m) return;
01152 csi.InvMatrix = csi.Matrix->inverted();
01153
01154
01155 _UserCoordSystemInfo->UserBasisToFXBasis = _CoordSystemInfo.InvMatrix * *(csi.Matrix);
01156 _UserCoordSystemInfo->FXBasisToUserBasis = csi.InvMatrix * getSysMat();
01157 }
01158
01160 bool CParticleSystem::hasOpaqueObjects(void) const
01161 {
01162 NL_PS_FUNC_MAIN(CParticleSystem_hasOpaqueObjects)
01164 for (TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
01165 {
01166 if ((*it)->isLocated())
01167 {
01168 CPSLocated *loc = static_cast<CPSLocated *>(*it);
01169 for (uint k = 0; k < loc->getNbBoundObjects(); ++k)
01170 {
01171 CPSLocatedBindable *lb = loc->getBoundObject(k);
01172 if (lb->getType() == PSParticle)
01173 {
01174 if (((CPSParticle *) lb)->hasOpaqueFaces()) return true;
01175 }
01176 }
01177 }
01178 }
01179 return false;
01180 }
01181
01183 bool CParticleSystem::hasTransparentObjects(void) const
01184 {
01185 NL_PS_FUNC_MAIN(CParticleSystem_hasTransparentObjects)
01187 for (TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
01188 {
01189 if ((*it)->isLocated())
01190 {
01191 CPSLocated *loc = static_cast<CPSLocated *>(*it);
01192 for (uint k = 0; k < loc->getNbBoundObjects(); ++k)
01193 {
01194 CPSLocatedBindable *lb = loc->getBoundObject(k);
01195 if (lb->getType() == PSParticle)
01196 {
01197 if (((CPSParticle *) lb)->hasTransparentFaces()) return true;
01198 }
01199 }
01200 }
01201 }
01202 return false;
01203 }
01204
01206 bool CParticleSystem::hasLightableObjects() const
01207 {
01208 NL_PS_FUNC_MAIN(CParticleSystem_hasLightableObjects)
01209 if (_ForceGlobalColorLighting) return true;
01211 for (TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
01212 {
01213 if ((*it)->isLocated())
01214 {
01215 CPSLocated *loc = static_cast<CPSLocated *>(*it);
01216 for (uint k = 0; k < loc->getNbBoundObjects(); ++k)
01217 {
01218 CPSLocatedBindable *lb = loc->getBoundObject(k);
01219 if (lb->getType() == PSParticle)
01220 {
01221 if (((CPSParticle *) lb)->hasLightableFaces()) return true;
01222 if (((CPSParticle *) lb)->usesGlobalColorLighting()) return true;
01223 }
01224 }
01225 }
01226 }
01227 return false;
01228 }
01229
01231 void CParticleSystem::getLODVect(NLMISC::CVector &v, float &offset, TPSMatrixMode matrixMode)
01232 {
01233 NL_PS_FUNC_MAIN(CParticleSystem_getLODVect)
01234 switch(matrixMode)
01235 {
01236 case PSFXWorldMatrix:
01237 {
01238 const CVector tv = getInvertedSysMat().mulVector(_InvertedViewMat.getJ());
01239 const CVector org = getInvertedSysMat() * _InvertedViewMat.getPos();
01240 v = _InvCurrentViewDist * tv;
01241 offset = - org * v;
01242 }
01243 break;
01244 case PSIdentityMatrix:
01245 {
01246 v = _InvCurrentViewDist * _InvertedViewMat.getJ();
01247 offset = - _InvertedViewMat.getPos() * v;
01248 }
01249 break;
01250 case PSUserMatrix:
01251 {
01252 const CVector tv = getInvertedUserMatrix().mulVector(_InvertedViewMat.getJ());
01253 const CVector org = getInvertedUserMatrix() * _InvertedViewMat.getPos();
01254 v = _InvCurrentViewDist * tv;
01255 offset = - org * v;
01256 }
01257 break;
01258 default:
01259 nlassert(0);
01260 break;
01261 }
01262 }
01263
01265 TPSLod CParticleSystem::getLOD(void) const
01266 {
01267 NL_PS_FUNC_MAIN(CParticleSystem_getLOD)
01268 const float dist = fabsf(_InvCurrentViewDist * (getSysMat().getPos() - _InvertedViewMat.getPos()) * _InvertedViewMat.getJ());
01269 return dist > _LODRatio ? PSLod2 : PSLod1;
01270 }
01271
01272
01274 void CParticleSystem::registerLocatedBindableExternID(uint32 id, CPSLocatedBindable *lb)
01275 {
01276 NL_PS_FUNC_MAIN(CParticleSystem_registerLocatedBindableExternID)
01277 nlassert(lb);
01278 nlassert(lb->getOwner() && lb->getOwner()->getOwner() == this);
01279 #ifdef NL_DEBUG
01280
01281 TLBMap::iterator lbd = _LBMap.lower_bound(id), ubd = _LBMap.upper_bound(id);
01282 nlassert(std::find(lbd, ubd, TLBMap::value_type (id, lb)) == ubd);
01283 nlassert(std::find(lbd, ubd, TLBMap::value_type (id, lb)) == ubd );
01284
01285 #endif
01286 _LBMap.insert(TLBMap::value_type (id, lb) );
01287 }
01288
01290 void CParticleSystem::unregisterLocatedBindableExternID(CPSLocatedBindable *lb)
01291 {
01292 NL_PS_FUNC_MAIN(CParticleSystem_unregisterLocatedBindableExternID)
01293 nlassert(lb);
01294 nlassert(lb->getOwner() && lb->getOwner()->getOwner() == this);
01295 uint32 id = lb->getExternID();
01296 if (!id) return;
01297 TLBMap::iterator lbd = _LBMap.lower_bound(id), ubd = _LBMap.upper_bound(id);
01298 TLBMap::iterator el = std::find(lbd, ubd, TLBMap::value_type (id, lb));
01299 nlassert(el != ubd);
01300 _LBMap.erase(el);
01301 }
01302
01304 uint CParticleSystem::getNumLocatedBindableByExternID(uint32 id) const
01305 {
01306 NL_PS_FUNC_MAIN(CParticleSystem_getNumLocatedBindableByExternID)
01307 return _LBMap.count(id);
01308 }
01309
01311 CPSLocatedBindable *CParticleSystem::getLocatedBindableByExternID(uint32 id, uint index)
01312 {
01313 NL_PS_FUNC_MAIN(CParticleSystem_getLocatedBindableByExternID)
01314 if (index >= _LBMap.count(id))
01315 {
01316 return NULL;
01317 }
01318 TLBMap::const_iterator el = _LBMap.lower_bound(id);
01319 uint left = index;
01320 while (left--) ++el;
01321 return el->second;
01322
01323 }
01324
01326 const CPSLocatedBindable *CParticleSystem::getLocatedBindableByExternID(uint32 id, uint index) const
01327 {
01328 NL_PS_FUNC_MAIN(CParticleSystem_getLocatedBindableByExternID)
01329 if (index >= _LBMap.count(id))
01330 {
01331 return NULL;
01332 }
01333 TLBMap::const_iterator el = _LBMap.lower_bound(id);
01334 uint left = index;
01335 while (left--) ++el;
01336 return el->second;
01337 }
01338
01340 bool CParticleSystem::merge(CParticleSystemShape *pss)
01341 {
01342 NL_PS_FUNC_MAIN(CParticleSystem_merge)
01343 nlassert(pss);
01344 nlassert(_Scene);
01345 CParticleSystem *duplicate = pss->instanciatePS(*this->_Scene);
01346
01347 for (TProcessVect::iterator it = duplicate->_ProcessVect.begin(); it != duplicate->_ProcessVect.end(); ++it)
01348 {
01349 if (!attach(*it))
01350 {
01351 for (TProcessVect::iterator clearIt = duplicate->_ProcessVect.begin(); clearIt != it; ++it)
01352 {
01353 detach(getIndexOf(**it));
01354 }
01355 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.");
01356 return false;
01357 }
01358 }
01359
01360 if (getBypassMaxNumIntegrationSteps())
01361 {
01362 if (!canFinish())
01363 {
01364 for (TProcessVect::iterator it = duplicate->_ProcessVect.begin(); it != duplicate->_ProcessVect.end(); ++it)
01365 {
01366 detach(getIndexOf(**it));
01367 }
01368 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.");
01369 return false;
01370 }
01371 }
01372
01373 duplicate->_ProcessVect.clear();
01374 delete duplicate;
01375 systemDurationChanged();
01376 CHECK_INTEGRITY
01377 return true;
01378 }
01379
01381 void CParticleSystem::activatePresetBehaviour(TPresetBehaviour behaviour)
01382 {
01383 NL_PS_FUNC_MAIN(CParticleSystem_activatePresetBehaviour)
01384 switch(behaviour)
01385 {
01386 case EnvironmentFX:
01387 setDestroyModelWhenOutOfRange(false);
01388 setDestroyCondition(none);
01389 destroyWhenOutOfFrustum(false);
01390 setAnimType(AnimVisible);
01391 setBypassMaxNumIntegrationSteps(false);
01392 _KeepEllapsedTimeForLifeUpdate = false;
01393 break;
01394 case RunningEnvironmentFX:
01395 setDestroyModelWhenOutOfRange(false);
01396 setDestroyCondition(none);
01397 destroyWhenOutOfFrustum(false);
01398 setAnimType(AnimInCluster);
01399 setBypassMaxNumIntegrationSteps(false);
01400 _KeepEllapsedTimeForLifeUpdate = false;
01401 break;
01402 case SpellFX:
01403 setDestroyModelWhenOutOfRange(true);
01404 setDestroyCondition(noMoreParticles);
01405 destroyWhenOutOfFrustum(false);
01406 setAnimType(AnimAlways);
01407 setBypassMaxNumIntegrationSteps(true);
01408 _KeepEllapsedTimeForLifeUpdate = false;
01409 break;
01410 case LoopingSpellFX:
01411 setDestroyModelWhenOutOfRange(false);
01412 setDestroyCondition(noMoreParticles);
01413 destroyWhenOutOfFrustum(false);
01414
01415 setAnimType(AnimVisible);
01416 setBypassMaxNumIntegrationSteps(false);
01417 _KeepEllapsedTimeForLifeUpdate = false;
01418 break;
01419 case MinorFX:
01420 setDestroyModelWhenOutOfRange(true);
01421 setDestroyCondition(noMoreParticles);
01422 destroyWhenOutOfFrustum(true);
01423 setAnimType(AnimVisible);
01424 setBypassMaxNumIntegrationSteps(false);
01425 _KeepEllapsedTimeForLifeUpdate = false;
01426 break;
01427 case MovingLoopingFX:
01428 setDestroyModelWhenOutOfRange(false);
01429 setDestroyCondition(none);
01430 destroyWhenOutOfFrustum(false);
01431 setAnimType(AnimVisible);
01432 setBypassMaxNumIntegrationSteps(false);
01433 _KeepEllapsedTimeForLifeUpdate = true;
01434 break;
01435 case SpawnedEnvironmentFX:
01436 setDestroyModelWhenOutOfRange(true);
01437 setDestroyCondition(noMoreParticles);
01438 destroyWhenOutOfFrustum(false);
01439 setAnimType(AnimAlways);
01440 setBypassMaxNumIntegrationSteps(false);
01441 _KeepEllapsedTimeForLifeUpdate = false;
01442 break;
01443 case GroundFX:
01444 setDestroyModelWhenOutOfRange(false);
01445 setDestroyCondition(none);
01446 destroyWhenOutOfFrustum(false);
01447 setAnimType(AnimAlways);
01448 setBypassMaxNumIntegrationSteps(false);
01449 _KeepEllapsedTimeForLifeUpdate = true;
01450 break;
01451 case Projectile:
01452 setDestroyModelWhenOutOfRange(false);
01453 setDestroyCondition(noMoreParticles);
01454 destroyWhenOutOfFrustum(false);
01455 setAnimType(AnimVisible);
01456 setBypassMaxNumIntegrationSteps(false);
01457 _KeepEllapsedTimeForLifeUpdate = true;
01458 break;
01459 default: break;
01460 }
01461 _PresetBehaviour = behaviour;
01462 }
01463
01464
01466 CParticleSystemProcess *CParticleSystem::detach(uint index)
01467 {
01468 NL_PS_FUNC_MAIN(CParticleSystem_detach)
01469 nlassert(index < _ProcessVect.size());
01470 CParticleSystemProcess *proc = _ProcessVect[index];
01471
01472 for(TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
01473 {
01474 (*it)->releaseRefTo(proc);
01475 }
01476
01477 _ProcessVect.erase(_ProcessVect.begin() + index);
01478 proc->setOwner(NULL);
01479
01480 systemDurationChanged();
01481
01482 return proc;
01483 }
01484
01486 bool CParticleSystem::isProcess(const CParticleSystemProcess *process) const
01487 {
01488 NL_PS_FUNC_MAIN(CParticleSystem_isProcess)
01489 for(TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
01490 {
01491 if (*it == process) return true;
01492 }
01493 return false;
01494 }
01495
01497 uint CParticleSystem::getIndexOf(const CParticleSystemProcess &process) const
01498 {
01499 NL_PS_FUNC_MAIN(CParticleSystem_getIndexOf)
01500 #ifdef NL_DEBUG
01501 nlassert(isProcess(&process));
01502 #endif
01503 return process.getIndex();
01504 }
01505
01507 uint CParticleSystem::getNumID() const
01508 {
01509 NL_PS_FUNC_MAIN(CParticleSystem_getNumID)
01510 return _LBMap.size();
01511 }
01512
01514 uint32 CParticleSystem::getID(uint index) const
01515 {
01516 NL_PS_FUNC_MAIN(CParticleSystem_getID)
01517 TLBMap::const_iterator it = _LBMap.begin();
01518 for(uint k = 0; k < index; ++k)
01519 {
01520 if (it == _LBMap.end()) return 0;
01521 ++it;
01522 }
01523 return it->first;
01524 }
01525
01527 void CParticleSystem::getIDs(std::vector<uint32> &dest) const
01528 {
01529 NL_PS_FUNC_MAIN(CParticleSystem_getIDs)
01530 dest.resize(_LBMap.size());
01531 uint k = 0;
01532 for(TLBMap::const_iterator it = _LBMap.begin(); it != _LBMap.end(); ++it)
01533 {
01534 dest[k] = it->first;
01535 ++k;
01536 }
01537 }
01538
01540 void CParticleSystem::interpolateFXPosDelta(NLMISC::CVector &dest, TAnimationTime deltaT)
01541 {
01542 NL_PS_FUNC_MAIN(CParticleSystem_interpolateFXPosDelta)
01543 nlassert(_CoordSystemInfo.Matrix);
01544 dest = _CoordSystemInfo.CurrentDeltaPos - (deltaT * InverseTotalEllapsedTime) * (_CoordSystemInfo.Matrix->getPos() - _CoordSystemInfo.OldPos);
01545 }
01546
01548 void CParticleSystem::interpolateUserPosDelta(NLMISC::CVector &dest, TAnimationTime deltaT)
01549 {
01550 NL_PS_FUNC_MAIN(CParticleSystem_interpolateUserPosDelta)
01551 if (!_UserCoordSystemInfo)
01552 {
01553 interpolateFXPosDelta(dest, deltaT);
01554 }
01555 else
01556 {
01557 CCoordSystemInfo &csi = _UserCoordSystemInfo->CoordSystemInfo;
01558 dest = csi.CurrentDeltaPos - (deltaT * InverseTotalEllapsedTime) * (csi.Matrix->getPos() - csi.OldPos);
01559 }
01560 }
01561
01563 void CParticleSystem::bindGlobalValueToUserParam(const std::string &globalValueName, uint userParamIndex)
01564 {
01565 NL_PS_FUNC_MAIN(CParticleSystem_bindGlobalValueToUserParam)
01566 nlassert(userParamIndex < MaxPSUserParam);
01567 if (globalValueName.empty())
01568 {
01569 if (!_UserParamGlobalValue) return;
01570 _UserParamGlobalValue[userParamIndex] = NULL;
01571 for(uint k = 0; k < MaxPSUserParam; ++k)
01572 {
01573 if (_UserParamGlobalValue[k] != NULL) return;
01574 }
01575
01576 delete _UserParamGlobalValue;
01577 _UserParamGlobalValue = NULL;
01578 }
01579 else
01580 {
01581 if (!_UserParamGlobalValue)
01582 {
01583
01584 _UserParamGlobalValue = new const TGlobalValuesMap::value_type *[MaxPSUserParam];
01585 std::fill(_UserParamGlobalValue, _UserParamGlobalValue + MaxPSUserParam, (TGlobalValuesMap::value_type *) NULL);
01586 }
01587
01588 TGlobalValuesMap::const_iterator it = _GlobalValuesMap.find(globalValueName);
01589 if (it != _GlobalValuesMap.end())
01590 {
01591
01592 _UserParamGlobalValue[userParamIndex] = &(*it);
01593 }
01594 else
01595 {
01596
01597 std::pair<TGlobalValuesMap::iterator, bool> itPair = _GlobalValuesMap.insert(TGlobalValuesMap::value_type(globalValueName, 0.f));
01598 _UserParamGlobalValue[userParamIndex] = &(*(itPair.first));
01599 }
01600 }
01601 }
01602
01604 void CParticleSystem::setGlobalValue(const std::string &name, float value)
01605 {
01606 NL_PS_FUNC(CParticleSystem_setGlobalValue)
01607 nlassert(!name.empty());
01608 NLMISC::clamp(value, 0.f, 1.f);
01609 _GlobalValuesMap[name] = value;
01610 }
01611
01613 float CParticleSystem::getGlobalValue(const std::string &name)
01614 {
01615 NL_PS_FUNC(CParticleSystem_getGlobalValue)
01616 TGlobalValuesMap::const_iterator it = _GlobalValuesMap.find(name);
01617 if (it != _GlobalValuesMap.end()) return it->second;
01618 return 0.f;
01619 }
01620
01622 std::string CParticleSystem::getGlobalValueName(uint userParamIndex) const
01623 {
01624 NL_PS_FUNC_MAIN(CParticleSystem_getGlobalValueName)
01625 nlassert(userParamIndex < MaxPSUserParam);
01626 if (!_UserParamGlobalValue) return "";
01627 if (!_UserParamGlobalValue[userParamIndex]) return "";
01628 return _UserParamGlobalValue[userParamIndex]->first;
01629 }
01630
01632 void CParticleSystem::setGlobalVectorValue(const std::string &name, const NLMISC::CVector &value)
01633 {
01634 NL_PS_FUNC(CParticleSystem_setGlobalVectorValue)
01635 nlassert(!name.empty());
01636 _GlobalVectorValuesMap[name] = value;
01637 }
01638
01639
01641 NLMISC::CVector CParticleSystem::getGlobalVectorValue(const std::string &name)
01642 {
01643 NL_PS_FUNC(CParticleSystem_getGlobalVectorValue)
01644 nlassert(!name.empty());
01645 TGlobalVectorValuesMap::const_iterator it = _GlobalVectorValuesMap.find(name);
01646 if (it != _GlobalVectorValuesMap.end()) return it->second;
01647 return NLMISC::CVector::Null;
01648 }
01649
01651 CParticleSystem::CGlobalVectorValueHandle CParticleSystem::getGlobalVectorValueHandle(const std::string &name)
01652 {
01653 NL_PS_FUNC(CParticleSystem_getGlobalVectorValueHandle)
01654 nlassert(!name.empty());
01655 TGlobalVectorValuesMap::iterator it = _GlobalVectorValuesMap.find(name);
01656 if (it == _GlobalVectorValuesMap.end())
01657 {
01658 it = _GlobalVectorValuesMap.insert(TGlobalVectorValuesMap::value_type(name, NLMISC::CVector::Null)).first;
01659 }
01660 CGlobalVectorValueHandle handle;
01661 handle._Value = &it->second;
01662 handle._Name = &it->first;
01663 return handle;
01664 }
01665
01667 void CParticleSystem::setMaxDistLODBias(float lodBias)
01668 {
01669 NL_PS_FUNC_MAIN(CParticleSystem_setMaxDistLODBias)
01670 NLMISC::clamp(lodBias, 0.f, 1.f);
01671 _MaxDistLODBias = lodBias;
01672 }
01673
01675 bool CParticleSystem::canFinish(CPSLocatedBindable **lastingForeverObj ) const
01676 {
01677 NL_PS_FUNC_MAIN(CParticleSystem_canFinish)
01678 if (hasLoop(lastingForeverObj)) return false;
01679 for(uint k = 0; k < _ProcessVect.size(); ++k)
01680 {
01681 if (_ProcessVect[k]->isLocated())
01682 {
01683 CPSLocated *loc = static_cast<CPSLocated *>(_ProcessVect[k]);
01684 if (loc->getLastForever())
01685 {
01686 for(uint l = 0; l < loc->getNbBoundObjects(); ++l)
01687 {
01688 CPSEmitter *em = dynamic_cast<CPSEmitter *>(loc->getBoundObject(l));
01689 if (em && em->testEmitForever())
01690 {
01691 if (lastingForeverObj) *lastingForeverObj = em;
01692 return false;
01693 }
01694 CPSParticle *p = dynamic_cast<CPSParticle *>(loc->getBoundObject(l));
01695 if (p)
01696 {
01697 if (lastingForeverObj) *lastingForeverObj = p;
01698 return false;
01699 }
01700 }
01701 }
01702 }
01703 }
01704 return true;
01705 }
01706
01708 bool CParticleSystem::hasLoop(CPSLocatedBindable **loopingObj ) const
01709 {
01710 NL_PS_FUNC_MAIN(CParticleSystem_hasLoop)
01711
01712
01713 for(uint k = 0; k < _ProcessVect.size(); ++k)
01714 {
01715 if (_ProcessVect[k]->isLocated())
01716 {
01717 CPSLocated *loc = static_cast<CPSLocated *>(_ProcessVect[k]);
01718 for(uint l = 0; l < loc->getNbBoundObjects(); ++l)
01719 {
01720 CPSEmitter *em = dynamic_cast<CPSEmitter *>(loc->getBoundObject(l));
01721 if (em)
01722 {
01723 if (em->checkLoop())
01724 {
01725 if (loopingObj) *loopingObj = em;
01726 return true;
01727 }
01728 }
01729 }
01730 }
01731 }
01732 return false;
01733 }
01734
01736 void CParticleSystem::systemDurationChanged()
01737 {
01738 NL_PS_FUNC_MAIN(CParticleSystem_systemDurationChanged)
01739 if (getAutoComputeDelayBeforeDeathConditionTest())
01740 {
01741 setDelayBeforeDeathConditionTest(-1.f);
01742 }
01743 }
01744
01746 void CParticleSystem::setAutoComputeDelayBeforeDeathConditionTest(bool computeAuto)
01747 {
01748 NL_PS_FUNC_MAIN(CParticleSystem_setAutoComputeDelayBeforeDeathConditionTest)
01749 if (computeAuto == _AutoComputeDelayBeforeDeathTest) return;
01750 _AutoComputeDelayBeforeDeathTest = computeAuto;
01751 if (computeAuto) setDelayBeforeDeathConditionTest(-1.f);
01752 }
01753
01755 TAnimationTime CParticleSystem::getDelayBeforeDeathConditionTest() const
01756 {
01757 NL_PS_FUNC_MAIN(CParticleSystem_getDelayBeforeDeathConditionTest)
01758 if (_DelayBeforeDieTest < 0.f)
01759 {
01760 _DelayBeforeDieTest = evalDuration();
01761 }
01762 return std::max(PS_MIN_TIMEOUT, _DelayBeforeDieTest);
01763 }
01764
01766
01767 struct CToVisitEmitter
01768 {
01769 float Duration;
01770 const CPSLocated *Located;
01771 };
01772
01774 float CParticleSystem::evalDuration() const
01775 {
01776 NL_PS_FUNC_MAIN(CParticleSystem_evalDuration)
01777 std::vector<const CPSLocated *> visitedEmitter;
01778 std::vector<CToVisitEmitter> toVisitEmitter;
01779 float maxDuration = 0.f;
01780 for(uint k = 0; k < _ProcessVect.size(); ++k)
01781 {
01782 if (_ProcessVect[k]->isLocated())
01783 {
01784 bool emitterFound = false;
01785 const CPSLocated *loc = static_cast<const CPSLocated *>(_ProcessVect[k]);
01786 for(uint l = 0; l < loc->getNbBoundObjects(); ++l)
01787 {
01788 const CPSLocatedBindable *bind = loc->getBoundObject(l);
01789 if (loc->getSize() > 0)
01790 {
01791 switch(bind->getType())
01792 {
01793 case PSParticle:
01794 {
01795 if (loc->getLastForever())
01796 {
01797 return -1;
01798 }
01799 else
01800 {
01801 maxDuration = std::max(maxDuration, loc->evalMaxDuration());
01802 }
01803 }
01804 break;
01805 case PSEmitter:
01806 {
01807 if (!emitterFound)
01808 {
01809 CToVisitEmitter tve;
01810 tve.Located = loc;
01811 tve.Duration = 0.f;
01812 toVisitEmitter.push_back(tve);
01813 emitterFound = true;
01814 }
01815 }
01816 break;
01817 }
01818 }
01819 }
01820 visitedEmitter.clear();
01821 while (!toVisitEmitter.empty())
01822 {
01823 const CPSLocated *loc = toVisitEmitter.back().Located;
01824 float duration = toVisitEmitter.back().Duration;
01825 toVisitEmitter.pop_back();
01826 visitedEmitter.push_back(loc);
01827 bool emitterFound = false;
01828 for(uint m = 0; m < loc->getNbBoundObjects(); ++m)
01829 {
01830 const CPSLocatedBindable *bind = loc->getBoundObject(m);
01831 if (bind->getType() == PSEmitter)
01832 {
01833 const CPSEmitter *em = NLMISC::safe_cast<const CPSEmitter *>(loc->getBoundObject(m));
01834 const CPSLocated *emittedType = em->getEmittedType();
01835
01836 if (std::find(visitedEmitter.begin(), visitedEmitter.end(), emittedType) == visitedEmitter.end())
01837 {
01838 if (emittedType != NULL)
01839 {
01840 emitterFound = true;
01841 CToVisitEmitter tve;
01842 tve.Located = emittedType;
01843
01844 if (!loc->getLastForever())
01845 {
01846 tve.Duration = duration + loc->evalMaxDuration();
01847 }
01848 else
01849 {
01850
01851 switch(em->getEmissionType())
01852 {
01853 case CPSEmitter::regular:
01854 {
01855 if (em->getMaxEmissionCount() != 0)
01856 {
01857 float period = em->getPeriodScheme() ? em->getPeriodScheme()->getMaxValue() : em->getPeriod();
01858 tve.Duration = duration + em->getEmitDelay() + period * em->getMaxEmissionCount();
01859 }
01860 else
01861 {
01862 tve.Duration = duration + em->getEmitDelay();
01863 }
01864 }
01865 break;
01866 case CPSEmitter::onDeath:
01867 case CPSEmitter::once:
01868 case CPSEmitter::onBounce:
01869 case CPSEmitter::externEmit:
01870 tve.Duration = duration;
01871 break;
01872 default:
01873 break;
01874 }
01875 }
01876 toVisitEmitter.push_back(tve);
01877 }
01878 }
01879 }
01880 }
01881 if (!emitterFound)
01882 {
01883 if (!loc->getLastForever())
01884 {
01885 duration += loc->evalMaxDuration();
01886 }
01887 maxDuration = std::max(maxDuration, duration);
01888 }
01889 }
01890 }
01891 }
01892 return maxDuration;
01893 }
01894
01896 bool CParticleSystem::isDestroyConditionVerified() const
01897 {
01898 NL_PS_FUNC_MAIN(CParticleSystem_isDestroyConditionVerified)
01899 if (getDestroyCondition() != CParticleSystem::none)
01900 {
01901 if (getSystemDate() > getDelayBeforeDeathConditionTest())
01902 {
01903 switch (getDestroyCondition())
01904 {
01905 case CParticleSystem::noMoreParticles: return !hasParticles();
01906 case CParticleSystem::noMoreParticlesAndEmitters: return !hasParticles() && !hasEmitters();
01907 default: nlassert(0); return false;
01908 }
01909 }
01910 }
01911 return false;
01912 }
01913
01915 void CParticleSystem::setSystemDate(float date)
01916 {
01917 NL_PS_FUNC_MAIN(CParticleSystem_setSystemDate)
01918 if (date == _SystemDate) return;
01919 _SystemDate = date;
01920 for(uint k = 0; k < _ProcessVect.size(); ++k)
01921 {
01922 _ProcessVect[k]->systemDateChanged();
01923 }
01924 }
01925
01927 void CParticleSystem::registerSoundServer(UPSSoundServer *soundServer)
01928 {
01929 NL_PS_FUNC(CParticleSystem_registerSoundServer)
01930 if (soundServer == _SoundServer) return;
01931 if (_SoundServer)
01932 {
01933 CParticleSystemManager::stopSoundForAllManagers();
01934 }
01935 _SoundServer = soundServer;
01936 if (_SoundServer)
01937 {
01938 CParticleSystemManager::reactivateSoundForAllManagers();
01939 }
01940 }
01941
01943 void CParticleSystem::activateEmitters(bool active)
01944 {
01945 NL_PS_FUNC_MAIN(CParticleSystem_activateEmitters)
01946 for(uint k = 0; k < getNbProcess(); ++k)
01947 {
01948 if (getProcess(k)->isLocated())
01949 {
01950 CPSLocated *loc = static_cast<CPSLocated *>(getProcess(k));
01951 if (loc)
01952 {
01953 for(uint l = 0; l < loc->getNbBoundObjects(); ++l)
01954 {
01955 if (loc->getBoundObject(l)->getType() == PSEmitter)
01956 loc->getBoundObject(l)->setActive(active);
01957 }
01958 }
01959 }
01960 }
01961 }
01962
01964 bool CParticleSystem::hasActiveEmitters() const
01965 {
01966 NL_PS_FUNC_MAIN(CParticleSystem_hasActiveEmitters)
01967 for(uint k = 0; k < getNbProcess(); ++k)
01968 {
01969 if (getProcess(k)->isLocated())
01970 {
01971 const CPSLocated *loc = static_cast<const CPSLocated *>(getProcess(k));
01972 if (loc)
01973 {
01974 for(uint l = 0; l < loc->getNbBoundObjects(); ++l)
01975 {
01976 if (loc->getBoundObject(l)->getType() == PSEmitter)
01977 {
01978 if (loc->getBoundObject(l)->isActive()) return true;
01979 }
01980 }
01981 }
01982 }
01983 }
01984 return false;
01985 }
01986
01988 bool CParticleSystem::hasEmittersTemplates() const
01989 {
01990 NL_PS_FUNC_MAIN(CParticleSystem_hasEmittersTemplates)
01991 for(uint k = 0; k < getNbProcess(); ++k)
01992 {
01993 if (getProcess(k)->isLocated())
01994 {
01995 const CPSLocated *loc = static_cast<const CPSLocated *>(getProcess(k));
01996 if (loc)
01997 {
01998 for(uint l = 0; l < loc->getNbBoundObjects(); ++l)
01999 {
02000 if (loc->getBoundObject(l)->getType() == PSEmitter)
02001 {
02002 return true;
02003 }
02004 }
02005 }
02006 }
02007 }
02008 return false;
02009 }
02010
02012 void CParticleSystem::matchArraySize()
02013 {
02014 NL_PS_FUNC_MAIN(CParticleSystem_matchArraySize)
02015 for(uint k = 0; k < getNbProcess(); ++k)
02016 {
02017 if (getProcess(k)->isLocated())
02018 {
02019 CPSLocated *loc = static_cast<CPSLocated *>(getProcess(k));
02020 loc->resize(loc->getSize());
02021 }
02022 }
02023 }
02024
02026 uint CParticleSystem::getMaxNumParticles() const
02027 {
02028 NL_PS_FUNC_MAIN(CParticleSystem_getMaxNumParticles)
02029 uint numParts = 0;
02030 for(uint k = 0; k < getNbProcess(); ++k)
02031 {
02032 if (getProcess(k)->isLocated())
02033 {
02034 const CPSLocated *loc = static_cast<const CPSLocated *>(getProcess(k));
02035 if (loc)
02036 {
02037 for(uint l = 0; l < loc->getNbBoundObjects(); ++l)
02038 {
02039 if (loc->getBoundObject(l)->getType() == PSParticle)
02040 {
02041 numParts += loc->getMaxSize();
02042 }
02043 }
02044 }
02045 }
02046 }
02047 return numParts;
02048 }
02049
02051 uint CParticleSystem::getCurrNumParticles() const
02052 {
02053 NL_PS_FUNC_MAIN(CParticleSystem_getCurrNumParticles)
02054 uint numParts = 0;
02055 for(uint k = 0; k < getNbProcess(); ++k)
02056 {
02057 if (getProcess(k)->isLocated())
02058 {
02059 const CPSLocated *loc = static_cast<const CPSLocated *>(getProcess(k));
02060 if (loc)
02061 {
02062 for(uint l = 0; l < loc->getNbBoundObjects(); ++l)
02063 {
02064 if (loc->getBoundObject(l)->getType() == PSParticle)
02065 {
02066 numParts += loc->getSize();
02067 }
02068 }
02069 }
02070 }
02071 }
02072 return numParts;
02073 }
02074
02076 void CParticleSystem::getTargeters(const CPSLocated *target, std::vector<CPSTargetLocatedBindable *> &targeters)
02077 {
02078 NL_PS_FUNC_MAIN(CParticleSystem_getTargeters)
02079 nlassert(target);
02080 nlassert(isProcess(target));
02081 targeters.clear();
02082 for(uint k = 0; k < getNbProcess(); ++k)
02083 {
02084 if (getProcess(k)->isLocated())
02085 {
02086 CPSLocated *loc = static_cast<CPSLocated *>(getProcess(k));
02087 if (loc)
02088 {
02089 for(uint l = 0; l < loc->getNbBoundObjects(); ++l)
02090 {
02091 CPSTargetLocatedBindable *targeter = dynamic_cast<CPSTargetLocatedBindable *>(loc->getBoundObject(l));
02092 if (targeter)
02093 {
02094 for(uint m = 0; m < targeter->getNbTargets(); ++m)
02095 {
02096 if (targeter->getTarget(m) == target)
02097 {
02098 targeters.push_back(targeter);
02099 break;
02100 }
02101 }
02102 }
02103 }
02104 }
02105 }
02106 }
02107 }
02108
02110 void CParticleSystem::matrixModeChanged(CParticleSystemProcess *proc, TPSMatrixMode oldMode, TPSMatrixMode newMode)
02111 {
02112 NL_PS_FUNC_MAIN(CParticleSystem_matrixModeChanged)
02113 nlassert(proc);
02114
02115 nlassert(isProcess(proc));
02116 if (oldMode != PSUserMatrix && newMode == PSUserMatrix)
02117 {
02118 addRefForUserSysCoordInfo();
02119 }
02120 else if (oldMode == PSUserMatrix && newMode != PSUserMatrix)
02121 {
02122 releaseRefForUserSysCoordInfo();
02123 }
02124 }
02125
02127 void CParticleSystem::addRefForUserSysCoordInfo(uint numRefs)
02128 {
02129 NL_PS_FUNC_MAIN(CParticleSystem_addRefForUserSysCoordInfo)
02130 if (!numRefs) return;
02131 if (!_UserCoordSystemInfo)
02132 {
02133 _UserCoordSystemInfo = new CUserCoordSystemInfo;
02134 }
02135 nlassert(_UserCoordSystemInfo)
02136 _UserCoordSystemInfo->NumRef += numRefs;
02137
02138 }
02139
02141 void CParticleSystem::releaseRefForUserSysCoordInfo(uint numRefs)
02142 {
02143 NL_PS_FUNC_MAIN(CParticleSystem_releaseRefForUserSysCoordInfo)
02144 if (!numRefs) return;
02145 nlassert(_UserCoordSystemInfo);
02146 nlassert(numRefs <= _UserCoordSystemInfo->NumRef)
02147 _UserCoordSystemInfo->NumRef -= numRefs;
02148 if (_UserCoordSystemInfo->NumRef == 0)
02149 {
02150 delete _UserCoordSystemInfo;
02151 _UserCoordSystemInfo = NULL;
02152 }
02153 }
02154
02156 void CParticleSystem::checkIntegrity()
02157 {
02158 NL_PS_FUNC_MAIN(CParticleSystem_checkIntegrity)
02159
02160 uint userMatrixUsageCount = 0;
02161 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
02162 {
02163 userMatrixUsageCount += (*it)->getUserMatrixUsageCount();
02164 }
02165 if (userMatrixUsageCount == 0)
02166 {
02167 nlassert(_UserCoordSystemInfo == NULL);
02168 }
02169 else
02170 {
02171 nlassert(_UserCoordSystemInfo != NULL);
02172 nlassert(_UserCoordSystemInfo->NumRef == userMatrixUsageCount);
02173 }
02174 for(uint k = 0; k < _ProcessVect.size(); ++k)
02175 {
02176 nlassert(_ProcessVect[k]->getOwner() == this);
02177 }
02178 }
02179
02181 void CParticleSystem::enumTexs(std::vector<NLMISC::CSmartPtr<ITexture> > &dest, IDriver &drv)
02182 {
02183 NL_PS_FUNC_MAIN(CParticleSystem_enumTexs)
02184 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
02185 {
02186 (*it)->enumTexs(dest, drv);
02187 }
02188 }
02189
02191 void CParticleSystem::setZBias(float value)
02192 {
02193 NL_PS_FUNC_MAIN(CParticleSystem_setZBias)
02194 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
02195 {
02196 (*it)->setZBias(value);
02197 }
02198 }
02199
02201 void CParticleSystem::getSortingByEmitterPrecedence(std::vector<uint> &result) const
02202 {
02203 NL_PS_FUNC_MAIN(CParticleSystem_getSortingByEmitterPrecedence)
02204 #ifdef NL_DEBUG
02205 nlassert(!hasLoop());
02206 #endif
02207 typedef std::list<CParticleSystemProcess *> TProcessList;
02208 std::vector<TProcessList> degreeToNodes;
02209 std::vector<TProcessList::iterator> nodeToIterator(_ProcessVect.size());
02210
02211 std::vector<uint> inDegree(_ProcessVect.size(), 0);
02212 for(uint k = 0; k < _ProcessVect.size(); ++k)
02213 {
02214 if (_ProcessVect[k]->isLocated())
02215 {
02216 CPSLocated *loc = static_cast<CPSLocated *>(_ProcessVect[k]);
02217 for(uint l = 0; l < loc->getNbBoundObjects(); ++l)
02218 {
02219 if (loc->getBoundObject(l)->getType() == PSEmitter)
02220 {
02221 CPSEmitter *pEmit = NLMISC::safe_cast<CPSEmitter *>(loc->getBoundObject(l));
02222 if (pEmit->getEmittedType())
02223 {
02224 ++ inDegree[getIndexOf(*pEmit->getEmittedType())];
02225 }
02226 }
02227 }
02228 }
02229 }
02230
02231 for(uint k = 0; k < inDegree.size(); ++k)
02232 {
02233 if (degreeToNodes.size() <= inDegree[k])
02234 {
02235 degreeToNodes.resize(inDegree[k] + 1);
02236 }
02237 }
02238
02239 for(uint k = 0; k < inDegree.size(); ++k)
02240 {
02241
02242 degreeToNodes[inDegree[k]].push_front(_ProcessVect[k]);
02243 nodeToIterator[k] = degreeToNodes[inDegree[k]].begin();
02244 }
02245
02246 #ifdef NL_DEBUG
02247 #define DO_SBEP_CHECK \
02248 { for(uint k = 0; k < degreeToNodes.size(); ++k) \
02249 { \
02250 for(TProcessList::const_iterator it = degreeToNodes[k].begin(); it != degreeToNodes[k].end(); ++it) \
02251 { \
02252 nlassert(inDegree[(*it)->getIndex()] == k); \
02253 } \
02254 }}
02255 #else
02256 #define DO_SBEP_CHECK
02257 #endif
02258
02259 DO_SBEP_CHECK
02260 result.reserve(_ProcessVect.size());
02261 result.clear();
02262 if (degreeToNodes.empty()) return;
02263
02264 while (!degreeToNodes[0].empty())
02265 {
02266 DO_SBEP_CHECK
02267 CParticleSystemProcess *pr = degreeToNodes[0].front();
02268 degreeToNodes[0].pop_front();
02269 result.push_back(getIndexOf(*pr));
02270 if (pr->isLocated())
02271 {
02272 CPSLocated *loc = static_cast<CPSLocated *>(pr);
02273 for(uint l = 0; l < loc->getNbBoundObjects(); ++l)
02274 {
02275 if (loc->getBoundObject(l)->getType() == PSEmitter)
02276 {
02277 CPSEmitter *pEmit = NLMISC::safe_cast<CPSEmitter *>(loc->getBoundObject(l));
02278
02279 if (pEmit->getEmittedType())
02280 {
02281 uint emittedLocIndex = getIndexOf(*pEmit->getEmittedType());
02282 uint degree = inDegree[emittedLocIndex];
02283 nlassert(degree != 0);
02284 degreeToNodes[degree - 1].splice(degreeToNodes[degree - 1].begin(), degreeToNodes[degree], nodeToIterator[emittedLocIndex]);
02285 nodeToIterator[emittedLocIndex] = degreeToNodes[degree - 1].begin();
02286 -- inDegree[emittedLocIndex];
02287 DO_SBEP_CHECK
02288 }
02289 }
02290 }
02291 }
02292 }
02293 }
02294
02296 void CParticleSystem::updateProcessIndices()
02297 {
02298 NL_PS_FUNC_MAIN(CParticleSystem_updateProcessIndices)
02299 for(uint k = 0; k < _ProcessVect.size(); ++k)
02300 {
02301 _ProcessVect[k]->setIndex(k);
02302 }
02303 }
02304
02305
02307 void CParticleSystem::dumpHierarchy()
02308 {
02309 NL_PS_FUNC_MAIN(CParticleSystem_dumpHierarchy)
02310 for(uint k = 0; k < _ProcessVect.size(); ++k)
02311 {
02312 CPSLocated *loc = dynamic_cast<CPSLocated *>(_ProcessVect[k]);
02313 if (loc)
02314 {
02315 nlinfo("Located k : %s @%x", loc->getName().c_str(), (ptrdiff_t) loc);
02316 for(uint l = 0; l < loc->getNbBoundObjects(); ++l)
02317 {
02318 CPSEmitter *emitter = dynamic_cast<CPSEmitter *>(loc->getBoundObject(l));
02319 if (emitter)
02320 {
02321 nlinfo(" emitter %s : emit %s @%x", emitter->getName().c_str(), emitter->getEmittedType() ? emitter->getEmittedType()->getName().c_str() : "none", (ptrdiff_t) emitter->getEmittedType());
02322 }
02323 }
02324 }
02325 }
02326 }
02327
02329 void CParticleSystem::onShow(bool shown)
02330 {
02331 NL_PS_FUNC_MAIN(CParticleSystem_onShow)
02332 for(uint k = 0; k < _ProcessVect.size(); ++k)
02333 {
02334 _ProcessVect[k]->onShow(shown);
02335 }
02336 }
02337
02338
02339 }