00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/particle_system.h"
00029 #include "3d/ps_located.h"
00030 #include "3d/driver.h"
00031 #include "3d/vertex_buffer.h"
00032 #include "3d/material.h"
00033 #include "3d/primitive_block.h"
00034 #include "3d/nelu.h"
00035 #include "3d/ps_util.h"
00036 #include "3d/ps_particle.h"
00037 #include "3d/ps_sound.h"
00038 #include "3d/particle_system_shape.h"
00039 #include "nel/misc/aabbox.h"
00040 #include "nel/misc/file.h"
00041 #include "nel/misc/stream.h"
00042
00043
00044
00045
00046 namespace NL3D
00047 {
00048
00049 uint32 CParticleSystem::NbParticlesDrawn = 0;
00050 UPSSoundServer * CParticleSystem::_SoundServer = NULL;
00051 CParticleSystem::TGlobalValuesMap CParticleSystem::_GlobalValuesMap;
00052 CParticleSystem::TGlobalVectorValuesMap CParticleSystem::_GlobalVectorValuesMap;
00053
00054
00056
00058
00059
00061 const float PSDefaultMaxViewDist = 300.f;
00062
00063
00064
00065
00066 CParticleSystem::CParticleSystem() : _Driver(NULL),
00067 _FontGenerator(NULL),
00068 _FontManager(NULL),
00069 _Date(0),
00070 _LastUpdateDate(-1),
00071 _CurrEditedElementLocated(NULL),
00072 _CurrEditedElementIndex(0),
00073 _Scene(NULL),
00074 _TimeThreshold(0.15f),
00075 _SystemDate(0.f),
00076 _MaxNbIntegrations(2),
00077 _LODRatio(0.5f),
00078 _OneMinusCurrentLODRatio(0),
00079 _MaxViewDist(PSDefaultMaxViewDist),
00080 _InvMaxViewDist(1.f / PSDefaultMaxViewDist),
00081 _InvCurrentViewDist(1.f / PSDefaultMaxViewDist),
00082 _DieCondition(none),
00083 _DelayBeforeDieTest(0.2f),
00084 _MaxNumFacesWanted(0),
00085 _AnimType(AnimInCluster),
00086 _UserParamGlobalValue(NULL),
00087 _BypassGlobalUserParam(0),
00088 _PresetBehaviour(UserBehaviour),
00089 _AutoLODStartDistPercent(0.3f),
00090 _AutoLODDegradationExponent(1),
00091 _ColorAttenuationScheme(NULL),
00092 _GlobalColor(NLMISC::CRGBA::White),
00093 _ComputeBBox(true),
00094 _BBoxTouched(true),
00095 _AccurateIntegration(true),
00096 _CanSlowDown(true),
00097 _DestroyModelWhenOutOfRange(false),
00098 _DestroyWhenOutOfFrustum(false),
00099 _Sharing(false),
00100 _AutoLOD(false),
00101 _KeepEllapsedTimeForLifeUpdate(false),
00102 _AutoLODSkipParticles(false),
00103 _EnableLoadBalancing(true),
00104 _InverseEllapsedTime(0.f),
00105 _CurrentDeltaPos(NLMISC::CVector::Null),
00106 _DeltaPos(NLMISC::CVector::Null)
00107
00108 {
00109 std::fill(_UserParam, _UserParam + MaxPSUserParam, 0);
00110 }
00111
00112
00115 void CParticleSystem::stopSound()
00116 {
00117 for (uint k = 0; k < this->getNbProcess(); ++k)
00118 {
00119 CPSLocated *psl = dynamic_cast<NL3D::CPSLocated *>(this->getProcess(k));
00120 if (psl)
00121 {
00122 for (uint l = 0; l < psl->getNbBoundObjects(); ++l)
00123 {
00124 if (psl->getBoundObject(l)->getType() == PSSound)
00125 {
00126 static_cast<CPSSound *>(psl->getBoundObject(l))->stopSound();
00127
00128 }
00129 }
00130 }
00131 }
00132 }
00133
00135 void CParticleSystem::reactivateSound()
00136 {
00137 for (uint k = 0; k < this->getNbProcess(); ++k)
00138 {
00139 CPSLocated *psl = dynamic_cast<NL3D::CPSLocated *>(this->getProcess(k));
00140 if (psl)
00141 {
00142 for (uint l = 0; l < psl->getNbBoundObjects(); ++l)
00143 {
00144 if (psl->getBoundObject(l)->getType() == NL3D::PSSound)
00145 {
00146 static_cast<CPSSound *>(psl->getBoundObject(l))->reactivateSound();
00147 }
00148 }
00149 }
00150 }
00151 }
00152
00153
00155 void CParticleSystem::enableLoadBalancing(bool enabled )
00156 {
00157 if (enabled)
00158 {
00159 notifyMaxNumFacesChanged();
00160 }
00161 _EnableLoadBalancing = enabled;
00162 }
00163
00165 void CParticleSystem::notifyMaxNumFacesChanged(void)
00166 {
00167 if (!_EnableLoadBalancing) return;
00168 _MaxNumFacesWanted = 0;
00169 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00170 {
00171 _MaxNumFacesWanted += (*it)->querryMaxWantedNumFaces();
00172 }
00173 }
00174
00175
00177 float CParticleSystem::getWantedNumTris(float dist)
00178 {
00179 if (!_EnableLoadBalancing) return 0;
00180 if (dist > _MaxViewDist) return 0;
00181 float retValue = ((1.f - dist * _InvMaxViewDist) * _MaxNumFacesWanted);
00183 return retValue;
00184 }
00185
00186
00188 void CParticleSystem::setNumTris(uint numFaces)
00189 {
00190 if (_EnableLoadBalancing)
00191 {
00192 float modelDist = (_SysMat.getPos() - _InvertedViewMat.getPos()).norm();
00193
00194
00195 const float epsilon = 10E-5f;
00196
00197
00198 uint wantedNumTri = (uint) getWantedNumTris(modelDist);
00199 if (numFaces >= wantedNumTri || wantedNumTri == 0 || _MaxNumFacesWanted == 0 || modelDist < epsilon)
00200 {
00201 _InvCurrentViewDist = _InvMaxViewDist;
00202 }
00203 else
00204 {
00205
00206 _InvCurrentViewDist = (_MaxNumFacesWanted - numFaces) / ( _MaxNumFacesWanted * modelDist);
00207 }
00208 }
00209 else
00210 {
00211
00212 _InvCurrentViewDist = _InvMaxViewDist;
00213 }
00214 }
00215
00216
00219 CParticleSystem::~CParticleSystem()
00220 {
00221 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00222 {
00223 delete *it;
00224 }
00225 delete _ColorAttenuationScheme;
00226 delete _UserParamGlobalValue;
00227 }
00228
00230 void CParticleSystem::setViewMat(const NLMISC::CMatrix &m)
00231 {
00232 _ViewMat = m;
00233 _InvertedViewMat = m.inverted();
00234 }
00235
00237 bool CParticleSystem::hasEmitters(void) const
00238 {
00239 for (TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00240 {
00241 if ((*it)->hasEmitters()) return true;
00242 }
00243 return false;
00244 }
00245
00247 bool CParticleSystem::hasParticles(void) const
00248 {
00249 for (TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00250 {
00251 if ((*it)->hasParticles()) return true;
00252 }
00253 return false;
00254 }
00255
00257 void CParticleSystem::stepLocated(TPSProcessPass pass, TAnimationTime et, TAnimationTime realEt)
00258 {
00259 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00260 {
00261 (*it)->step(pass, et, realEt);
00262 }
00263 }
00264
00265
00267 inline void CParticleSystem::updateLODRatio()
00268 {
00269
00270 CVector sysPos = _SysMat.getPos();
00271 CVector obsPos = _InvertedViewMat.getPos();
00272 const CVector d = _SysMat.getPos() - _InvertedViewMat.getPos();
00273 _OneMinusCurrentLODRatio = 1.f - (d.norm() * _InvCurrentViewDist);
00274 NLMISC::clamp(_OneMinusCurrentLODRatio, 0.f, 1.f);
00275 }
00276
00278 inline void CParticleSystem::updateColor()
00279 {
00280 if (_ColorAttenuationScheme)
00281 {
00282 float ratio = 1.00f - _OneMinusCurrentLODRatio;
00283 _GlobalColor = _ColorAttenuationScheme->get(ratio > 0.f ? ratio : 0.f);
00284 }
00285 }
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00298 void CParticleSystem::step(TPass pass, TAnimationTime ellapsedTime)
00299 {
00300 switch (pass)
00301 {
00302 case SolidRender:
00304 if (_Sharing)
00305 {
00306 updateLODRatio();
00307 }
00308
00309 ++_Date;
00310
00311 updateColor();
00312 stepLocated(PSSolidRender, ellapsedTime, ellapsedTime);
00313
00314 break;
00315 case BlendRender:
00317 if (_Sharing)
00318 {
00319 updateLODRatio();
00320 }
00321
00322 ++_Date;
00323
00324 updateColor();
00325 stepLocated(PSBlendRender, ellapsedTime, ellapsedTime);
00326 break;
00327 case ToolRender:
00328 stepLocated(PSToolRender, ellapsedTime, ellapsedTime);
00329 break;
00330 case Anim:
00331 {
00332
00333 if (_UserParamGlobalValue)
00334 {
00335 nlctassert(MaxPSUserParam < 8);
00336 uint8 bypassMask = 1;
00337 for(uint k = 0; k < MaxPSUserParam; ++k)
00338 {
00339 if (_UserParamGlobalValue[k] && !(_BypassGlobalUserParam & bypassMask))
00340 {
00341 _UserParam[k] = _UserParamGlobalValue[k]->second;
00342 }
00343 bypassMask <<= 1;
00344 }
00345 }
00346
00347 _BBoxTouched = true;
00348 TAnimationTime et = ellapsedTime;
00349 uint nbPass = 1;
00350 if (_AccurateIntegration)
00351 {
00352 if (et > _TimeThreshold)
00353 {
00354 nbPass = (uint32) ceilf(et / _TimeThreshold);
00355 if (nbPass > _MaxNbIntegrations)
00356 {
00357 nbPass = _MaxNbIntegrations;
00358 if (_CanSlowDown)
00359 {
00360 et = _TimeThreshold;
00361 nlassert(_TimeThreshold != 0);
00362 _InverseEllapsedTime = 1.f / (_TimeThreshold * nbPass);
00363 }
00364 else
00365 {
00366 et = ellapsedTime / nbPass;
00367 _InverseEllapsedTime = ellapsedTime != 0 ? 1.f / ellapsedTime : 0.f;
00368 }
00369 }
00370 else
00371 {
00372 et = ellapsedTime / nbPass;
00373 _InverseEllapsedTime = ellapsedTime != 0 ? 1.f / ellapsedTime : 0.f;
00374 }
00375 }
00376 else
00377 {
00378 _InverseEllapsedTime = ellapsedTime != 0 ? 1.f / ellapsedTime : 0.f;
00379 }
00380 }
00381 else
00382 {
00383 _InverseEllapsedTime = ellapsedTime != 0 ? 1.f / ellapsedTime : 0.f;
00384 }
00385 updateLODRatio();
00386
00387
00388 _CurrentDeltaPos = -_DeltaPos;
00389
00390
00391 float realEt = _KeepEllapsedTimeForLifeUpdate ? (ellapsedTime / nbPass)
00392 : et;
00393 do
00394 {
00395
00396 _CurrentDeltaPos += _DeltaPos * (et * _InverseEllapsedTime);
00397
00398
00399 stepLocated(PSCollision, et, realEt);
00400 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00401 {
00402 (*it)->updateLife(realEt);
00403 (*it)->step(PSMotion, et, realEt);
00404 }
00405 _SystemDate += realEt;
00406 stepLocated(PSEmit, et, realEt);
00407 }
00408 while (--nbPass);
00409
00410
00411 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00412 {
00413 if ((*it)->isParametricMotionEnabled()) (*it)->performParametricMotion(_SystemDate, ellapsedTime, realEt);
00414 }
00415
00416 }
00417 }
00418 }
00419
00420
00421
00423 void CParticleSystem::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00424 {
00425 sint version = f.serialVersion(12);
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 f.serial(_SysMat);
00436 f.serial(_Date);
00437 if (f.isReading())
00438 {
00439 delete _ColorAttenuationScheme;
00440
00441 _LBMap.clear();
00442
00443 for (TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00444 {
00445 delete (*it);
00446 }
00447
00448 _ProcessVect.clear();
00449
00450 f.serialContPolyPtr(_ProcessVect);
00451
00452 _InvSysMat = _SysMat.inverted();
00453 _FontGenerator = NULL;
00454 _FontManager = NULL;
00455 delete _UserParamGlobalValue;
00456 _UserParamGlobalValue = NULL;
00457 _BypassGlobalUserParam = 0;
00458 }
00459 else
00460 {
00461 f.serialContPolyPtr(_ProcessVect);
00462 }
00463
00464 if (version > 1)
00465 {
00466 f.serial(_Name);
00467 }
00468
00469 if (version > 2)
00470 {
00471 f.serial(_AccurateIntegration);
00472 if (_AccurateIntegration) f.serial(_CanSlowDown, _TimeThreshold, _MaxNbIntegrations);
00473 f.serial(_InvMaxViewDist, _LODRatio);
00474 _MaxViewDist = 1.f / _InvMaxViewDist;
00475 _InvCurrentViewDist = _InvMaxViewDist;
00476 }
00477
00478 if (version > 3)
00479 {
00480 f.serial(_ComputeBBox);
00481 if (!_ComputeBBox)
00482 {
00483 f.serial(_PreComputedBBox);
00484 }
00485 }
00486
00487 if (version > 4)
00488 {
00489 f.serial(_DestroyModelWhenOutOfRange);
00490 f.serialEnum(_DieCondition);
00491 if (_DieCondition != none)
00492 {
00493 f.serial(_DelayBeforeDieTest);
00494 }
00495 }
00496
00497 if (version > 5)
00498 {
00499 f.serial(_DestroyWhenOutOfFrustum);
00500 }
00501
00502 if (version > 6 && version < 8)
00503 {
00504 bool performMotionWOOF;
00505 if (f.isReading())
00506 {
00507 f.serial(performMotionWOOF);
00508 performMotionWhenOutOfFrustum(performMotionWOOF);
00509 }
00510 else
00511 {
00512 performMotionWOOF = doesPerformMotionWhenOutOfFrustum();
00513 f.serial(performMotionWOOF);
00514 }
00515 }
00516
00517 if (version > 7)
00518 {
00519 f.serialEnum(_AnimType);
00520 f.serialEnum(_PresetBehaviour);
00521 }
00522
00523 if (version > 8)
00524 {
00525 f.serial(_Sharing);
00526 f.serial(_AutoLOD);
00527 if (_AutoLOD)
00528 {
00529 f.serial(_AutoLODStartDistPercent, _AutoLODDegradationExponent);
00530 f.serial(_AutoLODSkipParticles);
00531 }
00532 f.serial(_KeepEllapsedTimeForLifeUpdate);
00533 f.serialPolyPtr(_ColorAttenuationScheme);
00534 }
00535
00536 if (version >= 11)
00537 {
00538 f.serial(_EnableLoadBalancing);
00539 }
00540
00541 if (version >= 12)
00542 {
00543
00544 nlctassert(MaxPSUserParam < 8);
00545 if (f.isReading())
00546 {
00547 uint8 mask;
00548 f.serial(mask);
00549 if (mask)
00550 {
00551 std::string globalValueName;
00552 uint8 testMask = 1;
00553 for(uint k = 0; k < MaxPSUserParam; ++k)
00554 {
00555 if (mask & testMask)
00556 {
00557 f.serial(globalValueName);
00558 bindGlobalValueToUserParam(globalValueName.c_str(), k);
00559 }
00560 testMask <<= 1;
00561 }
00562 }
00563 }
00564 else
00565 {
00566 uint8 mask = 0;
00567 if (_UserParamGlobalValue)
00568 {
00569 for(uint k = 0; k < MaxPSUserParam; ++k)
00570 {
00571 if (_UserParamGlobalValue[k]) mask |= (1 << k);
00572 }
00573 }
00574 f.serial(mask);
00575 if (_UserParamGlobalValue)
00576 {
00577 for(uint k = 0; k < MaxPSUserParam; ++k)
00578 {
00579 if (_UserParamGlobalValue[k])
00580 {
00581 std::string valueName = _UserParamGlobalValue[k]->first;
00582 f.serial(valueName);
00583 }
00584 }
00585 }
00586 }
00587 }
00588
00589 if (f.isReading())
00590 {
00591 notifyMaxNumFacesChanged();
00592 }
00593 }
00594
00595
00597 void CParticleSystem::attach(CParticleSystemProcess *ptr)
00598 {
00599 nlassert(std::find(_ProcessVect.begin(), _ProcessVect.end(), ptr) == _ProcessVect.end() );
00600
00601 _ProcessVect.push_back(ptr);
00602 ptr->setOwner(this);
00603 notifyMaxNumFacesChanged();
00604 }
00605
00607 void CParticleSystem::remove(CParticleSystemProcess *ptr)
00608 {
00609 TProcessVect::iterator it = std::find(_ProcessVect.begin(), _ProcessVect.end(), ptr);
00610 nlassert(it != _ProcessVect.end() );
00611 _ProcessVect.erase(it);
00612 delete ptr;
00613 }
00614
00616 void CParticleSystem::computeBBox(NLMISC::CAABBox &aabbox)
00617 {
00618 if (!_ComputeBBox || !_BBoxTouched)
00619 {
00620 aabbox = _PreComputedBBox;
00621 return;
00622 }
00623
00624 bool foundOne = false;
00625 NLMISC::CAABBox tmpBox;
00626 for (TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00627 {
00628 if ((*it)->computeBBox(tmpBox))
00629 {
00630 if (!(*it)->isInSystemBasis())
00631 {
00632
00633 tmpBox = NLMISC::CAABBox::transformAABBox(_InvSysMat, tmpBox);
00634 }
00635 if (foundOne)
00636 {
00637 aabbox = NLMISC::CAABBox::computeAABBoxUnion(aabbox, tmpBox);
00638 }
00639 else
00640 {
00641 aabbox = tmpBox;
00642 foundOne = true;
00643 }
00644 }
00645 }
00646
00647 if (!foundOne)
00648 {
00649 aabbox.setCenter(NLMISC::CVector::Null);
00650 aabbox.setHalfSize(NLMISC::CVector::Null);
00651 }
00652
00653 _BBoxTouched = false;
00654 _PreComputedBBox = aabbox;
00655 }
00656
00658 void CParticleSystem::setSysMat(const CMatrix &m)
00659 {
00660 if (_SystemDate != 0.f)
00661 {
00662 _OldSysMat = _SysMat;
00663 _DeltaPos = m.getPos() - _OldSysMat.getPos();
00664 }
00665 else
00666 {
00667 _DeltaPos = NLMISC::CVector::Null;
00668 _OldSysMat = m;
00669 }
00670 _SysMat = m;
00671 _InvSysMat = _SysMat.inverted();
00672 }
00673
00675 bool CParticleSystem::hasOpaqueObjects(void) const
00676 {
00678 for (TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00679 {
00680 if (dynamic_cast<CPSLocated *>(*it))
00681 {
00682 for (uint k = 0; k < ((CPSLocated *) *it)->getNbBoundObjects(); ++k)
00683 {
00684 CPSLocatedBindable *lb = ((CPSLocated *) *it)->getBoundObject(k);
00685 if (lb->getType() == PSParticle)
00686 {
00687 if (((CPSParticle *) lb)->hasOpaqueFaces()) return true;
00688 }
00689 }
00690 }
00691 }
00692 return false;
00693 }
00694
00696 bool CParticleSystem::hasTransparentObjects(void) const
00697 {
00699 for (TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00700 {
00701 if (dynamic_cast<CPSLocated *>(*it))
00702 {
00703 for (uint k = 0; k < ((CPSLocated *) *it)->getNbBoundObjects(); ++k)
00704 {
00705 CPSLocatedBindable *lb = ((CPSLocated *) *it)->getBoundObject(k);
00706 if (lb->getType() == PSParticle)
00707 {
00708 if (((CPSParticle *) lb)->hasTransparentFaces()) return true;
00709 }
00710 }
00711 }
00712 }
00713 return false;
00714 }
00715
00717 void CParticleSystem::getLODVect(NLMISC::CVector &v, float &offset, bool systemBasis)
00718 {
00719 if (!systemBasis)
00720 {
00721 v = _InvCurrentViewDist * _InvertedViewMat.getJ();
00722 offset = - _InvertedViewMat.getPos() * v;
00723 }
00724 else
00725 {
00726 const CVector tv = _InvSysMat.mulVector(_InvertedViewMat.getJ());
00727 const CVector org = _InvSysMat * _InvertedViewMat.getPos();
00728 v = _InvCurrentViewDist * tv;
00729 offset = - org * v;
00730 }
00731 }
00732
00734 TPSLod CParticleSystem::getLOD(void) const
00735 {
00736 const float dist = fabsf(_InvCurrentViewDist * (_SysMat.getPos() - _InvertedViewMat.getPos()) * _InvertedViewMat.getJ());
00737 return dist > _LODRatio ? PSLod2 : PSLod1;
00738 }
00739
00740
00742 void CParticleSystem::registerLocatedBindableExternID(uint32 id, CPSLocatedBindable *lb)
00743 {
00744 nlassert(lb);
00745 nlassert(lb->getOwner() && lb->getOwner()->getOwner() == this);
00746 #ifdef NL_DEBUG
00747
00748 TLBMap::iterator lbd = _LBMap.lower_bound(id), ubd = _LBMap.upper_bound(id);
00749 nlassert(std::find(lbd, ubd, TLBMap::value_type (id, lb)) == ubd);
00750 nlassert(std::find(lbd, ubd, TLBMap::value_type (id, lb)) == ubd );
00751
00752 #endif
00753 _LBMap.insert(TLBMap::value_type (id, lb) );
00754 }
00755
00757 void CParticleSystem::unregisterLocatedBindableExternID(CPSLocatedBindable *lb)
00758 {
00759 nlassert(lb);
00760 nlassert(lb->getOwner() && lb->getOwner()->getOwner() == this);
00761 uint32 id = lb->getExternID();
00762 if (!id) return;
00763 TLBMap::iterator lbd = _LBMap.lower_bound(id), ubd = _LBMap.upper_bound(id);
00764 TLBMap::iterator el = std::find(lbd, ubd, TLBMap::value_type (id, lb));
00765 nlassert(el != ubd);
00766 _LBMap.erase(el);
00767 }
00768
00770 uint CParticleSystem::getNumLocatedBindableByExternID(uint32 id) const
00771 {
00772 return _LBMap.count(id);
00773 }
00774
00776 CPSLocatedBindable *CParticleSystem::getLocatedBindableByExternID(uint32 id, uint index)
00777 {
00778 if (index >= _LBMap.count(id))
00779 {
00780 return NULL;
00781 }
00782 TLBMap::const_iterator el = _LBMap.lower_bound(id);
00783 uint left = index;
00784 while (left--) ++el;
00785 return el->second;
00786
00787 }
00788
00790 const CPSLocatedBindable *CParticleSystem::getLocatedBindableByExternID(uint32 id, uint index) const
00791 {
00792 if (index >= _LBMap.count(id))
00793 {
00794 return NULL;
00795 }
00796 TLBMap::const_iterator el = _LBMap.lower_bound(id);
00797 uint left = index;
00798 while (left--) ++el;
00799 return el->second;
00800 }
00801
00803 void CParticleSystem::merge(CParticleSystemShape *pss)
00804 {
00805 nlassert(pss);
00806 CParticleSystem *duplicate = pss->instanciatePS(*this->_Scene);
00807
00808 for (TProcessVect::iterator it = duplicate->_ProcessVect.begin(); it != duplicate->_ProcessVect.end(); ++it)
00809 {
00810 attach(*it);
00811 }
00812 duplicate->_ProcessVect.clear();
00813 delete duplicate;
00814 }
00815
00817 void CParticleSystem::activatePresetBehaviour(TPresetBehaviour behaviour)
00818 {
00819
00820 switch(behaviour)
00821 {
00822 case EnvironmentFX:
00823 setDestroyModelWhenOutOfRange(false);
00824 setDestroyCondition(none);
00825 destroyWhenOutOfFrustum(false);
00826 setAnimType(AnimVisible);
00827 break;
00828 case RunningEnvironmentFX:
00829 setDestroyModelWhenOutOfRange(false);
00830 setDestroyCondition(none);
00831 destroyWhenOutOfFrustum(false);
00832 setAnimType(AnimInCluster);
00833 break;
00834 case SpellFX:
00835 setDestroyModelWhenOutOfRange(true);
00836 setDestroyCondition(noMoreParticles);
00837 destroyWhenOutOfFrustum(false);
00838 setAnimType(AnimAlways);
00839 break;
00840 case LoopingSpellFX:
00841 setDestroyModelWhenOutOfRange(true);
00842 setDestroyCondition(noMoreParticles);
00843 destroyWhenOutOfFrustum(false);
00844 setAnimType(AnimInCluster);
00845 break;
00846 case MinorFX:
00847 setDestroyModelWhenOutOfRange(true);
00848 setDestroyCondition(noMoreParticles);
00849 destroyWhenOutOfFrustum(true);
00850 setAnimType(AnimVisible);
00851 break;
00852 default: break;
00853 }
00854 _PresetBehaviour = behaviour;
00855 }
00856
00857
00859 CParticleSystemProcess *CParticleSystem::detach(uint index)
00860 {
00861 nlassert(index < _ProcessVect.size());
00862 CParticleSystemProcess *proc = _ProcessVect[index];
00863
00864 for(TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00865 {
00866 (*it)->releaseRefTo(proc);
00867 }
00868
00869 _ProcessVect.erase(_ProcessVect.begin() + index);
00870 proc->setOwner(NULL);
00871
00872 return proc;
00873 }
00874
00876 bool CParticleSystem::isProcess(CParticleSystemProcess *process) const
00877 {
00878 for(TProcessVect::const_iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00879 {
00880 if (*it == process) return true;
00881 }
00882 return false;
00883 }
00884
00886 uint CParticleSystem::getIndexOf(const CParticleSystemProcess *process) const
00887 {
00888 for(uint k = 0; k < _ProcessVect.size(); ++k)
00889 {
00890 if (_ProcessVect[k] == process) return k;
00891 }
00892 nlassert(0);
00893 return 0;
00894 }
00895
00897 uint CParticleSystem::getNumID() const
00898 {
00899 return _LBMap.size();
00900 }
00901
00903 uint32 CParticleSystem::getID(uint index) const
00904 {
00905 TLBMap::const_iterator it = _LBMap.begin();
00906 for(uint k = 0; k < index; ++k)
00907 {
00908 if (it == _LBMap.end()) return 0;
00909 ++it;
00910 }
00911 return it->first;
00912 }
00913
00915 void CParticleSystem::getIDs(std::vector<uint32> &dest) const
00916 {
00917 dest.resize(_LBMap.size());
00918 uint k = 0;
00919 for(TLBMap::const_iterator it = _LBMap.begin(); it != _LBMap.end(); ++it)
00920 {
00921 dest[k] = it->first;
00922 ++k;
00923 }
00924 }
00925
00927 void CParticleSystem::interpolatePosDelta(NLMISC::CVector &dest,TAnimationTime deltaT)
00928 {
00929 dest = _CurrentDeltaPos - (deltaT * _InverseEllapsedTime) * _DeltaPos;
00930 }
00931
00933 void CParticleSystem::bindGlobalValueToUserParam(const std::string &globalValueName, uint userParamIndex)
00934 {
00935 nlassert(userParamIndex < MaxPSUserParam);
00936 if (globalValueName.empty())
00937 {
00938 if (!_UserParamGlobalValue) return;
00939 _UserParamGlobalValue[userParamIndex] = NULL;
00940 for(uint k = 0; k < MaxPSUserParam; ++k)
00941 {
00942 if (_UserParamGlobalValue[k] != NULL) return;
00943 }
00944
00945 delete _UserParamGlobalValue;
00946 _UserParamGlobalValue = NULL;
00947 }
00948 else
00949 {
00950 if (!_UserParamGlobalValue)
00951 {
00952
00953 _UserParamGlobalValue = new const TGlobalValuesMap::value_type *[MaxPSUserParam];
00954 std::fill(_UserParamGlobalValue, _UserParamGlobalValue + MaxPSUserParam, (TGlobalValuesMap::value_type *) NULL);
00955 }
00956
00957 TGlobalValuesMap::const_iterator it = _GlobalValuesMap.find(globalValueName);
00958 if (it != _GlobalValuesMap.end())
00959 {
00960
00961 _UserParamGlobalValue[userParamIndex] = &(*it);
00962 }
00963 else
00964 {
00965
00966 std::pair<TGlobalValuesMap::iterator, bool> itPair = _GlobalValuesMap.insert(TGlobalValuesMap::value_type(globalValueName, 0.f));
00967 _UserParamGlobalValue[userParamIndex] = &(*(itPair.first));
00968 }
00969 }
00970 }
00971
00973 void CParticleSystem::setGlobalValue(const std::string &name, float value)
00974 {
00975 nlassert(!name.empty());
00976 NLMISC::clamp(value, 0.f, 1.f);
00977 _GlobalValuesMap[name] = value;
00978 }
00979
00981 float CParticleSystem::getGlobalValue(const std::string &name)
00982 {
00983 TGlobalValuesMap::const_iterator it = _GlobalValuesMap.find(name);
00984 if (it != _GlobalValuesMap.end()) return it->second;
00985 return 0.f;
00986 }
00987
00989 std::string CParticleSystem::getGlobalValueName(uint userParamIndex) const
00990 {
00991 nlassert(userParamIndex < MaxPSUserParam);
00992 if (!_UserParamGlobalValue) return "";
00993 if (!_UserParamGlobalValue[userParamIndex]) return "";
00994 return _UserParamGlobalValue[userParamIndex]->first;
00995 }
00996
00998 void CParticleSystem::setGlobalVectorValue(const std::string &name, const NLMISC::CVector &value)
00999 {
01000 nlassert(!name.empty());
01001 _GlobalVectorValuesMap[name] = value;
01002 }
01003
01004
01006 NLMISC::CVector CParticleSystem::getGlobalVectorValue(const std::string &name)
01007 {
01008 nlassert(!name.empty());
01009 TGlobalVectorValuesMap::const_iterator it = _GlobalVectorValuesMap.find(name);
01010 if (it != _GlobalVectorValuesMap.end()) return it->second;
01011 return NLMISC::CVector::Null;
01012 }
01013
01015 CParticleSystem::CGlobalVectorValueHandle CParticleSystem::getGlobalVectorValueHandle(const std::string &name)
01016 {
01017 nlassert(!name.empty());
01018 TGlobalVectorValuesMap::iterator it = _GlobalVectorValuesMap.find(name);
01019 if (it == _GlobalVectorValuesMap.end())
01020 {
01021 it = _GlobalVectorValuesMap.insert(TGlobalVectorValuesMap::value_type(name, NLMISC::CVector::Null)).first;
01022 }
01023 CGlobalVectorValueHandle handle;
01024 handle._Value = &it->second;
01025 handle._Name = &it->first;
01026 return handle;
01027 }
01028
01029
01030
01031 }