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 "nel/misc/debug.h"
00029 #include "nel/misc/common.h"
00030 #include "nel/misc/hierarchical_timer.h"
00031 #include "3d/particle_system_model.h"
00032 #include "3d/particle_system_shape.h"
00033 #include "3d/particle_system.h"
00034 #include "3d/scene.h"
00035 #include "3d/anim_detail_trav.h"
00036 #include "3d/clip_trav.h"
00037 #include "3d/render_trav.h"
00038 #include "3d/skeleton_model.h"
00039
00040
00041
00042 #include "cluster.h"
00043
00044
00045
00046
00047 namespace NL3D {
00048
00051 CParticleSystemModel::CParticleSystemModel() : _AutoGetEllapsedTime(true),
00052 _ParticleSystem(NULL),
00053 _Scene(NULL),
00054 _EllapsedTime(0.01f),
00055 _EllapsedTimeRatio(1.f),
00056 _ToolDisplayEnabled(false),
00057 _TransparencyStateTouched(true),
00058 _EditionMode(false),
00059 _Invalidated(false),
00060 _InsertedInVisibleList(false),
00061 _InClusterAndVisible(false),
00062 _BypassGlobalUserParam(0)
00063 {
00064 setOpacity(false);
00065 setTransparency(true);
00066 IAnimatable::resize(AnimValueLast);
00067 _TriggerAnimatedValue.Value = true;
00068
00069
00070 CTransform::setIsForceAnimDetail(true);
00071 }
00072
00073
00075 void CParticleSystemModel::setEditionMode(bool enable )
00076 {
00077 if (enable)
00078 {
00080 if (!_ParticleSystem)
00081 {
00082 nlassert(_Scene);
00083 nlassert(Shape);
00084 reallocRsc();
00085 }
00086 }
00087 _EditionMode = enable;
00088 }
00089
00091 void CParticleSystemModel::registerPSModelObserver(IPSModelObserver *obs)
00092 {
00093 nlassert(!isPSModelObserver(obs));
00094 _Observers.push_back(obs);
00095 }
00096
00098 void CParticleSystemModel::removePSModelObserver(IPSModelObserver *obs)
00099 {
00100 nlassert(isPSModelObserver(obs));
00101 std::vector<IPSModelObserver *>::iterator it = std::find(_Observers.begin(), _Observers.end(), obs);
00102 _Observers.erase(it);
00103 }
00104
00105
00107 bool CParticleSystemModel::isPSModelObserver(IPSModelObserver *obs)
00108 {
00109 return std::find(_Observers.begin(), _Observers.end(), obs) != _Observers.end();
00110 }
00111
00112
00114 void CParticleSystemModel::registerBasic()
00115 {
00116
00117 CMOT::registerModel(ParticleSystemModelId, TransformShapeId, CParticleSystemModel::creator);
00118 CMOT::registerObs(AnimDetailTravId, ParticleSystemModelId, CParticleSystemDetailObs::creator);
00119 CMOT::registerObs(ClipTravId, ParticleSystemModelId, CParticleSystemClipObs::creator);
00120 CMOT::registerObs(RenderTravId, ParticleSystemModelId, CParticleSystemRenderObs::creator);
00121 }
00122
00124 void CParticleSystemModel::updateOpacityInfos(void)
00125 {
00126 nlassert(_ParticleSystem);
00127 if (!_TransparencyStateTouched) return;
00128 nlassert(_ParticleSystem);
00129 setOpacity(_ParticleSystem->hasOpaqueObjects() || _ToolDisplayEnabled);
00130 setTransparency(_ParticleSystem->hasTransparentObjects());
00131 _TransparencyStateTouched = false;
00132 }
00133
00134
00136 void CParticleSystemModel::getAABBox(NLMISC::CAABBox &bbox) const
00137 {
00138 if (_ParticleSystem)
00139 {
00140 _ParticleSystem->computeBBox(bbox);
00141 }
00142 else
00143 {
00144 NLMISC::safe_cast<CParticleSystemShape *>((IShape *) Shape)->getAABBox(bbox);
00145 }
00146 }
00147
00149 CParticleSystemModel::~CParticleSystemModel()
00150 {
00151 nlassert(_Scene);
00152 if (_ParticleSystem)
00153 {
00154 _Scene->getParticleSystemManager().removeSystemModel(_ModelHandle);
00155 }
00156
00157 if(_FatherSkeletonModel)
00158 {
00159
00160
00161 _FatherSkeletonModel->detachSkeletonSon(this);
00162 nlassert(_FatherSkeletonModel==NULL);
00163 }
00164 }
00165
00166
00169 void CParticleSystemModel::reallocRsc()
00170 {
00171 nlassert(_ParticleSystem == NULL);
00172 _ParticleSystem = NLMISC::safe_cast<CParticleSystemShape *>((IShape *) Shape)->instanciatePS(*_Scene);
00173 nlassert(_ParticleSystem);
00174 nlassert(_Scene);
00175 CParticleSystemManager &psmgt = _Scene->getParticleSystemManager();
00176 _ModelHandle = psmgt.addSystemModel(this);
00177 if (_ParticleSystem->getAnimType() == CParticleSystem::AnimAlways)
00178 {
00179 _AnimatedModelHandle = psmgt.addPermanentlyAnimatedSystem(this);
00180 }
00181
00182 for (uint k = 0; k < MaxPSUserParam; ++k)
00183 {
00184 touch((uint)CParticleSystemModel::PSParam0 + k, OwnerBit);
00185 }
00186 }
00187
00189 void CParticleSystemModel::releasePSPointer()
00190 {
00191 if (_ParticleSystem.getNbRef() == 1)
00192 {
00193
00194 for (uint k = 0; k < MaxPSUserParam; ++k)
00195 {
00196
00197 _UserParam[k].Value = _ParticleSystem->getUserParam(k);
00198 }
00199 }
00200
00201 _ParticleSystem = NULL;
00202 }
00203
00205 bool CParticleSystemModel::refreshRscDeletion(const std::vector<CPlane> &worldFrustumPyramid, const NLMISC::CVector &viewerPos)
00206 {
00207 if (_EditionMode) return false;
00216 nlassert(_ParticleSystem);
00217 CParticleSystemShape *shape = NLMISC::safe_cast<CParticleSystemShape *>((IShape *) Shape);
00218
00219
00220
00221
00222
00223 NLMISC::CVector sysPos = getWorldMatrix().getPos();
00224
00225 NLMISC::CVector v = sysPos - viewerPos;
00227 const float dist2 = v * v;
00228
00229 if (dist2 > shape->_MaxViewDist * shape->_MaxViewDist)
00230 {
00231 if (_AnimatedModelHandle.Valid)
00232 {
00233 _Scene->getParticleSystemManager().removePermanentlyAnimatedSystem(_AnimatedModelHandle);
00234 _AnimatedModelHandle.Valid = false;
00235 }
00236 releasePSPointer();
00237 if (shape->_DestroyModelWhenOutOfRange)
00238 {
00239 _Invalidated = true;
00240 }
00241 return true;
00242 }
00243
00245 if (shape->_DestroyWhenOutOfFrustum)
00246 {
00247 if (checkAgainstPyramid(worldFrustumPyramid) == false)
00248 {
00249 if (_AnimatedModelHandle.Valid)
00250 {
00251 _Scene->getParticleSystemManager().removePermanentlyAnimatedSystem(_AnimatedModelHandle);
00252 _AnimatedModelHandle.Valid = false;
00253 }
00254
00255 if (shape->_DestroyModelWhenOutOfRange)
00256 {
00257 _Invalidated = true;
00258 }
00259 releasePSPointer();
00260 return true;
00261 }
00262 }
00263
00264 return false;
00265 }
00266
00268 void CParticleSystemModel::releaseRsc()
00269 {
00270 if (!_ParticleSystem) return;
00271
00272 if (_AnimatedModelHandle.Valid)
00273 {
00274 _Scene->getParticleSystemManager().removePermanentlyAnimatedSystem(_AnimatedModelHandle);
00275 _AnimatedModelHandle.Valid = false;
00276 }
00277 nlassert(_Scene);
00278 _Scene->getParticleSystemManager().removeSystemModel(_ModelHandle);
00279 }
00280
00282 void CParticleSystemModel::releaseRscAndInvalidate()
00283 {
00284
00285 if (!_ParticleSystem) return;
00286
00287 if (_AnimatedModelHandle.Valid)
00288 {
00289 _Scene->getParticleSystemManager().removePermanentlyAnimatedSystem(_AnimatedModelHandle);
00290 _AnimatedModelHandle.Valid = false;
00291 }
00292 releasePSPointer();
00293 _Invalidated = true;
00294
00295 nlassert(_Scene);
00296 _Scene->getParticleSystemManager().removeSystemModel(_ModelHandle);
00297
00298 static std::vector<IPSModelObserver *> copyVect;
00299 copyVect.resize(_Observers.size());
00300 std::copy(_Observers.begin(), _Observers.end(), copyVect.begin());
00301
00302 for (std::vector<IPSModelObserver *>::iterator it = copyVect.begin(); it != copyVect.end(); ++it)
00303 {
00304 (*it)->invalidPS(this);
00305 }
00306 }
00307
00309 IAnimatedValue* CParticleSystemModel::getValue (uint valueId)
00310 {
00311 nlassert(valueId < AnimValueLast);
00312 if (valueId < OwnerBit) return CTransformShape::getValue(valueId);
00313 if (valueId < PSTrigger)
00314 {
00315
00316 return &_UserParam[valueId - (uint) PSParam0];
00317 }
00318 return &_TriggerAnimatedValue;
00319 }
00320
00322 const char *CParticleSystemModel::getPSParamName (uint valueId)
00323 {
00324 nlassert(valueId < AnimValueLast);
00325 const char *name[] = { "PSParam0", "PSParam1", "PSParam2", "PSParam3" };
00326 return name[valueId - (uint) PSParam0];
00327 }
00328
00330 const char *CParticleSystemModel::getValueName (uint valueId) const
00331 {
00332 nlassert(valueId < AnimValueLast);
00333 if (valueId < OwnerBit) return CTransformShape::getValueName(valueId);
00334 if (valueId < PSTrigger) return getPSParamName(valueId);
00335 return "PSTrigger";
00336 }
00337
00339 ITrack* CParticleSystemModel::getDefaultTrack (uint valueId)
00340 {
00341 nlassert(valueId < AnimValueLast);
00342 nlassert(Shape);
00343
00344 CParticleSystemShape *pss = NLMISC::safe_cast<CParticleSystemShape *>((IShape *) Shape);
00345
00346 switch (valueId)
00347 {
00348 case PosValue: return pss->getDefaultPos();
00349 case RotQuatValue: return pss->getDefaultRotQuat();
00350 case ScaleValue: return pss->getDefaultScale();
00351 }
00352 if (valueId < OwnerBit) return CTransformShape::getDefaultTrack(valueId);
00353
00354
00355 if (valueId < PSTrigger)
00356 {
00357 return pss->getUserParamDefaultTrack(valueId - (uint) PSParam0);
00358 }
00359 return pss->getDefaultTriggerTrack();
00360 }
00361
00363 void CParticleSystemModel::registerToChannelMixer(CChannelMixer *chanMixer, const std::string &prefix )
00364 {
00365 CTransformShape::registerToChannelMixer(chanMixer, prefix);
00366 addValue(chanMixer, PSParam0, OwnerBit, prefix, true);
00367 addValue(chanMixer, PSParam1, OwnerBit, prefix, true);
00368 addValue(chanMixer, PSParam2, OwnerBit, prefix, true);
00369 addValue(chanMixer, PSParam3, OwnerBit, prefix, true);
00370 addValue(chanMixer, PSTrigger, OwnerBit, prefix, true);
00371 }
00372
00373
00375 float CParticleSystemModel::getNumTriangles (float distance)
00376 {
00377 if (!_ParticleSystem) return 0;
00378 return (float) _ParticleSystem->getWantedNumTris(distance);
00379 }
00380
00382 bool CParticleSystemModel::checkAgainstPyramid(const std::vector<CPlane> &pyramid) const
00383 {
00384 nlassert(_ParticleSystem)
00385 NLMISC::CAABBox bbox;
00386 _ParticleSystem->computeBBox(bbox);
00387 const CMatrix &mat = getMatrix();
00388
00389
00390 for(sint i=0; i < (sint) pyramid.size(); i++)
00391 {
00392
00393 if (!bbox.clipBack(pyramid[i] * mat ))
00394 {
00395 return false;
00396 }
00397 }
00398 return true;
00399
00400 }
00401
00403
00405
00407
00408 {
00409 CTransformAnimDetailObs::traverse(caller);
00410 CParticleSystemModel *psm= NLMISC::safe_cast<CParticleSystemModel *>(Model);
00411 CParticleSystem *ps = psm->getPS();
00412 if (psm->_Invalidated) return;
00413 if (psm->getVisibility() == CHrcTrav::Hide) return;
00414
00415
00416 if (!psm->_EditionMode && !psm->_InClusterAndVisible)
00417 {
00418 CParticleSystemShape *pss = NLMISC::safe_cast<CParticleSystemShape *>((IShape *)psm->Shape);
00419 if (pss->_DestroyWhenOutOfFrustum)
00420 {
00421 if (pss->_DestroyModelWhenOutOfRange)
00422 {
00423 psm->releaseRscAndInvalidate();
00424 }
00425 else
00426 {
00427 psm->releaseRsc();
00428 }
00429 return;
00430 }
00431 if (!ps) return;
00432 }
00433
00434
00435 if (!psm->_EditionMode)
00436 {
00437 if (!psm->_TriggerAnimatedValue.Value)
00438 {
00439
00440 if (ps)
00441 {
00442 psm->releaseRsc();
00443 }
00444 return;
00445 }
00446 }
00447
00448
00449 if (!ps)
00450 {
00451 nlassert(psm->_Scene);
00452 nlassert(psm->Shape);
00453 psm->reallocRsc();
00454 ps = psm->_ParticleSystem;
00455 }
00456
00457 CClipTrav *trav= (CClipTrav*) ClipObs->Trav;
00458
00459 if (psm->_InClusterAndVisible || ps->getAnimType() == CParticleSystem::AnimInCluster)
00460 {
00461 bool animate = true;
00462 if (ps->isSharingEnabled())
00463 {
00464 if (ps->_LastUpdateDate == trav->CurrentDate)
00465 {
00466 animate = false;
00467 }
00468 else
00469 {
00470 ps->_LastUpdateDate = trav->CurrentDate;
00471 }
00472 }
00473 else
00474 {
00475 ps->_LastUpdateDate = trav->CurrentDate;
00476 }
00477 ps->_LastUpdateDate = trav->CurrentDate;
00478 if (animate)
00479 {
00480 const CMatrix &mat= HrcObs->WorldMatrix;
00481 ps->setSysMat(mat);
00482 ps->setViewMat(trav->ViewMatrix);
00483 psm->updateOpacityInfos();
00484
00485
00486 nlassert(ps->getScene());
00487
00488
00489
00490 ps->setNumTris((uint) psm->getNumTrianglesAfterLoadBalancing());
00491
00492
00493
00494 nlctassert(MaxPSUserParam < 8);
00495 ps->_BypassGlobalUserParam = psm->_BypassGlobalUserParam;
00496
00497
00498 for (uint k = 0; k < MaxPSUserParam; ++k)
00499 {
00500 if (psm->isTouched((uint)CParticleSystemModel::PSParam0 + k))
00501 {
00502 ps->setUserParam(k, psm->_UserParam[k].Value);
00503 psm->clearFlag((uint)CParticleSystemModel::PSParam0 + k);
00504 }
00505 }
00506
00507 if (ps->getAnimType() != CParticleSystem::AnimAlways)
00508 {
00509 if (psm->isAutoGetEllapsedTimeEnabled())
00510 {
00511 psm->setEllapsedTime(ps->getScene()->getEllapsedTime() * psm->getEllapsedTimeRatio());
00512 }
00513 TAnimationTime delay = psm->getEllapsedTime();
00514
00515 ps->step(CParticleSystem::Anim, delay);
00516 }
00517 }
00518 }
00519
00520
00521
00522 if (psm->_InClusterAndVisible)
00523 {
00524 trav->RenderTrav->addRenderObs(ClipObs->RenderObs);
00525 }
00526 }
00527
00528
00529
00531
00533
00534 {
00535
00536
00537
00538
00539
00540
00541 CTransformShapeRenderObs::traverse(caller);
00542
00543 }
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553 void CParticleSystemClipObs::traverse(IObs *caller)
00554 {
00555 H_AUTO ( NL3D_Particles_Clip );
00556
00557
00558 traverseSons();
00559 nlassert(!caller || dynamic_cast<IBaseClipObs*>(caller));
00560 CParticleSystemModel *m= (CParticleSystemModel*)Model;
00561 if (m->_Invalidated) return;
00562 CClipTrav *trav= (CClipTrav*)Trav;
00563
00564
00565 if (Date != trav->CurrentDate)
00566 {
00567 m->_InsertedInVisibleList = false;
00568 m->_InClusterAndVisible = false;
00569 Date = trav->CurrentDate;
00570 }
00571 if (m->_InClusterAndVisible) return;
00572
00573
00574 CParticleSystem *ps = m->_ParticleSystem;
00575
00576
00577 if (ps)
00578 {
00579
00580 if (checkDestroyCondition(ps, m)) return;
00581 }
00582
00583
00584 if( ((CTransformHrcObs*)HrcObs)->_AncestorSkeletonModel!=NULL )
00585 {
00586 bool visible = ((CTransformHrcObs*)HrcObs)->_AncestorSkeletonModel->isClipVisible();
00587
00588 if(Visible && m->_FatherSkeletonModel)
00589 {
00590 CClipTrav *clipTrav= NLMISC::safe_cast<CClipTrav*>(Trav);
00591
00592
00593 if(m->_FatherSkeletonModel->isDisplayedAsLodCharacter())
00594 {
00595
00596
00597 if(!m->getShowWhenLODSticked())
00598
00599 visible = false;
00600 }
00601 }
00602
00603 if (visible)
00604 {
00605 Visible = true;
00606 insertInVisibleList();
00607 m->_InClusterAndVisible = true;
00608 return;
00609 }
00610 else
00611 {
00612 if (!ps)
00613 {
00614 CParticleSystemShape *pss= NLMISC::safe_cast<CParticleSystemShape *>((IShape *)m->Shape);
00615 nlassert(pss);
00616
00617 const CVector pos = m->getMatrix().getPos();
00618 const CVector d = pos - trav->CamPos;
00619 if (d * d > pss->_MaxViewDist * pss->_MaxViewDist)
00620 {
00621 Visible = false;
00622 if (pss->_DestroyModelWhenOutOfRange)
00623 {
00624 m->_Invalidated = true;
00625 }
00626 }
00627 }
00628 else
00629 {
00630
00631 if (!m->_EditionMode)
00632 {
00633 Visible = true;
00634 insertInVisibleList();
00635 }
00636 }
00637 }
00638 return;
00639 }
00640
00641
00642
00643 const std::vector<CPlane> &pyramid= trav->WorldPyramid;
00648
00649 const CMatrix &mat= HrcObs->WorldMatrix;
00650
00651
00652
00653
00654
00655 if(!ps)
00656 {
00657 CParticleSystemShape *pss= NLMISC::safe_cast<CParticleSystemShape *>((IShape *)m->Shape);
00658 nlassert(pss);
00659
00660
00661
00662
00663
00664
00665 const CVector pos = m->getMatrix().getPos();
00666
00667 const CVector d = pos - trav->CamPos;
00668
00669
00670
00671 if (d * d > pss->_MaxViewDist * pss->_MaxViewDist)
00672 {
00673 Visible = false;
00674 if (pss->_DestroyModelWhenOutOfRange)
00675 {
00676 m->_Invalidated = true;
00677 }
00678 return;
00679 }
00680
00681
00682 if (!pss->_UsePrecomputedBBox)
00683 {
00686 for(sint i=0; i < (sint)pyramid.size(); i++)
00687 {
00688 if ( (pyramid[i] * mat ).d > 0.0f )
00689
00690 {
00691 Visible = true;
00692 insertInVisibleList();
00693 return;
00694 }
00695 }
00696
00697 Visible = true;
00698 insertInVisibleList();
00699 m->_InClusterAndVisible = true;
00700 return;
00701 }
00702 else
00703 {
00706 for(sint i=0; i < (sint)pyramid.size(); i++)
00707 {
00708 if ( !pss->_PrecomputedBBox.clipBack(pyramid[i] * mat ) )
00709 {
00710
00711 Visible = true;
00712 insertInVisibleList();
00713 return;
00714 }
00715 }
00716
00717 Visible = true;
00718 insertInVisibleList();
00719 m->_InClusterAndVisible = true;
00720 return;
00721
00722 }
00723 }
00724
00725
00726
00727
00728 nlassert(ps);
00730 if (m->checkAgainstPyramid(pyramid) == false)
00731 {
00732 if (!m->_EditionMode)
00733 {
00734
00735 Visible = true;
00736 insertInVisibleList();
00737 }
00738 return;
00739 }
00740
00741
00742 Visible = true;
00743 insertInVisibleList();
00744 m->_InClusterAndVisible = true;
00745 }
00746
00747
00748 bool CParticleSystemClipObs::checkDestroyCondition(CParticleSystem *ps, CParticleSystemModel *m)
00749 {
00750 nlassert(ps && m);
00751 if (!m->_EditionMode)
00752 {
00756 if (ps->getAnimType() != CParticleSystem::AnimAlways)
00757 {
00758
00759 if (ps->getDestroyCondition() != CParticleSystem::none)
00760 {
00761 if (ps->getSystemDate() > ps->getDelayBeforeDeathConditionTest())
00762 {
00763 switch (ps->getDestroyCondition())
00764 {
00765 case CParticleSystem::noMoreParticles:
00766 if (!ps->hasParticles())
00767 {
00768 m->releaseRscAndInvalidate();
00769 return true;
00770 }
00771 break;
00772 case CParticleSystem::noMoreParticlesAndEmitters:
00773 if (!ps->hasParticles() && !ps->hasEmitters())
00774 {
00775 m->releaseRscAndInvalidate();
00776 return true;
00777 }
00778 break;
00779 default: break;
00780 }
00781 }
00782 }
00783 }
00784 }
00785 return false;
00786 }
00787
00788
00789 void CParticleSystemModel::bypassGlobalUserParamValue(uint userParamIndex,bool byPass )
00790 {
00791 nlctassert(MaxPSUserParam < 8);
00792 nlassert(userParamIndex < MaxPSUserParam);
00793 if (byPass) _BypassGlobalUserParam |= (1 << userParamIndex);
00794 else _BypassGlobalUserParam &= ~(1 << userParamIndex);
00795 }
00796
00797
00798 bool CParticleSystemModel::isGlobalUserParamValueBypassed(uint userParamIndex) const
00799 {
00800 nlctassert(MaxPSUserParam < 8);
00801 nlassert(userParamIndex < MaxPSUserParam);
00802 return (_BypassGlobalUserParam & (1 << userParamIndex)) != 0;
00803 }
00804
00805
00806 }