# 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.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 "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 // CPaticleSystem implementation //
00058 
00059 
00061 const float PSDefaultMaxViewDist = 300.f;
00062 
00063 /*
00064  * Constructor
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 /*=true*/)
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; // no contribution to the load balancing
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                 /*uint numFaceWanted = (uint) getWantedNumTris(modelDist);*/
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                 // always take full detail when there's no load balancing
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         // temp
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 static void displaySysPos(IDriver *drv, const CVector &pos, CRGBA col)
00290 {
00291         if (!drv) return;       
00292         drv->setupModelMatrix(CMatrix::Identity);
00293         CPSUtil::displayArrow(drv, pos, CVector::K, 1.f, CRGBA::White, col);
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                         // update time
00309                         ++_Date;        
00310                         // update global color
00311                         updateColor();
00312                         stepLocated(PSSolidRender, ellapsedTime, ellapsedTime);
00313 
00314                 break;
00315                 case BlendRender:                       
00317                         if (_Sharing)
00318                         {
00319                                 updateLODRatio();
00320                         }
00321                         // update time
00322                         ++_Date; 
00323                         // update global color
00324                         updateColor();                  
00325                         stepLocated(PSBlendRender, ellapsedTime, ellapsedTime);
00326                 break;
00327                 case ToolRender:
00328                         stepLocated(PSToolRender, ellapsedTime, ellapsedTime);
00329                 break;
00330                 case Anim:
00331                 {
00332                         // update user param from global value if needed, unless this behaviour is bypassed has indicated by a flag in _BypassGlobalUserParam
00333                         if (_UserParamGlobalValue)
00334                         {
00335                                 nlctassert(MaxPSUserParam < 8); // there should be less than 8 parameters because of mask stored in a byte                      
00336                                 uint8 bypassMask = 1;
00337                                 for(uint k = 0; k < MaxPSUserParam; ++k)
00338                                 {
00339                                         if (_UserParamGlobalValue[k] && !(_BypassGlobalUserParam & bypassMask)) // if there is a global value for this param and if the update is not bypassed
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                         // set start position. Used by emitters that emit from Local basis to world
00388                         _CurrentDeltaPos = -_DeltaPos;
00389                         //displaySysPos(_Driver, _CurrentDeltaPos + _OldSysMat.getPos(), CRGBA::Red);
00390                         // process passes
00391                         float realEt = _KeepEllapsedTimeForLifeUpdate ? (ellapsedTime / nbPass)
00392                                                                                                                   : et;                 
00393                         do
00394                         {                                       
00395                                 // position of the system at the end of the integration
00396                                 _CurrentDeltaPos += _DeltaPos * (et * _InverseEllapsedTime);
00397                                 //displaySysPos(_Driver, _CurrentDeltaPos + _OldSysMat.getPos(), CRGBA::Blue);
00398                                 // the order of the following is important...
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                         // perform parametric motion if present
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         // version 12: global userParams
00427         // version 11: enable load balancing flag 
00428         // version 9: Sharing flag added
00429         //            Auto-lod parameters
00430         //            New integration flag
00431         //                        Global color attenuation
00432         // version 8: Replaced the attribute '_PerformMotionWhenOutOfFrustum' by a _AnimType field which allow more precise control
00433 
00434         //f.serial(_ViewMat);
00435         f.serial(_SysMat);
00436         f.serial(_Date);
00437         if (f.isReading())
00438         {
00439                 delete _ColorAttenuationScheme;
00440                 // delete previous multimap
00441                 _LBMap.clear();
00442                 // delete previously attached process
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) // name of the system
00465         {
00466                 f.serial(_Name);
00467         }
00468 
00469         if (version > 2) // infos about integration, and LOD
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) // tell wether the system must compute his bbox, hold a precomputed bbox
00479         {
00480                 f.serial(_ComputeBBox);
00481                 if (!_ComputeBBox)
00482                 {
00483                         f.serial(_PreComputedBBox);
00484                 }
00485         }
00486 
00487         if (version > 4) // lifetime informations
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                 // serial infos about global user params
00544                 nlctassert(MaxPSUserParam < 8); // In this version mask of used global user params are stored in a byte..               
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         //nlassert(ptr->getOwner() == NULL); // deja attache a un autre systeme
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                                 // rotate the aabbox so that it is in the correct basis
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; // _sysMat is relevant if at least one call to setSysMat has been performed before
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); // the located bindable must belong to that system
00746         #ifdef NL_DEBUG         
00747                 // check that this lb hasn't been inserted yet
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); // the located bindable must belong to that system
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); // duplicate the p.s. to merge
00807         // now we transfer the located of the duplicated ps to this object...
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         // release references other process may have to this system
00864         for(TProcessVect::iterator it = _ProcessVect.begin(); it != _ProcessVect.end(); ++it)
00865         {
00866                 (*it)->releaseRefTo(proc);
00867         }
00868         // erase from the vector
00869         _ProcessVect.erase(_ProcessVect.begin() + index);
00870         proc->setOwner(NULL);
00871         // not part of this system any more     
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); // not a process of this system
00893         return 0; // for warning
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()) // disable a user param global value
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                 // no more entry used
00945                 delete _UserParamGlobalValue;
00946                 _UserParamGlobalValue = NULL;
00947         }
00948         else // enable a user param global value
00949         {
00950                 if (!_UserParamGlobalValue) 
00951                 {
00952                         // no table has been allocated yet, so create one
00953                         _UserParamGlobalValue = new const TGlobalValuesMap::value_type *[MaxPSUserParam];
00954                         std::fill(_UserParamGlobalValue, _UserParamGlobalValue + MaxPSUserParam, (TGlobalValuesMap::value_type *) NULL);
00955                 }
00956                 // has the global value be created yet ?
00957                 TGlobalValuesMap::const_iterator it = _GlobalValuesMap.find(globalValueName);
00958                 if (it != _GlobalValuesMap.end())
00959                 {
00960                         // yes, make a reference on it
00961                         _UserParamGlobalValue[userParamIndex] = &(*it);
00962                 }
00963                 else
00964                 {
00965                         // create a new entry
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; // not a known value
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; // not a known value      
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 } // NL3D