# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

particle_system_model.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
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" // ask trap
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         // AnimDetail behavior: Must be traversed in AnimDetail, even if no channel mixer registered
00070         CTransform::setIsForceAnimDetail(true);
00071 }
00072 
00073 
00075 void CParticleSystemModel::setEditionMode(bool enable /*= true*/)
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)); // this observer has already been registered
00094         _Observers.push_back(obs);
00095 }
00096 
00098 void CParticleSystemModel::removePSModelObserver(IPSModelObserver *obs)
00099 {       
00100         nlassert(isPSModelObserver(obs)); // the observer must have been registered
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         // register the model and his observers
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         // Auto detach me from skeleton. Must do it here, not in ~CTransform().
00157         if(_FatherSkeletonModel)
00158         {
00159                 // detach me from the skeleton.
00160                 // Observers hierarchy is modified.
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         // touch user params animated value. If the system rsc have been released before, this force to restore them
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                 // Backup user params (in animated value) so that they will be restored when the system is recreated
00194                 for (uint k = 0; k < MaxPSUserParam; ++k)
00195                 {
00196                         
00197                         _UserParam[k].Value = _ParticleSystem->getUserParam(k);                                 
00198                 }
00199         }
00200         //
00201         _ParticleSystem = NULL; // one less ref with the smart ptr 
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         /* NLMISC::CVector sysPos = getTransformMode() == DirectMatrix ?
00220                                                          getMatrix().getPos()                       :
00221                                                          getPos(); */
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) // too far ?
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); // if this crash, then you forgot to call removePSModelObserver !
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); // delegate to parent
00353 
00354         // this value belong to us
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 /* =std::string() */)
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         // Transform the pyramid in Object space.       
00390         for(sint i=0; i < (sint) pyramid.size(); i++)
00391         {       
00392                 // test wether the bbox is entirely in the neg side of the plane
00393                 if (!bbox.clipBack(pyramid[i]  * mat  )) 
00394                 {
00395                         return false;                   
00396                 }
00397         }
00398         return true;
00399 
00400 }
00401 
00403 // CParticleSystemDetailObs implementation  //
00405 
00407 void    CParticleSystemDetailObs::traverse(IObs *caller)
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 // remove rsc but do not invalidate the system
00426                         {
00427                                 psm->releaseRsc();
00428                         }
00429                         return;
00430                 }
00431                 if (!ps) return;
00432         }       
00433 
00434         // check for trigger. If the trigger is false, and there is a system instanciated, we delete it.
00435         if (!psm->_EditionMode)
00436         {
00437                 if (!psm->_TriggerAnimatedValue.Value)
00438                 {                                                                       
00439                         // system is off, or hasn't been instanciated now...
00440                         if (ps)
00441                         {
00442                                 psm->releaseRsc();                              
00443                         }
00444                         return;
00445                 }
00446         }
00447 
00448         // the system or its center is in the view frustum, but it may not have been instanciated from its shape now
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                         //ps->setSysMat(psm->getWorldMatrix());
00486                         nlassert(ps->getScene());       
00487 
00488 
00489                         // setup the number of faces we allow
00490                         ps->setNumTris((uint) psm->getNumTrianglesAfterLoadBalancing());
00491 
00492 
00493                         // set the global user param that are bypassed
00494                         nlctassert(MaxPSUserParam < 8); // there should be less than 8 parameters because of mask stored in a byte
00495                         ps->_BypassGlobalUserParam = psm->_BypassGlobalUserParam;
00496 
00497                         // setup system user parameters for parameters that have been touched
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) // if the animation is always perfomed, then its done by the particle system manager
00508                         {
00509                                 if (psm->isAutoGetEllapsedTimeEnabled())
00510                                 {
00511                                         psm->setEllapsedTime(ps->getScene()->getEllapsedTime() * psm->getEllapsedTimeRatio());
00512                                 }
00513                                 TAnimationTime delay = psm->getEllapsedTime();
00514                                 // animate particles                            
00515                                 ps->step(CParticleSystem::Anim, delay);                                 
00516                         }
00517                 }
00518         }               
00519         
00520 
00521         // add a render obs if in cluster & not hidden
00522         if (psm->_InClusterAndVisible)
00523         {
00524                 trav->RenderTrav->addRenderObs(ClipObs->RenderObs);
00525         }
00526 }
00527 
00528 
00529 
00531 // CParticleSystemRenderObs implementation  //
00533 void    CParticleSystemRenderObs::traverse(IObs *caller)
00534 {
00535 
00536         
00537 
00538 /*
00539         if (!psm->_OutOfFrustum)
00540         {*/
00541                 CTransformShapeRenderObs::traverse(caller);
00542         //}
00543 }
00544 
00545 
00546 /*
00547  * CParticleSystemClipObs implementation              
00548  * IMPORTANT : the Visible attribute is interpreted as 'in traversed clusters'. We need this because we want
00549  * to know when a p.s is in clusters, but not visible. As a matter of fact we may need to have system that are animated
00550  * as long as in cluster, but not visible. 
00551  */
00552         
00553 void    CParticleSystemClipObs::traverse(IObs *caller)
00554 {
00555         H_AUTO ( NL3D_Particles_Clip );
00556 
00557 //          CTransformClipObs::traverse(caller);
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; // already visible
00572                 
00573 
00574                 CParticleSystem *ps = m->_ParticleSystem;
00575 
00576                 
00577                 if (ps) // system instanciated
00578                 {
00579                         // if there are no more particles, no need to even clip..
00580                         if (checkDestroyCondition(ps, m)) return;
00581                 }
00582                 
00583                 // special case : system sticked to a skeleton
00584                 if( ((CTransformHrcObs*)HrcObs)->_AncestorSkeletonModel!=NULL )
00585                 {
00586                         bool visible = ((CTransformHrcObs*)HrcObs)->_AncestorSkeletonModel->isClipVisible();
00587                         // Special test: if we are sticked to a skeletonModel, and if we are still visible, maybe we don't have to
00588                         if(Visible && m->_FatherSkeletonModel)
00589                         {
00590                                 CClipTrav               *clipTrav= NLMISC::safe_cast<CClipTrav*>(Trav);
00591 
00592                                 // if our skeletonModel father is displayed with a Lod, maybe we are not to be displayed
00593                                 if(m->_FatherSkeletonModel->isDisplayedAsLodCharacter())
00594                                 {
00595                                         // We are visible only if we where sticked to the skeleton with forceCLod==true.
00596                                         // This is also true if we are actually a skeletonModel
00597                                         if(!m->getShowWhenLODSticked())
00598                                                 // otherWise we are not visible. eg: this is the case of skins and some sticked object
00599                                                 visible = false;
00600                                 }
00601                         }
00602                         //
00603                         if (visible)
00604                         {                               
00605                                 Visible = true;
00606                                 insertInVisibleList();                          
00607                                 m->_InClusterAndVisible = true;
00608                                 return;
00609                         }
00610                         else // not visible, may need animation however..
00611                         {                               
00612                                 if (!ps) // no resc allocated
00613                                 {
00614                                         CParticleSystemShape            *pss= NLMISC::safe_cast<CParticleSystemShape *>((IShape *)m->Shape);
00615                                         nlassert(pss);
00616                                         // invalidate the system if too far
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                                         // NB : The test to see wether the system is not too far is performed by the particle system manager                                    
00631                                         if (!m->_EditionMode)
00632                                         {
00633                                                 Visible = true;     // system near, but maybe not in cluster..
00634                                                 insertInVisibleList();
00635                                         }                                       
00636                                 }
00637                         }
00638                         return;                         
00639                 }
00640 
00641 
00642                 //
00643                 const std::vector<CPlane>       &pyramid= trav->WorldPyramid;   
00648                 // now the pyramid is directly expressed in the world
00649                 const CMatrix           &mat= HrcObs->WorldMatrix;       
00650 
00651                                 
00652                 // Transform the pyramid in Object space.
00653 
00654                 
00655                 if(!ps) 
00656                 {
00657                         CParticleSystemShape            *pss= NLMISC::safe_cast<CParticleSystemShape *>((IShape *)m->Shape);
00658                         nlassert(pss);
00659 
00660                         // the system wasn't present the last time, we use its center to see if it's back in the view frustum,
00661                         // or if it is near enough.
00662                         // if this is the case, we say it isn't clipped, so it will be reinstanciated from the shape
00663                         // during the DetailAnimTraversal
00664 
00665                         const CVector pos = m->getMatrix().getPos();
00666                 
00667                         const CVector d = pos - trav->CamPos;
00668 
00669 
00670                         // check wether system not too far              
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                         // test the shape to see wether we have a precomputed bbox
00682                         if (!pss->_UsePrecomputedBBox)
00683                         {                                                               
00686                                 for(sint i=0; i < (sint)pyramid.size(); i++)
00687                                 {                                       
00688                                         if ( (pyramid[i]   *  mat  ).d > 0.0f )  // in its basis, the system is at the center
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                 // the system is already instanciated
00727                 
00728                 nlassert(ps);                                           
00730                 if (m->checkAgainstPyramid(pyramid) == false)
00731                 {
00732                         if (!m->_EditionMode)
00733                         {
00734                                 // system near, but maybe not in cluster..      
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                         // test deletion condition (no more particle, no more particle and emitters)
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 /*=true*/)
00790 {
00791         nlctassert(MaxPSUserParam < 8); // there should be less than 8 parameters because of mask stored in a byte
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); // there should be less than 8 parameters because of mask stored in a byte
00801         nlassert(userParamIndex < MaxPSUserParam);
00802         return (_BypassGlobalUserParam & (1 << userParamIndex)) != 0;
00803 }
00804 
00805 
00806 } // NL3D