ps_located.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #include "std3d.h"
00025 
00026 
00027 
00028 #include <algorithm>
00029 #include "nel/misc/aabbox.h"
00030 #include "nel/misc/matrix.h"
00031 #include "nel/misc/common.h"
00032 #include "nel/3d/ps_util.h"
00033 #include "nel/3d/particle_system.h"
00034 #include "nel/3d/ps_zone.h"
00035 #include "nel/3d/driver.h"
00036 #include "nel/3d/material.h"
00037 #include "nel/3d/dru.h"
00038 #include "nel/3d/ps_located.h"
00039 #include "nel/3d/ps_particle.h"
00040 #include "nel/3d/ps_force.h"
00041 #include "nel/3d/ps_emitter.h"
00042 #include "nel/3d/ps_misc.h"
00043 
00044 #include "nel/misc/line.h"
00045 #include "nel/misc/system_info.h"
00046 #include "nel/misc/common.h"
00047 
00048 //
00049 #include "nel/3d/particle_system_model.h"
00050 
00051 
00052 #ifdef NL_DEBUG
00053     #define CHECK_PS_INTEGRITY checkIntegrity();
00054 #else
00055     #define CHECK_PS_INTEGRITY
00056 #endif
00057 
00058 namespace NL3D {
00059 
00060 
00061 std::vector<CPSCollisionInfo> CPSLocated::_Collisions;
00062 CPSCollisionInfo *CPSLocated::_FirstCollision = NULL;
00063 
00064 
00065 
00067 
00070 CPSLocated::CPSLocated() : /*_MaxNumFaces(0),*/
00071                            _Size(0),
00072                            _MaxSize(DefaultMaxLocatedInstance),
00073                            _CollisionInfoNbRef(0),
00074                            _CollisionNextPos(NULL),
00075                            _InitialLife(1.f),
00076                            _LifeScheme(NULL),
00077                            _InitialMass(1.f),
00078                            _MassScheme(NULL),
00079                            _LODDegradation(false),
00080                            _ParametricMotion(false),
00081                            _TriggerOnDeath(false),
00082                            _LastForever(true),
00083                            _TriggerID((uint32) 'NONE'),
00084                            _NonIntegrableForceNbRefs(0),
00085                            _NumIntegrableForceWithDifferentBasis(0)
00086 {
00087     NL_PS_FUNC(CPSLocated_CPSLocated)
00088 }
00089 
00090 
00091 //*****************************************************************************************************
00092 const NLMISC::CMatrix &CPSLocated::getLocalToWorldMatrix() const
00093 {
00094     NL_PS_FUNC(CPSLocated_getLocalToWorldMatrix)
00095     nlassert(_Owner);
00096     switch(getMatrixMode())
00097     {
00098         case PSFXWorldMatrix:               return _Owner->getSysMat();
00099         case PSIdentityMatrix:              return NLMISC::CMatrix::Identity;
00100         case PSUserMatrix:  return _Owner->getUserMatrix();
00101         default:
00102             nlassert(0);
00103     }
00104     nlassert(0);
00105     return NLMISC::CMatrix::Identity;
00106 }
00107 
00108 //*****************************************************************************************************
00109 const NLMISC::CMatrix &CPSLocated::getWorldToLocalMatrix() const
00110 {
00111     NL_PS_FUNC(CPSLocated_getWorldToLocalMatrix)
00112     nlassert(_Owner);
00113     switch(getMatrixMode())
00114     {
00115         case PSFXWorldMatrix:               return _Owner->getInvertedSysMat();
00116         case PSIdentityMatrix:              return NLMISC::CMatrix::Identity;
00117         case PSUserMatrix:  return _Owner->getInvertedUserMatrix();
00118         default:
00119             nlassert(0);
00120     }
00121     nlassert(0);
00122     return NLMISC::CMatrix::Identity;
00123 }
00124 
00125 
00127 float CPSLocated::evalMaxDuration() const
00128 {
00129     NL_PS_FUNC(CPSLocated_evalMaxDuration)
00130     if (_LastForever) return -1.f;
00131     return _LifeScheme ? _LifeScheme->getMaxValue() : _InitialLife;
00132 }
00133 
00134 
00136 void CPSLocated::checkIntegrity() const
00137 {
00138     NL_PS_FUNC(CPSLocated_checkIntegrity)
00139     nlassert(_InvMass.getMaxSize() == _Pos.getMaxSize());
00140     nlassert(_Pos.getMaxSize() == _Speed.getMaxSize());
00141     nlassert(_Speed.getMaxSize() == _Time.getMaxSize());
00142     nlassert(_Time.getMaxSize() == _TimeIncrement.getMaxSize());
00143     //
00144     nlassert(_InvMass.getSize() == _Pos.getSize());
00145     nlassert(_Pos.getSize() == _Speed.getSize());
00146     nlassert(_Speed.getSize() == _Time.getSize());
00147     nlassert(_Time.getSize() == _TimeIncrement.getSize());
00148     //
00149     if (hasCollisionInfos())
00150     {
00151         nlassert(_CollisionNextPos->getSize() == _Pos.getSize());
00152         nlassert(_CollisionNextPos->getMaxSize() == _Pos.getMaxSize());
00153     }
00154     //
00155 }
00156 
00158 bool CPSLocated::setLastForever()
00159 {
00160     NL_PS_FUNC(CPSLocated_setLastForever)
00161     CHECK_PS_INTEGRITY
00162     _LastForever = true;
00163     if (_Owner && _Owner->getBypassMaxNumIntegrationSteps())
00164     {
00165         // Should test that the system is still valid.
00166         if (!_Owner->canFinish())
00167         {
00168             _LastForever = false;
00169             nlwarning("<CPSLocated::setLastForever> Can't set flag : this causes the system to last forever, and it has been flagged with 'BypassMaxNumIntegrationSteps'. Flag is not set");
00170             return false;
00171         }
00172     }
00173     CHECK_PS_INTEGRITY
00174     return true;
00175 }
00176 
00177 
00179 void CPSLocated::systemDateChanged()
00180 {
00181     NL_PS_FUNC(CPSLocated_systemDateChanged)
00182     CHECK_PS_INTEGRITY
00183     for(TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00184     {
00185         (*it)->systemDateChanged();
00186     }
00187     CHECK_PS_INTEGRITY
00188 }
00189 
00190 
00192 void CPSLocated::releaseRefTo(const CParticleSystemProcess *other)
00193 {
00194     NL_PS_FUNC(CPSLocated_releaseRefTo)
00195     CHECK_PS_INTEGRITY
00196     // located bindables
00197     {
00198         for(TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00199         {
00200             (*it)->releaseRefTo(other);
00201         }
00202     }
00203     // dtor observers
00204     {
00205 
00206         for(TDtorObserversVect::iterator it = _DtorObserversVect.begin(); it != _DtorObserversVect.end(); ++it)
00207         {
00208             if ((*it)->getOwner() == other)
00209             {
00210                 CPSLocatedBindable *refMaker = *it;
00211                 refMaker->notifyTargetRemoved(this);
00212                 break;
00213             }
00214         }
00215     }
00216     CHECK_PS_INTEGRITY
00217 }
00218 
00220 void CPSLocated::releaseAllRef()
00221 {
00222     NL_PS_FUNC(CPSLocated_releaseAllRef)
00223     CHECK_PS_INTEGRITY
00224      // located bindables
00225     {
00226         for(TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00227         {
00228             (*it)->releaseAllRef();
00229         }
00230     }
00231 
00232     // we must do a copy, because the subsequent call can modify this vector
00233     TDtorObserversVect copyVect(_DtorObserversVect.begin(), _DtorObserversVect.end());
00234     // call all the dtor observers
00235     for (TDtorObserversVect::iterator it = copyVect.begin(); it != copyVect.end(); ++it)
00236     {
00237         (*it)->notifyTargetRemoved(this);
00238     }
00239     _DtorObserversVect.clear();
00240 
00241     nlassert(_CollisionInfoNbRef == 0); //If this is not = 0, then someone didnt call releaseCollisionInfo
00242                                          // If this happen, you can register with the registerDTorObserver
00243                                          // (observer pattern)
00244                                          // and override notifyTargetRemove to call releaseCollisionInfo
00245     nlassert(_IntegrableForces.size() == 0);
00246     nlassert(_NonIntegrableForceNbRefs == 0);
00247     CHECK_PS_INTEGRITY
00248 }
00249 
00250 
00252 void CPSLocated::notifyMotionTypeChanged(void)
00253 {
00254     NL_PS_FUNC(CPSLocated_notifyMotionTypeChanged)
00255     CHECK_PS_INTEGRITY
00256     for (TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00257     {
00258         (*it)->motionTypeChanged(_ParametricMotion);
00259     }
00260     CHECK_PS_INTEGRITY
00261 }
00262 
00263 
00265 void CPSLocated::integrateSingle(float startDate, float deltaT, uint numStep,
00266                                 uint32 indexInLocated,
00267                                 NLMISC::CVector *destPos,
00268                                 uint stride) const
00269 {
00270     NL_PS_FUNC(CPSLocated_integrateSingle)
00271     CHECK_PS_INTEGRITY
00272     nlassert(supportParametricMotion() && _ParametricMotion);
00273     if (_IntegrableForces.size() != 0)
00274     {
00275         bool accumulate = false;
00276         for (TForceVect::const_iterator it = _IntegrableForces.begin(); it != _IntegrableForces.end(); ++it)
00277         {
00278             nlassert((*it)->isIntegrable());
00279             (*it)->integrateSingle(startDate, deltaT, numStep, this, indexInLocated, destPos, accumulate, stride);
00280             accumulate = true;
00281         }
00282     }
00283     else // no forces applied, just deduce position from date, initial pos and speed
00284     {
00285             #ifdef NL_DEBUG
00286                 NLMISC::CVector *endPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride * numStep);
00287             #endif
00288             const CPSLocated::CParametricInfo &pi = _PInfo[indexInLocated];
00289             destPos = FillBufUsingSubdiv(pi.Pos, pi.Date, startDate, deltaT, numStep, destPos, stride);
00290             if (numStep != 0)
00291             {
00292                 float currDate = startDate - pi.Date;
00293                 nlassert(currDate >= 0);
00294                 do
00295                 {
00296                     #ifdef NL_DEBUG
00297                         nlassert(destPos < endPos);
00298                     #endif
00299                     destPos->x = pi.Pos.x + currDate * pi.Speed.x;
00300                     destPos->y = pi.Pos.y + currDate * pi.Speed.y;
00301                     destPos->z = pi.Pos.z + currDate * pi.Speed.z;
00302                     currDate += deltaT;
00303                     destPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride);
00304                 }
00305                 while (--numStep);
00306             }
00307     }
00308     CHECK_PS_INTEGRITY
00309 }
00310 
00311 
00313 void CPSLocated::performParametricMotion(TAnimationTime date)
00314 {
00315     NL_PS_FUNC(CPSLocated_performParametricMotion)
00316     CHECK_PS_INTEGRITY
00317     if (!_Size) return;
00318     nlassert(supportParametricMotion() && _ParametricMotion);
00319 
00320     if (_IntegrableForces.size() != 0)
00321     {
00322         bool accumulate = false;
00323         for (TForceVect::iterator it = _IntegrableForces.begin(); it != _IntegrableForces.end(); ++it)
00324         {
00325             nlassert((*it)->isIntegrable());
00326             (*it)->integrate(date, this, 0, _Size, &_Pos[0], &_Speed[0], accumulate);
00327             accumulate = true;
00328         }
00329     }
00330     else
00331     {
00332         CPSLocated::TPSAttribParametricInfo::const_iterator it = _PInfo.begin(),
00333                                             endIt = _PInfo.end();
00334         TPSAttribVector::iterator posIt = _Pos.begin();
00335         float deltaT;
00336         do
00337         {
00338             deltaT = date - it->Date;
00339             posIt->x = it->Pos.x + deltaT * it->Speed.x;
00340             posIt->y = it->Pos.y + deltaT * it->Speed.y;
00341             posIt->z = it->Pos.z + deltaT * it->Speed.z;
00342             ++posIt;
00343             ++it;
00344         }
00345         while (it != endIt);
00346     }
00347     CHECK_PS_INTEGRITY
00348 }
00349 
00352 void  CPSLocated::allocateParametricInfos(void)
00353 {
00354     NL_PS_FUNC(CPSLocated_allocateParametricInfos)
00355     CHECK_PS_INTEGRITY
00356     if (_ParametricMotion) return;
00357     nlassert(supportParametricMotion());
00358     nlassert(_Owner);
00359     const float date = _Owner->getSystemDate();
00360     _PInfo.resize(_MaxSize);
00361     // copy back infos from current position and speeds
00362     TPSAttribVector::const_iterator posIt = _Pos.begin(), endPosIt = _Pos.end();
00363     TPSAttribVector::const_iterator speedIt = _Speed.begin();
00364     while (posIt != endPosIt)
00365     {
00366         _PInfo.insert( CParametricInfo(*posIt, *speedIt, date) );
00367         ++posIt;
00368     }
00369     _ParametricMotion = true;
00370     notifyMotionTypeChanged();
00371     CHECK_PS_INTEGRITY
00372 }
00373 
00376 void  CPSLocated::releaseParametricInfos(void)
00377 {
00378     NL_PS_FUNC(CPSLocated_releaseParametricInfos)
00379     CHECK_PS_INTEGRITY
00380     if (!_ParametricMotion) return;
00381     NLMISC::contReset(_PInfo);
00382     _ParametricMotion = false;
00383     notifyMotionTypeChanged();
00384     CHECK_PS_INTEGRITY
00385 }
00386 
00389 bool      CPSLocated::supportParametricMotion(void) const
00390 {
00391     NL_PS_FUNC(CPSLocated_supportParametricMotion)
00392     return _NonIntegrableForceNbRefs == 0 && _NumIntegrableForceWithDifferentBasis == 0;
00393 }
00394 
00396 
00399 void    CPSLocated::enableParametricMotion(bool enable /*= true*/)
00400 {
00401     NL_PS_FUNC(CPSLocated_enableParametricMotion)
00402     CHECK_PS_INTEGRITY
00403     nlassert(supportParametricMotion());
00404     if (enable)
00405     {
00406         allocateParametricInfos();
00407     }
00408     else
00409     {
00410         releaseParametricInfos();
00411     }
00412     CHECK_PS_INTEGRITY
00413 }
00414 
00416 void CPSLocated::setMatrixMode(TPSMatrixMode matrixMode)
00417 {
00418     NL_PS_FUNC(CPSLocated_setMatrixMode)
00419     CHECK_PS_INTEGRITY
00420     if (matrixMode != getMatrixMode())
00421     {
00422         for (TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00423         {
00424             (*it)->basisChanged(matrixMode);
00425         }
00426 
00427         CParticleSystemProcess::setMatrixMode(matrixMode);
00428         for (TForceVect::iterator fIt = _IntegrableForces.begin(); fIt != _IntegrableForces.end(); ++fIt)
00429         {
00430             integrableForceBasisChanged( (*fIt)->getOwner()->getMatrixMode() );
00431         }
00432     }
00433     CHECK_PS_INTEGRITY
00434 }
00435 
00437 /*
00438 void CPSLocated::notifyMaxNumFacesChanged(void)
00439 {
00440     CHECK_PS_INTEGRITY
00441     if (!_Owner) return;
00442 
00443     // we examine whether we have particle attached to us, and ask for the max number of faces they may want
00444     _MaxNumFaces  = 0;
00445     for (TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00446     {
00447         if ((*it)->getType() == PSParticle)
00448         {
00449             uint maxNumFaces = ((CPSParticle *) (*it))->getMaxNumFaces();
00451             _MaxNumFaces += maxNumFaces;
00452         }
00453     }
00454     CHECK_PS_INTEGRITY
00455 }
00456 */
00457 
00459 uint CPSLocated::getNumWantedTris() const
00460 {
00461     NL_PS_FUNC(CPSLocated_getNumWantedTris)
00462     CHECK_PS_INTEGRITY
00463     if (!_Owner) return 0;
00464     uint numWantedTris = 0;
00465     for (TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00466     {
00467         if ((*it)->getType() == PSParticle)
00468         {
00469             numWantedTris += NLMISC::safe_cast<CPSParticle *>(*it)->getNumWantedTris();
00470         }
00471     }
00472     CHECK_PS_INTEGRITY
00473     return numWantedTris;
00474 }
00475 
00476 /*
00478 uint CPSLocated::querryMaxWantedNumFaces(void)
00479 {
00480     return _MaxNumFaces;
00481 }
00482 */
00483 
00486 bool CPSLocated::hasParticles(void) const
00487 {
00488     NL_PS_FUNC(CPSLocated_hasParticles)
00489     CHECK_PS_INTEGRITY
00490     for (TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00491     {
00492         if ((*it)->getType() == PSParticle && (*it)->hasParticles()) return true;
00493     }
00494     CHECK_PS_INTEGRITY
00495     return false;
00496 }
00497 
00500 bool CPSLocated::hasEmitters(void) const
00501 {
00502     NL_PS_FUNC(CPSLocated_hasEmitters)
00503     CHECK_PS_INTEGRITY
00504     for (TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00505     {
00506         if ((*it)->getType() == PSEmitter && (*it)->hasEmitters()) return true;
00507     }
00508     CHECK_PS_INTEGRITY
00509     return false;
00510 }
00511 
00513 void CPSLocated::getLODVect(NLMISC::CVector &v, float &offset, TPSMatrixMode matrixMode)
00514 {
00515     NL_PS_FUNC(CPSLocated_getLODVect)
00516     nlassert(_Owner);
00517     CHECK_PS_INTEGRITY
00518     _Owner->getLODVect(v, offset, matrixMode);
00519     CHECK_PS_INTEGRITY
00520 }
00521 
00523 float CPSLocated::getUserParam(uint numParam) const
00524 {
00525     NL_PS_FUNC(CPSLocated_getUserParam)
00526     nlassert(_Owner);
00527     CHECK_PS_INTEGRITY
00528     return _Owner->getUserParam(numParam);
00529 }
00530 
00532 CScene *CPSLocated::getScene(void)
00533 {
00534     NL_PS_FUNC(CPSLocated_getScene)
00535     nlassert(_Owner);
00536     CHECK_PS_INTEGRITY
00537     return _Owner->getScene();
00538 }
00539 
00541 void CPSLocated::incrementNbDrawnParticles(uint num)
00542 {
00543     NL_PS_FUNC(CPSLocated_incrementNbDrawnParticles)
00544     CHECK_PS_INTEGRITY
00545     CParticleSystem::NbParticlesDrawn += num; // for benchmark purpose
00546 }
00547 
00549 void CPSLocated::setInitialLife(TAnimationTime lifeTime)
00550 {
00551     NL_PS_FUNC(CPSLocated_setInitialLife)
00552     CHECK_PS_INTEGRITY
00553     _LastForever = false;
00554     _InitialLife = lifeTime;
00555     delete _LifeScheme;
00556     _LifeScheme = NULL;
00557 
00561     for (uint k = 0; k < _Size; ++k)
00562     {
00563         _Time[k] = 0.f;
00564     }
00565     //
00566     if (_Owner)
00567     {
00568         _Owner->systemDurationChanged();
00569     }
00570     CHECK_PS_INTEGRITY
00571 }
00572 
00574 void CPSLocated::setLifeScheme(CPSAttribMaker<float> *scheme)
00575 {
00576     NL_PS_FUNC(CPSLocated_setLifeScheme)
00577     CHECK_PS_INTEGRITY
00578     nlassert(scheme);
00579     nlassert(!scheme->hasMemory()); // scheme with memory is invalid there !!
00580     _LastForever = false;
00581     delete _LifeScheme;
00582     _LifeScheme = scheme;
00583     //
00584     if (_Owner)
00585     {
00586         _Owner->systemDurationChanged();
00587     }
00588     CHECK_PS_INTEGRITY
00589 }
00590 
00592 void CPSLocated::setInitialMass(float mass)
00593 {
00594     NL_PS_FUNC(CPSLocated_setInitialMass)
00595     CHECK_PS_INTEGRITY
00596     _InitialMass = mass;
00597     delete _MassScheme;
00598     _MassScheme = NULL;
00599     CHECK_PS_INTEGRITY
00600 }
00601 
00603 void CPSLocated::setMassScheme(CPSAttribMaker<float> *scheme)
00604 {
00605     NL_PS_FUNC(CPSLocated_setMassScheme)
00606     CHECK_PS_INTEGRITY
00607     nlassert(scheme);
00608     nlassert(!scheme->hasMemory()); // scheme with memory is invalid there !!
00609     delete _MassScheme;
00610     _MassScheme = scheme;
00611     CHECK_PS_INTEGRITY
00612 }
00613 
00616 const NLMISC::CMatrix &CPSLocated::getConversionMatrix(const CParticleSystem &ps, TPSMatrixMode destMode, TPSMatrixMode srcMode)
00617 {
00618     NL_PS_FUNC(CPSLocated_getConversionMatrix)
00619     switch(destMode)
00620     {
00621         case PSFXWorldMatrix:
00622             switch(srcMode)
00623             {
00624                 case PSFXWorldMatrix:               return NLMISC::CMatrix::Identity;
00625                 case PSIdentityMatrix:              return ps.getInvertedSysMat();
00626                 case PSUserMatrix:  return ps.getUserToFXMatrix();
00627                 default:
00628                 nlassert(0);
00629             }
00630         break;
00631         case PSIdentityMatrix:
00632             switch(srcMode)
00633             {
00634                 case PSFXWorldMatrix:               return ps.getSysMat();
00635                 case PSIdentityMatrix:              return NLMISC::CMatrix::Identity;
00636                 case PSUserMatrix:  return ps.getUserMatrix();
00637                 default:
00638                 nlassert(0);
00639             }
00640         break;
00641         case PSUserMatrix:
00642             switch(srcMode)
00643             {
00644                 case PSFXWorldMatrix:               return ps.getFXToUserMatrix();
00645                 case PSIdentityMatrix:              return ps.getInvertedUserMatrix();
00646                 case PSUserMatrix:  return NLMISC::CMatrix::Identity;
00647                 default:
00648                 nlassert(0);
00649             }
00650         break;
00651         default:
00652             nlassert(0);
00653     }
00654     nlassert(0);
00655     return NLMISC::CMatrix::Identity;
00656 }
00657 
00659 NLMISC::CVector CPSLocated::computeI(void) const
00660 {
00661     NL_PS_FUNC(CPSLocated_computeI)
00662     CHECK_PS_INTEGRITY
00663     const NLMISC::CMatrix &sysMat = _Owner->getSysMat();
00664     if (getMatrixMode() == PSIdentityMatrix)
00665     {
00666         if (!sysMat.hasScalePart())
00667         {
00668             return _Owner->getInvertedViewMat().getI();
00669         }
00670         else
00671         {
00672             return sysMat.getScaleUniform() * _Owner->getInvertedViewMat().getI();
00673         }
00674     }
00675     else
00676     {
00677         if (!sysMat.hasScalePart())
00678         {
00679             // we must express the I vector in the system basis, so we need to multiply it by the inverted matrix of the system
00680             return getWorldToLocalMatrix().mulVector(_Owner->getInvertedViewMat().getI());
00681         }
00682         else
00683         {
00684             return sysMat.getScaleUniform() * getWorldToLocalMatrix().mulVector(_Owner->getInvertedViewMat().getI());
00685         }
00686     }
00687 }
00688 
00690 NLMISC::CVector CPSLocated::computeIWithZAxisAligned(void) const
00691 {
00692     NL_PS_FUNC(CPSLocated_computeIWithZAxisAligned)
00693     CHECK_PS_INTEGRITY
00694     const NLMISC::CMatrix &sysMat = _Owner->getSysMat();
00695     const CVector &camI = _Owner->getInvertedViewMat().getI();
00696     CVector I(camI.x, camI.y, 0.f);
00697     I.normalize();
00698     if (getMatrixMode() == PSIdentityMatrix)
00699     {
00700         if (!sysMat.hasScalePart())
00701         {
00702             return I;
00703         }
00704         else
00705         {
00706             return sysMat.getScaleUniform() * I;
00707         }
00708     }
00709     else
00710     {
00711         if (!sysMat.hasScalePart())
00712         {
00713             // we must express the I vector in the system basis, so we need to multiply it by the inverted matrix of the system
00714             return getWorldToLocalMatrix().mulVector(I);
00715         }
00716         else
00717         {
00718             return sysMat.getScaleUniform() * getWorldToLocalMatrix().mulVector(I);
00719         }
00720     }
00721 }
00722 
00724 NLMISC::CVector CPSLocated::computeJ(void) const
00725 {
00726     NL_PS_FUNC(CPSLocated_computeJ)
00727     CHECK_PS_INTEGRITY
00728     const NLMISC::CMatrix &sysMat = _Owner->getSysMat();
00729     if (getMatrixMode() == PSIdentityMatrix)
00730     {
00731         if (!sysMat.hasScalePart())
00732         {
00733             return _Owner->getInvertedViewMat().getJ();
00734         }
00735         else
00736         {
00737             return sysMat.getScaleUniform() * _Owner->getInvertedViewMat().getJ();
00738         }
00739     }
00740     else
00741     {
00742         if (!sysMat.hasScalePart())
00743         {
00744             // we must express the J vector in the system basis, so we need to multiply it by the inverted matrix of the system
00745             return getWorldToLocalMatrix().mulVector(_Owner->getInvertedViewMat().getJ());
00746         }
00747         else
00748         {
00749             return sysMat.getScaleUniform() * getWorldToLocalMatrix().mulVector(_Owner->getInvertedViewMat().getJ());
00750         }
00751     }
00752 }
00753 
00755 NLMISC::CVector CPSLocated::computeK(void) const
00756 {
00757     NL_PS_FUNC(CPSLocated_computeK)
00758     CHECK_PS_INTEGRITY
00759     const NLMISC::CMatrix &sysMat = _Owner->getSysMat();
00760     if (getMatrixMode() == PSIdentityMatrix)
00761     {
00762 
00763         if (!sysMat.hasScalePart())
00764         {
00765             return _Owner->getInvertedViewMat().getK();
00766         }
00767         else
00768         {
00769             return sysMat.getScaleUniform() * _Owner->getInvertedViewMat().getK();
00770         }
00771     }
00772     else
00773     {
00774         if (!sysMat.hasScalePart())
00775         {
00776             // we must express the K vector in the system basis, so we need to multiply it by the inverted matrix of the system
00777             return getWorldToLocalMatrix().mulVector(_Owner->getInvertedViewMat().getK());
00778         }
00779         else
00780         {
00781             return sysMat.getScaleUniform() * getWorldToLocalMatrix().mulVector(_Owner->getInvertedViewMat().getK());
00782         }
00783     }
00784 }
00785 
00787 NLMISC::CVector CPSLocated::computeKWithZAxisAligned(void) const
00788 {
00789     NL_PS_FUNC(CPSLocated_computeKWithZAxisAligned)
00790     CHECK_PS_INTEGRITY
00791         const NLMISC::CMatrix &sysMat = _Owner->getSysMat();
00792     if (getMatrixMode() == PSIdentityMatrix)
00793     {
00794         if (!sysMat.hasScalePart())
00795         {
00796             return CVector::K;
00797         }
00798         else
00799         {
00800             return CVector(0.f, 0.f, sysMat.getScaleUniform());
00801         }
00802     }
00803     else
00804     {
00805         if (!sysMat.hasScalePart())
00806         {
00807             // we must express the K vector in the system basis, so we need to multiply it by the inverted matrix of the system
00808             return getWorldToLocalMatrix().mulVector(CVector::K);
00809         }
00810         else
00811         {
00812             return getWorldToLocalMatrix().mulVector(CVector(0.f, 0.f, sysMat.getScaleUniform()));
00813         }
00814     }
00815 }
00816 
00818 IDriver *CPSLocated::getDriver() const
00819 {
00820     NL_PS_FUNC(CPSLocated_getDriver)
00821     CHECK_PS_INTEGRITY
00822     nlassert(_Owner);
00823     nlassert (_Owner->getDriver() ); // you haven't called setDriver on the system
00824     return _Owner->getDriver();
00825 }
00826 
00829 CPSLocated::~CPSLocated()
00830 {
00831     NL_PS_FUNC(CPSLocated_CPSLocated)
00832     CHECK_PS_INTEGRITY
00833     // we must do a copy, because the subsequent call can modify this vector
00834     TDtorObserversVect copyVect(_DtorObserversVect.begin(), _DtorObserversVect.end());
00835     // call all the dtor observers
00836     for (TDtorObserversVect::iterator it = copyVect.begin(); it != copyVect.end(); ++it)
00837     {
00838         (*it)->notifyTargetRemoved(this);
00839     }
00840 
00841     nlassert(_CollisionInfoNbRef == 0); //If this is not = 0, then someone didnt call releaseCollisionInfo
00842                                          // If this happen, you can register with the registerDTorObserver
00843                                          // (observer pattern)
00844                                          // and override notifyTargetRemove to call releaseCollisionInfo
00845     nlassert(_IntegrableForces.size() == 0);
00846     nlassert(_NonIntegrableForceNbRefs == 0);
00847 
00848     // delete all bindable
00849     for (TLocatedBoundCont::iterator it2 = _LocatedBoundCont.begin(); it2 != _LocatedBoundCont.end(); ++it2)
00850     {
00851         (*it2)->finalize();
00852         delete *it2;
00853     }
00854     _LocatedBoundCont.clear();
00855 
00856     delete _LifeScheme;
00857     delete _MassScheme;
00858     delete _CollisionNextPos;
00859     CHECK_PS_INTEGRITY
00860 }
00861 
00863 
00866 bool CPSLocated::bind(CPSLocatedBindable *lb)
00867 {
00868     NL_PS_FUNC(CPSLocated_bind)
00869     CHECK_PS_INTEGRITY
00870     nlassert(std::find(_LocatedBoundCont.begin(), _LocatedBoundCont.end(), lb) == _LocatedBoundCont.end());
00871     TLocatedBoundCont::iterator it = _LocatedBoundCont.begin();
00872     while (it != _LocatedBoundCont.end() && **it < *lb) // the "<" operator sort them correctly
00873     {
00874         ++it;
00875     }
00876 
00877     _LocatedBoundCont.insert(it, lb);
00878     lb->setOwner(this);
00879     lb->resize(_MaxSize);
00880 
00881     // any located bindable that is bound to us should have no element in it for now !!
00882     // we resize it anyway...
00883 
00884     uint32 initialSize  = _Size;
00885     CPSEmitterInfo ei;
00886     ei.setDefaults();
00887     for (uint k = 0; k < initialSize; ++k)
00888     {
00889         _Size = k;
00890         lb->newElement(ei);
00891     }
00892     _Size = initialSize;
00893 
00894 
00895     if (_ParametricMotion) lb->motionTypeChanged(true);
00896 
00898     //notifyMaxNumFacesChanged();
00899 
00900     if (_Owner)
00901     {
00902         CParticleSystem *ps = _Owner;
00903         if (ps->getBypassMaxNumIntegrationSteps())
00904         {
00905             if (!ps->canFinish())
00906             {
00907                 unbind(getIndexOf(lb));
00908                 nlwarning("<CPSLocated::bind> Can't bind the located : this causes the system to last forever, and it has been flagged with 'BypassMaxNumIntegrationSteps'. Located is not bound.");
00909                 return false;
00910             }
00911         }
00912         // if there's an extern id, register in lb list
00913         if (lb->getExternID() != 0)
00914         {
00915             // register in ID list
00916             ps->registerLocatedBindableExternID(lb->getExternID(), lb);
00917         }
00918         _Owner->systemDurationChanged();
00919     }
00920 
00921     CHECK_PS_INTEGRITY
00922     return true;
00923 }
00924 
00926 void CPSLocated::remove(const CPSLocatedBindable *p)
00927 {
00928     NL_PS_FUNC(CPSLocated_remove)
00929     CHECK_PS_INTEGRITY
00930     TLocatedBoundCont::iterator it = std::find(_LocatedBoundCont.begin(), _LocatedBoundCont.end(), p);
00931     nlassert(it != _LocatedBoundCont.end());
00932     (*it)->finalize();
00933     delete *it;
00934     _LocatedBoundCont.erase(it);
00935     if (_Owner)
00936     {
00937         _Owner->systemDurationChanged();
00938     }
00939     CHECK_PS_INTEGRITY
00940 }
00941 
00943 void CPSLocated::registerDtorObserver(CPSLocatedBindable *anObserver)
00944 {
00945     NL_PS_FUNC(CPSLocated_registerDtorObserver)
00946     CHECK_PS_INTEGRITY
00947     // check whether the observer wasn't registered twice
00948     nlassert(std::find(_DtorObserversVect.begin(), _DtorObserversVect.end(), anObserver) == _DtorObserversVect.end());
00949     _DtorObserversVect.push_back(anObserver);
00950     CHECK_PS_INTEGRITY
00951 }
00952 
00954 void CPSLocated::unregisterDtorObserver(CPSLocatedBindable *anObserver)
00955 {
00956     NL_PS_FUNC(CPSLocated_unregisterDtorObserver)
00957     CHECK_PS_INTEGRITY
00958     // check that it was registered
00959     TDtorObserversVect::iterator it = std::find(_DtorObserversVect.begin(), _DtorObserversVect.end(), anObserver);
00960     nlassert(it != _DtorObserversVect.end());
00961     _DtorObserversVect.erase(it);
00962     CHECK_PS_INTEGRITY
00963 }
00964 
00965 
00967 void CPSLocated::postNewElement(const NLMISC::CVector &pos,
00968                                 const NLMISC::CVector &speed,
00969                                 CPSLocated &emitterLocated,
00970                                 uint32 indexInEmitter,
00971                                 TPSMatrixMode speedCoordSystem,
00972                                 TAnimationTime lifeTime)
00973 {
00974     NL_PS_FUNC(CPSLocated_postNewElement)
00975     nlassert(CParticleSystem::InsideSimLoop); // should be called only inside the sim loop!
00976     // In the event loop life of emitter is updated just after particles are spawned, so we must check there if the particle wasn't emitted when the
00977     // emitter was already destroyed
00978     // When postNewElement is called, the particle and the emitter that created it live at the same date, so EmitterLife - ParticleLife should be > 1.f
00979     float emitterLife;
00980     if (!emitterLocated.getLastForever())
00981     {
00982         if (emitterLocated._LifeScheme)
00983         {
00984             emitterLife = emitterLocated._Time[indexInEmitter] - lifeTime * CParticleSystem::RealEllapsedTimeRatio * emitterLocated._TimeIncrement[indexInEmitter];
00985             if (emitterLife >= 1.f)
00986             {
00987                 return; // emitter had finished its life
00988             }
00989         }
00990         else
00991         {
00992             emitterLife = emitterLocated._Time[indexInEmitter] * emitterLocated._InitialLife - lifeTime * CParticleSystem::RealEllapsedTimeRatio;
00993             if (emitterLife >= emitterLocated._InitialLife)
00994             {
00995                 return; // emitter had finished its life
00996             }
00997             if (emitterLocated._InitialLife != 0.f)
00998             {
00999                 emitterLife /= emitterLocated._InitialLife;
01000             }
01001         }
01002     }
01003     else
01004     {
01005         emitterLife = emitterLocated.getTime()[indexInEmitter];
01006     }
01007 
01008     // now check that the emitter didn't collide before it spawned a particle
01009     if (emitterLocated.hasCollisionInfos())
01010     {
01011         const CPSCollisionInfo &ci = _Collisions[indexInEmitter];
01012         if (ci.Dist != -1.f)
01013         {
01014             // a collision occured, check time from collision to next time step
01015             if ((emitterLocated.getPos()[indexInEmitter] - ci.NewPos) * (pos - ci.NewPos) > 0.f) return; // discard emit that are farther than the collision
01016         }
01017     }
01018 
01019 
01020     // create a request to create a new element
01021     CParticleSystem::CSpawnVect &sp = *CParticleSystem::_Spawns[getIndex()];
01022     if (!_Owner->getAutoCountFlag() && sp.MaxNumSpawns == sp.SpawnInfos.size()) return; // no more place to spawn
01023     if (getMaxSize() >= ((1 << 16) - 1)) return;
01024     sp.SpawnInfos.resize(sp.SpawnInfos.size() + 1);
01025     CPSSpawnInfo &si = sp.SpawnInfos.back();
01026     si.EmitterInfo.Pos = emitterLocated.getPos()[indexInEmitter];
01027     si.EmitterInfo.Speed = emitterLocated.getSpeed()[indexInEmitter];
01028     si.EmitterInfo.InvMass = emitterLocated.getInvMass()[indexInEmitter];
01029     si.EmitterInfo.Life = emitterLife;
01030     si.EmitterInfo.Loc = &emitterLocated;
01031     si.SpawnPos = pos;
01032     si.Speed = speed;
01033     si.SpeedCoordSystem = speedCoordSystem;
01034     si.LifeTime = lifeTime;
01035 }
01036 
01037 
01039 sint32 CPSLocated::newElement(const CPSSpawnInfo &si, bool doEmitOnce /* = false */, TAnimationTime ellapsedTime)
01040 {
01041     NL_PS_FUNC(CPSLocated_newElement)
01042     CHECK_PS_INTEGRITY
01043     sint32 creationIndex;
01044 
01045     // get the convertion matrix  from the emitter basis to the emittee basis
01046     // if the emitter is null, we assume that the coordinate are given in the chosen basis for this particle type
01047     if (_MaxSize == _Size)
01048     {
01049         if (_Owner && _Owner->getAutoCountFlag() && getMaxSize() < ((1 << 16) - 1) )
01050         {
01051             // we are probably in edition mode -> auto-count mode helps to compute ideal particle array size
01052             // but at the expense of costly allocations
01053             uint maxSize = getMaxSize();
01054             resize((uint32) std::min((uint) NLMISC::raiseToNextPowerOf2(maxSize + 1), (uint) ((1 << 16) - 1))); // force a reserve with next power of 2 (no important in edition mode)
01055             resize(maxSize + 1);
01056             CParticleSystem::_SpawnPos.resize(maxSize + 1);
01057         }
01058         else
01059         {
01060             return -1;
01061         }
01062     }
01063 
01064     // During creation, we interpolate the position of the system (by using the ellapsed time) if particle are created in world basis and if the emitter is in local basis.
01065     // Example a fireball FX let particles in world basis, but the fireball is moving. If we dont interpolate position between 2 frames, emission will appear to be "sporadic".
01066     // For now, we manage the local to world case. The world to local is possible, but not very useful
01067     switch(si.EmitterInfo.Loc ? si.EmitterInfo.Loc->getMatrixMode() : this->getMatrixMode())
01068     {
01069         case PSFXWorldMatrix:
01070             switch(this->getMatrixMode())
01071             {
01072                 case PSFXWorldMatrix:
01073                 {
01074                     creationIndex  =_Pos.insert(si.SpawnPos);
01075                 }
01076                 break;
01077                 case PSIdentityMatrix:
01078                 {
01079                     CVector fxPosDelta;
01080                     _Owner->interpolateFXPosDelta(fxPosDelta, si.LifeTime);
01081                     creationIndex  =_Pos.insert(_Owner->getSysMat() * si.SpawnPos + fxPosDelta);
01082                 }
01083                 break;
01084                 case PSUserMatrix:
01085                 {
01086                     CVector fxPosDelta;
01087                     _Owner->interpolateFXPosDelta(fxPosDelta, si.LifeTime);
01088                     CVector userMatrixPosDelta;
01089                     _Owner->interpolateUserPosDelta(userMatrixPosDelta, si.LifeTime);
01090                     creationIndex  =_Pos.insert(_Owner->getInvertedUserMatrix() * (_Owner->getSysMat() * si.SpawnPos + fxPosDelta - userMatrixPosDelta));
01091                 }
01092                 break;
01093                 default:
01094                 nlassert(0);
01095             }
01096         break;
01097         case PSIdentityMatrix:
01098             switch(this->getMatrixMode())
01099             {
01100                 case PSFXWorldMatrix:
01101                 {
01102                     CVector fxPosDelta;
01103                     _Owner->interpolateFXPosDelta(fxPosDelta, si.LifeTime);
01104                     creationIndex  =_Pos.insert(_Owner->getInvertedSysMat() * (si.SpawnPos - fxPosDelta));
01105                 }
01106                 break;
01107                 case PSIdentityMatrix:
01108                 {
01109                     creationIndex  =_Pos.insert(si.SpawnPos);
01110                 }
01111                 break;
01112                 case PSUserMatrix:
01113                 {
01114                     CVector userMatrixPosDelta;
01115                     _Owner->interpolateUserPosDelta(userMatrixPosDelta, si.LifeTime);
01116                     creationIndex  =_Pos.insert(_Owner->getInvertedUserMatrix() * (si.SpawnPos - userMatrixPosDelta));
01117                 }
01118                 break;
01119                 default:
01120                 nlassert(0);
01121             }
01122         break;
01123         case PSUserMatrix:
01124             switch(this->getMatrixMode())
01125             {
01126                 case PSFXWorldMatrix:
01127                 {
01128                     CVector fxPosDelta;
01129                     _Owner->interpolateFXPosDelta(fxPosDelta, si.LifeTime);
01130                     CVector userMatrixPosDelta;
01131                     _Owner->interpolateUserPosDelta(userMatrixPosDelta, si.LifeTime);
01132                     creationIndex  =_Pos.insert(_Owner->getInvertedSysMat() * (_Owner->getUserMatrix() * si.SpawnPos + userMatrixPosDelta- fxPosDelta));
01133                 }
01134                 break;
01135                 case PSIdentityMatrix:
01136                 {
01137                     CVector userMatrixPosDelta;
01138                     _Owner->interpolateUserPosDelta(userMatrixPosDelta, si.LifeTime);
01139                     creationIndex  =_Pos.insert(_Owner->getUserMatrix() * si.SpawnPos + userMatrixPosDelta);
01140                 }
01141                 break;
01142                 case PSUserMatrix:
01143                 {
01144                     creationIndex  =_Pos.insert(si.SpawnPos);
01145                 }
01146                 break;
01147                 default:
01148                 nlassert(0);
01149             }
01150         break;
01151         default:
01152             nlassert(0);
01153     }
01154 
01155 
01156     nlassert(creationIndex != -1); // all attributs must contains the same number of elements
01157 
01158     if (si.SpeedCoordSystem == this->getMatrixMode()) // is speed vector expressed in the good basis ?
01159     {
01160         _Speed.insert(si.Speed);
01161     }
01162     else
01163     {
01164         // must do conversion of speed
01165         nlassert(_Owner);
01166         const NLMISC::CMatrix &convMat = getConversionMatrix(*_Owner, this->getMatrixMode(), si.SpeedCoordSystem);
01167         _Speed.insert(convMat.mulVector(si.Speed));
01168     }
01169 
01170     _InvMass.insert(1.f / ((_MassScheme && si.EmitterInfo.Loc) ? _MassScheme->get(si.EmitterInfo) : _InitialMass ) );
01171     if (CParticleSystem::InsideSimLoop)
01172     {
01173         CParticleSystem::_SpawnPos[creationIndex] = _Pos[creationIndex];
01174     }
01175     // compute age of particle when it has been created
01176     if (getLastForever())
01177     {
01178         // age of particle is in seconds
01179         _Time.insert(CParticleSystem::RealEllapsedTimeRatio * si.LifeTime);
01180         _TimeIncrement.insert(_InitialLife != 0.f ? 1.f / _InitialLife : 1.f);
01181     }
01182     else
01183     {
01184         const float totalLifeTime = (_LifeScheme && si.EmitterInfo.Loc) ?  _LifeScheme->get(si.EmitterInfo) : _InitialLife ;
01185         float timeIncrement = totalLifeTime ? 1.f / totalLifeTime : 10E6f;
01186         _TimeIncrement.insert(timeIncrement);
01187         _Time.insert(CParticleSystem::RealEllapsedTimeRatio * si.LifeTime * timeIncrement);
01188     }
01189 
01190 
01191     // test whether parametric motion is used, and generate the infos that are needed then
01192     if (_ParametricMotion)
01193     {
01194         _PInfo.insert( CParametricInfo(_Pos[creationIndex], _Speed[creationIndex], _Owner->getSystemDate() + CParticleSystem::RealEllapsedTime - CParticleSystem::RealEllapsedTimeRatio * si.LifeTime) );
01195     }
01196     else
01197     {
01198         _Pos[creationIndex] += si.LifeTime * _Speed[creationIndex];
01199     }
01200 
01202     // generate datas for all bound objects  //
01204     for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01205     {
01206         (*it)->newElement(si.EmitterInfo);
01207         // if element is an emitter, then must bias the emission time counter because it will be updated of frameDT, but the particle has been alive for (frameDT - deltaT)
01208         if ((*it)->getType() == PSEmitter)
01209         {
01210             CPSEmitter *pEmit = NLMISC::safe_cast<CPSEmitter *>(*it);
01211             pEmit->_Phase[creationIndex] -= std::max(0.f, (ellapsedTime - si.LifeTime));
01212         }
01213     }
01214     if (doEmitOnce && !CPSEmitter::getBypassEmitOnDeath())
01215     {
01216         // can be called only outside the sim loop (when the user triggers an emitters for example)
01217         for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01218         {
01219             if ((*it)->getType() == PSEmitter)
01220             {
01221                 CPSEmitter *pEmit = NLMISC::safe_cast<CPSEmitter *>(*it);
01222                 if (pEmit->getEmissionType() == CPSEmitter::once)
01223                 {
01224                     for(uint k = 0; k < getSize(); ++k)
01225                     {
01226                         pEmit->singleEmit(k, 1);
01227                     }
01228                 }
01229             }
01230         }
01231     }
01232     if (_CollisionNextPos)
01233     {
01234         _CollisionNextPos->insert();
01235     }
01236     ++_Size;    // if this is modified, you must also modify the getNewElementIndex in this class
01237                 // because that method give the index of the element being created for overrider of the newElement method
01238                 // of the CPSLocatedClass (which is called just above)
01239 
01240 
01241     CHECK_PS_INTEGRITY
01242     return creationIndex;
01243 }
01244 
01245 
01247 sint32 CPSLocated::newElement(const CVector &pos, const CVector &speed, CPSLocated *emitter, uint32 indexInEmitter,
01248                               TPSMatrixMode speedCoordSystem, bool doEmitOnce /* = false */)
01249 {
01250     NL_PS_FUNC(CPSLocated_newElement)
01251     CPSSpawnInfo si;
01252     si.EmitterInfo.Loc = emitter;
01253     if (emitter)
01254     {
01255         si.EmitterInfo.Pos = emitter->getPos()[indexInEmitter];
01256         si.EmitterInfo.Speed = emitter->getSpeed()[indexInEmitter];
01257         si.EmitterInfo.InvMass = emitter->getInvMass()[indexInEmitter];
01258         si.EmitterInfo.Life = emitter->getTime()[indexInEmitter];
01259     }
01260     else
01261     {
01262         si.EmitterInfo.Pos = NLMISC::CVector::Null;
01263         si.EmitterInfo.Speed = NLMISC::CVector::Null;
01264         si.EmitterInfo.InvMass = 1.f;
01265         si.EmitterInfo.Life = 0.f;
01266     }
01267     si.SpawnPos = pos;
01268     si.Speed = speed;
01269     si.SpeedCoordSystem = speedCoordSystem;
01270     si.LifeTime = 0.f;
01271     return newElement(si, doEmitOnce, 0.f);
01272 }
01273 
01274 
01276 static inline uint32 IDToLittleEndian(uint32 input)
01277 {
01278     NL_PS_FUNC(IDToLittleEndian)
01279     #ifdef NL_LITTLE_ENDIAN
01280         return input;
01281     #else
01282         return ((input & (0xff<<24))>>24)
01283                 || ((input & (0xff<<16))>>8)
01284                 || ((input & (0xff<<8))<<8)
01285                 || ((input & 0xff)<<24);
01286     #endif
01287 }
01288 
01290 inline void CPSLocated::deleteElementBase(uint32 index)
01291 {
01292     NL_PS_FUNC(CPSLocated_deleteElementBase)
01293     // remove common located's attributes
01294     _InvMass.remove(index);
01295     _Pos.remove(index);
01296     _Speed.remove(index);
01297     _Time.remove(index);
01298     _TimeIncrement.remove(index);
01299     if (_CollisionNextPos)
01300     {
01301         _CollisionNextPos->remove(index);
01302     }
01303     if (_ParametricMotion)
01304     {
01305         _PInfo.remove(index);
01306     }
01307     --_Size;
01308     if (_TriggerOnDeath)
01309     {
01310         const uint32 id = IDToLittleEndian(_TriggerID);
01311         nlassert(_Owner);
01312         uint numLb  = _Owner->getNumLocatedBindableByExternID(id);
01313         for (uint k = 0; k < numLb; ++k)
01314         {
01315             CPSLocatedBindable *lb = _Owner->getLocatedBindableByExternID(id, k);
01316             if (lb->getType() == PSEmitter)
01317             {
01318                 CPSEmitter *e = NLMISC::safe_cast<CPSEmitter *>(lb);
01319                 e->setEmitTrigger();
01320             }
01321         }
01322     }
01323     CHECK_PS_INTEGRITY
01324 }
01325 
01327 void CPSLocated::deleteElement(uint32 index)
01328 {
01329     NL_PS_FUNC(CPSLocated_deleteElement)
01330     #ifdef NL_DEBUG
01331         if (CParticleSystem::InsideSimLoop)
01332         {
01333             nlassert(CParticleSystem::InsideRemoveLoop);
01334         }
01335     #endif
01336     CHECK_PS_INTEGRITY
01337     nlassert(index < _Size);
01338     for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01339     {
01340         (*it)->deleteElement(index);
01341     }
01342     deleteElementBase(index);
01343 }
01344 
01345 
01347 void CPSLocated::deleteElement(uint32 index, TAnimationTime timeToNextSimStep)
01348 {
01349     NL_PS_FUNC(CPSLocated_deleteElement)
01350     #ifdef NL_DEBUG
01351         if (CParticleSystem::InsideSimLoop)
01352         {
01353             nlassert(CParticleSystem::InsideRemoveLoop);
01354         }
01355     #endif
01356     nlassert(index < _Size);
01357     for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01358     {
01359         (*it)->deleteElement(index, timeToNextSimStep);
01360     }
01361     deleteElementBase(index);
01362 }
01363 
01366 void CPSLocated::resize(uint32 newSize)
01367 {
01368     NL_PS_FUNC(CPSLocated_resize)
01369     CHECK_PS_INTEGRITY
01370     nlassert(newSize < (1 << 16));
01371     if (newSize < _Size)
01372     {
01373         for (uint32 k = _Size - 1; k >= newSize; --k)
01374         {
01375             deleteElement(k);
01376 
01377             if (k == 0) break; // we're dealing with unsigned quantities
01378         }
01379         _Size = newSize;
01380     }
01381 
01382 
01383     _MaxSize = newSize;
01384     _InvMass.resize(newSize);
01385     _Pos.resize(newSize);
01386     _Speed.resize(newSize);
01387     _Time.resize(newSize);
01388     _TimeIncrement.resize(newSize);
01389 
01390     if (_ParametricMotion)
01391     {
01392         _PInfo.resize(newSize);
01393     }
01394 
01395     if (_CollisionNextPos)
01396     {
01397         _CollisionNextPos->resize(newSize);
01398     }
01399 
01400 
01401     // resize attributes for all bound objects
01402     for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01403     {
01404         (*it)->resize(newSize);
01405     }
01406 
01407 
01409     //notifyMaxNumFacesChanged();
01410     CHECK_PS_INTEGRITY
01411 }
01412 
01413 // dummy struct for serial of a field that has been removed
01414 class CDummyCollision
01415 {
01416 public:
01417     void serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01418     {
01419         NL_PS_FUNC(CDummyCollision_serial)
01420         f.serialVersion(1);
01421         float dummyDist = 0.f;
01422         NLMISC::CVector dummyNewPos, dummyNewSpeed;
01423         f.serial(dummyDist, dummyNewPos, dummyNewSpeed);
01424     };
01425 };
01426 
01428 void CPSLocated::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01429 {
01430     NL_PS_FUNC(CPSLocated_serial)
01431 
01432     // version 7 : - removed the field _NbFramesToSkip to get some space (it is never used)
01433     //             - removed the requestStack (system graph can't contains loops now)
01434     //             - removed _CollisonInfos because they are now static
01435 
01436     // version 4 to version 5 : bugfix with reading of collisions
01437     sint ver = f.serialVersion(7);
01438     CParticleSystemProcess::serial(f);
01439 
01440     if (f.isReading() && !CParticleSystem::getSerializeIdentifierFlag())
01441     {
01442         // just skip the name
01443         sint32 len;
01444         f.serial(len);
01445         f.seek(len, NLMISC::IStream::current);
01446     }
01447     else
01448     {
01449         f.serial(_Name);
01450     }
01451 
01452     f.serial(_InvMass);
01453     f.serial(_Pos);
01454     f.serial(_Speed);
01455     f.serial(_Time);
01456     if (f.isReading())
01457     {
01458         // tmp fix : some fx were saved with a life that is != to 0
01459         // this cause an assertion in CPSLocated::updateLife, because all particle are assumed to have an age of 0 when the system is started
01460         // TODO : saving _Time is maybe unecessary... or find something better for CPSLocated::updateLife
01461         uint timeSize = _Time.getSize();
01462         if (timeSize != 0)
01463         {
01464             std::fill(&_Time[0], &_Time[0] + timeSize, 0.f);
01465         }
01466     }
01467     f.serial(_TimeIncrement);
01468     f.serial(_Size);
01469     f.serial(_MaxSize);
01470 
01471     bool lastForever = _LastForever;
01472     f.serial(lastForever);
01473     _LastForever = lastForever;
01474 
01475     if (ver < 7)
01476     {
01477         nlassert(f.isReading());
01478         // serial a dummy ptr (previous code did a serial ptr)
01479         uint64 dummyPtr;
01480         f.serial(dummyPtr);
01481         if (dummyPtr)
01482         {
01483             #ifdef PS_FAST_ALLOC
01484                 extern NLMISC::CContiguousBlockAllocator *PSBlockAllocator;
01485                 NLMISC::CContiguousBlockAllocator *oldAlloc = PSBlockAllocator;
01486                 PSBlockAllocator = NULL;
01487             #endif
01488             static CPSAttrib<CDummyCollision> col;
01489             col.clear();
01490             f.serial(col);
01491             #ifdef PS_FAST_ALLOC
01492                 PSBlockAllocator = oldAlloc;
01493             #endif
01494         }
01495     }
01496     f.serial(_CollisionInfoNbRef); // TODO avoid to serialize this ?
01497     //
01498     if (f.isReading())
01499     {
01500         if (_CollisionInfoNbRef)
01501         {
01502             _CollisionNextPos = new TPSAttribVector;
01503             _CollisionNextPos->resize(_Pos.getMaxSize());
01504             for(uint k = 0; k < _Size; ++k)
01505             {
01506                 _CollisionNextPos->insert();
01507             }
01508         }
01509     }
01510     //CHECK_PS_INTEGRITY
01511     if (f.isReading())
01512     {
01513         delete _LifeScheme;
01514         delete _MassScheme;
01515 
01516         bool useScheme;
01517         f.serial(useScheme);
01518         if (useScheme)
01519         {
01520             f.serialPolyPtr(_LifeScheme);
01521         }
01522         else
01523         {
01524             f.serial(_InitialLife);
01525             _LifeScheme = NULL;
01526         }
01527 
01528         f.serial(useScheme);
01529         if (useScheme)
01530         {
01531             f.serialPolyPtr(_MassScheme);
01532         }
01533         else
01534         {
01535             f.serial(_InitialMass);
01536             nlassert(_InitialMass > 0);
01537             _MassScheme = NULL;
01538         }
01539     }
01540     else
01541     {
01542         bool bFalse = false, bTrue = true;
01543         if (_LifeScheme)
01544         {
01545             f.serial(bTrue);
01546             f.serialPolyPtr(_LifeScheme);
01547         }
01548         else
01549         {
01550             f.serial(bFalse);
01551             f.serial(_InitialLife);
01552         }
01553         if (_MassScheme)
01554         {
01555             f.serial(bTrue);
01556             f.serialPolyPtr(_MassScheme);
01557         }
01558         else
01559         {
01560             f.serial(bFalse);
01561             nlassert(_InitialMass > 0);
01562             f.serial(_InitialMass);
01563         }
01564     }
01565 
01566     if (ver < 7)
01567     {
01568         uint32 dummy = 0; // was previously the field "_NbFramesToSkip"
01569         f.serial(dummy);
01570     }
01571 
01572     f.serialContPolyPtr(_DtorObserversVect);
01573 
01574     if (ver < 7)
01575     {
01576         nlassert(f.isReading());
01577         // previously, there was a request stack serialized (because system permitted loops)
01578         uint32 size;
01579         f.serial(size);
01580         nlassert(size == 0);
01581         /*
01582         for (uint32 k = 0; k < size; ++k)
01583         {
01584             TNewElementRequestStack::value_type t;
01585             f.serial(t);
01586             _RequestStack.push(t);
01587         }
01588         */
01589     }
01590 
01591     if (ver < 7)
01592     {
01593         nlassert(f.isReading());
01594         bool dummy;
01595         f.serial(dummy); // was previously the flag "_UpdateLock"
01596     }
01597 
01598     f.serialContPolyPtr(_LocatedBoundCont);
01599 
01600 
01601     // check that owners are good
01602     #ifdef NL_DEBUG
01603         for(uint k = 0; k < _LocatedBoundCont.size(); ++k)
01604         {
01605             nlassert(_LocatedBoundCont[k]->getOwner() == this);
01606         }
01607     #endif
01608 
01609     if (ver > 1)
01610     {
01611         bool lodDegradation = _LODDegradation;
01612         f.serial(lodDegradation);
01613         _LODDegradation = lodDegradation;
01614     }
01615 
01616     if (ver > 2)
01617     {
01618         bool parametricMotion = _ParametricMotion;
01619         f.serial(parametricMotion);
01620         _ParametricMotion = parametricMotion;
01621     }
01622 
01623     if (f.isReading())
01624     {
01625         // evaluate our max number of faces
01626         //notifyMaxNumFacesChanged();
01627 
01628         if (_ParametricMotion)
01629         {
01630             _ParametricMotion = false;
01631             allocateParametricInfos();
01632             _ParametricMotion = true;
01633         }
01634     }
01635 
01636     if (ver > 3)
01637     {
01638         bool  triggerOnDeath = _TriggerOnDeath;
01639         f.serial(triggerOnDeath);
01640         _TriggerOnDeath = triggerOnDeath;
01641         f.serial(_TriggerID);
01642     }
01643     CHECK_PS_INTEGRITY
01644 }
01645 
01647 // integrate speed of particles. Makes eventually use of SSE instructions when present
01648 static void IntegrateSpeed(uint count, float *src1, const float *src2, float *dest, float ellapsedTime)
01649 {
01650     NL_PS_FUNC(IntegrateSpeed)
01651     #if 0 // this works, but is not enabled for now. The precision is not that good...
01652     /*
01653         #ifdef NL_OS_WINDOWS
01654 
01655 
01656 
01657         if (NLMISC::CCpuInfo::hasSSE()
01658             && ((uint) src1 & 15) == ((uint) src2 & 15)
01659             && ! ((uint) src1 & 3)
01660             && ! ((uint) src2 & 3)
01661            )   // must must be sure that memory alignment is identical
01662         {
01663 
01664             // compute first datas in order to align to 16 byte boudary
01665 
01666             uint alignCount =  ((uint) src1 >> 2) & 3; // number of float to process
01667 
01668             while (alignCount --)
01669             {
01670                 *src1++ += ellapsedTime * *src2 ++;
01671             }
01672 
01673 
01674 
01675             count -= alignCount;
01676             if (count > 3)
01677             {
01678                 float et[4] = { ellapsedTime, ellapsedTime, ellapsedTime, ellapsedTime};
01679                 // sse part of computation
01680                 __asm
01681                 {
01682                         mov  ecx, count
01683                         shr  ecx, 2
01684 
01685 
01686                         xor   edx, edx
01687 
01688                         mov    eax, src1
01689                         mov    ebx, src2
01690                         movups  xmm0, et[0]
01691                     myLoop:
01692                         movaps xmm2, [ebx + 8 * edx]
01693                         movaps xmm1, [eax + 8 * edx]
01694                         mulps  xmm2, xmm0
01695                         addps  xmm1, xmm2
01696                         movaps [eax + 8 * edx], xmm1
01697                         add edx, 2
01698                         dec ecx
01699                         jne myLoop
01700                 }
01701             }
01702             // proceed with left float
01703             count &= 3;
01704 
01705             if (count)
01706             {
01707                 src1 += alignCount;
01708                 src2 += alignCount;
01709                 do
01710                 {
01711                     *src1 += ellapsedTime * *src2;
01712 
01713                     ++src1;
01714                     ++src2;
01715                 }
01716                 while (--count);
01717             }
01718 
01719         }
01720         else
01721         #endif
01722         */
01723     #endif
01724     {
01725         // standard version
01726 
01727         // standard version
01728         uint countDiv8 = count>>3;
01729         count &= 7; // takes count % 8
01730 
01731         if (dest == src1)
01732         {
01733             while (countDiv8 --)
01734             {
01735                 src1[0] += ellapsedTime * src2[0];
01736                 src1[1] += ellapsedTime * src2[1];
01737                 src1[2] += ellapsedTime * src2[2];
01738                 src1[3] += ellapsedTime * src2[3];
01739 
01740                 src1[4] += ellapsedTime * src2[4];
01741                 src1[5] += ellapsedTime * src2[5];
01742                 src1[6] += ellapsedTime * src2[6];
01743                 src1[7] += ellapsedTime * src2[7];
01744 
01745                 src2 += 8;
01746                 src1 += 8;
01747             }
01748             while (count--)
01749             {
01750                 *src1++ += ellapsedTime * *src2++;
01751             }
01752         }
01753         else
01754         {
01755             while (countDiv8 --)
01756             {
01757                 dest[0] = src1[0] + ellapsedTime * src2[0];
01758                 dest[1] = src1[1] + ellapsedTime * src2[1];
01759                 dest[2] = src1[2] + ellapsedTime * src2[2];
01760                 dest[3] = src1[3] + ellapsedTime * src2[3];
01761                 dest[4] = src1[4] + ellapsedTime * src2[4];
01762                 dest[5] = src1[5] + ellapsedTime * src2[5];
01763                 dest[6] = src1[6] + ellapsedTime * src2[6];
01764                 dest[7] = src1[7] + ellapsedTime * src2[7];
01765                 src2 += 8;
01766                 src1 += 8;
01767                 dest += 8;
01768             }
01769             while (count--)
01770             {
01771                 *dest++ = *src1++ + ellapsedTime * *src2++;
01772             }
01773         }
01774     }
01775 }
01776 
01778 void CPSLocated::computeMotion()
01779 {
01780     NL_PS_FUNC(CPSLocated_computeMotion)
01781     nlassert(_Size);
01782     // there are 2 integration steps : with and without collisions
01783     if (!_CollisionNextPos) // no collisionner are used
01784     {
01785         {
01786             MINI_TIMER(PSMotion3)
01787             if (_Size != 0) // avoid referencing _Pos[0] if there's no size, causes STL vectors to assert...
01788                 IntegrateSpeed(_Size * 3, &_Pos[0].x, &_Speed[0].x, &_Pos[0].x, CParticleSystem::EllapsedTime);
01789         }
01790     }
01791     else
01792     {
01793         {
01794             MINI_TIMER(PSMotion4)
01795             // compute new position after the timeStep
01796             IntegrateSpeed(_Size * 3, &_Pos[0].x, &_Speed[0].x, &(*_CollisionNextPos)[0].x, CParticleSystem::EllapsedTime);
01797             nlassert(CPSLocated::_Collisions.size() >= _Size);
01798             computeCollisions(0, &_Pos[0], &(*_CollisionNextPos)[0]);
01799             // update new poositions by just swapping the 2 vectors
01800             _CollisionNextPos->swap(_Pos);
01801         }
01802     }
01803 }
01804 
01805 
01806 
01808 void CPSLocated::computeNewParticleMotion(uint firstInstanceIndex)
01809 {
01810     NL_PS_FUNC(CPSLocated_computeNewParticleMotion)
01811     nlassert(_CollisionNextPos);
01812     resetCollisions(_Size);
01813     computeCollisions(firstInstanceIndex, &CParticleSystem::_SpawnPos[0], &_Pos[0]);
01814 }
01815 
01817 void CPSLocated::resetCollisions(uint numInstances)
01818 {
01819     NL_PS_FUNC(CPSLocated_resetCollisions)
01820     CPSCollisionInfo *currCollision = _FirstCollision;
01821     while (currCollision)
01822     {
01823         currCollision->Dist = -1.f;
01824         currCollision = currCollision->Next;
01825     }
01826     _FirstCollision = NULL;
01827     if (numInstances > _Collisions.size())
01828     {
01829         uint oldSize = (uint) _Collisions.size();
01830         _Collisions.resize(numInstances);
01831         for(uint k = oldSize; k < numInstances; ++k)
01832         {
01833             _Collisions[k].Index = k;
01834         }
01835     }
01836 }
01837 
01839 void CPSLocated::updateCollisions()
01840 {
01841     NL_PS_FUNC(CPSLocated_updateCollisions)
01842     CPSCollisionInfo *currCollision = _FirstCollision;
01843     if (getLastForever())
01844     {
01845         while (currCollision)
01846         {
01847             _Pos[currCollision->Index] = currCollision->NewPos;
01848             std::swap(_Speed[currCollision->Index], currCollision->NewSpeed); // keep speed because may be needed when removing particles
01849             // notify each located bindable that a bounce occured ...
01850             for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01851             {
01852                 (*it)->bounceOccured(currCollision->Index, computeDateFromCollisionToNextSimStep(currCollision->Index, getAgeInSeconds(currCollision->Index)));
01853             }
01854             if (currCollision->CollisionZone->getCollisionBehaviour() == CPSZone::destroy)
01855             {
01856                 #ifdef NL_DEBUG
01857                     nlassert(CParticleSystem::_ParticleRemoveListIndex[currCollision->Index] == -1);
01858                 #endif
01859                 CParticleSystem::_ParticleToRemove.push_back(currCollision->Index);
01860                 #ifdef NL_DEBUG
01861                     nlassert(CParticleSystem::_ParticleToRemove.size() <= _Size);
01862                 #endif
01863                 CParticleSystem::_ParticleRemoveListIndex[currCollision->Index] = CParticleSystem::_ParticleToRemove.size() - 1;
01864 
01865             }
01866             currCollision = currCollision->Next;
01867         }
01868     }
01869     else
01870     {
01871         while (currCollision)
01872         {
01873             if (_Time[currCollision->Index] >= 1.f)
01874             {
01875                 // check whether particles died before the collision. If so, just continue (particle has already been inserted in the remove list), and cancel the collision
01876                 float timeToCollision = currCollision->Dist / _Speed[currCollision->Index].norm();
01877                 if (_Time[currCollision->Index] / _TimeIncrement[currCollision->Index] - timeToCollision * CParticleSystem::RealEllapsedTimeRatio >= 1.f)
01878                 {
01879                     // says that collision did not occurs
01880                     currCollision->Dist = -1.f;
01881                     currCollision = currCollision->Next;
01882                     continue;
01883                 }
01884             }
01885             // if particle is too old, check whether it died before the collision
01886             _Pos[currCollision->Index] = currCollision->NewPos;
01887             std::swap(_Speed[currCollision->Index], currCollision->NewSpeed);
01888             // notify each located bindable that a bounce occured ...
01889             if (!_LocatedBoundCont.empty())
01890             {
01891                 TAnimationTime timeFromcollisionToNextSimStep = computeDateFromCollisionToNextSimStep(currCollision->Index, getAgeInSeconds(currCollision->Index));
01892                 for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01893                 {
01894                     (*it)->bounceOccured(currCollision->Index, timeFromcollisionToNextSimStep);
01895                 }
01896             }
01897             if (currCollision->CollisionZone->getCollisionBehaviour() == CPSZone::destroy)
01898             {
01899                 if (_Time[currCollision->Index] < 1.f)
01900                 {
01901                     // insert particle only if not already dead
01902                     #ifdef NL_DEBUG
01903                         nlassert(CParticleSystem::_ParticleRemoveListIndex[currCollision->Index] == -1);
01904                     #endif
01905                     CParticleSystem::_ParticleToRemove.push_back(currCollision->Index);
01906                     #ifdef NL_DEBUG
01907                         nlassert(CParticleSystem::_ParticleToRemove.size() <= _Size);
01908                     #endif
01909                     CParticleSystem::_ParticleRemoveListIndex[currCollision->Index] = CParticleSystem::_ParticleToRemove.size() - 1;
01910                 }
01911             }
01912             currCollision = currCollision->Next;
01913         }
01914     }
01915 
01916 }
01917 
01919 void CPSLocated::doLODDegradation()
01920 {
01921     NL_PS_FUNC(CPSLocated_doLODDegradation)
01922     nlassert(CParticleSystem::InsideSimLoop);
01923     nlassert(!CParticleSystem::InsideRemoveLoop);
01924     CParticleSystem::InsideRemoveLoop = true;
01925     if (CParticleSystem::EllapsedTime > 0)
01926     {
01927         nlassert(_Owner);
01928         // compute the number of particles to show
01929         const uint maxToHave = (uint) (_MaxSize * _Owner->getOneMinusCurrentLODRatio());
01930         if (_Size > maxToHave) // too much instances ?
01931         {
01932             // choose a random element to start at, and a random step
01933             // this will avoid a pulse effect when the system is far away
01934 
01935             uint pos = maxToHave ? rand() % maxToHave : 0;
01936             uint step  = maxToHave ? rand() % maxToHave : 0;
01937 
01938             do
01939             {
01940                 deleteElement(pos);
01941                 pos += step;
01942                 if (pos >= maxToHave) pos -= maxToHave;
01943             }
01944             while (_Size !=maxToHave);
01945         }
01946     }
01947     CParticleSystem::InsideRemoveLoop = false;
01948 }
01949 
01951 void CPSLocated::step(TPSProcessPass pass)
01952 {
01953     NL_PS_FUNC(CPSLocated_step)
01954     CHECK_PS_INTEGRITY
01955     if (!_Size) return;
01956 
01957     if (pass != PSMotion)
01958     {
01959         {
01960             /*
01961             uint64 *target;
01962             switch(pass)
01963             {
01964                 case PSEmit: target = &PSStatEmit; break;
01965                 case PSCollision: target = &PSStatCollision; break;
01966                 default:
01967                     target = &PSStatRender;
01968                 break;
01969             }
01970             MINI_TIMER(*target)
01971             */
01972             // apply the pass to all bound objects
01973             for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01974             {
01975                 if ((*it)->isActive())
01976                 {
01977                     if ((*it)->getLOD() == PSLod1n2 || _Owner->getLOD() == (*it)->getLOD()) // has this object the right LOD ?
01978                     {
01979                         (*it)->step(pass);
01980                     }
01981                 }
01982             }
01983         }
01984     }
01985     else
01986     {
01987         for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01988         {
01989             if ((*it)->isActive())
01990             {
01991                 (*it)->step(pass);
01992             }
01993         }
01994 
01995     }
01996     CHECK_PS_INTEGRITY
01997 }
01998 
02000 void CPSLocated::updateLife()
02001 {
02002     NL_PS_FUNC(CPSLocated_updateLife)
02003     CHECK_PS_INTEGRITY
02004     if (!_Size) return;
02005     if (! _LastForever)
02006     {
02007         if (_LifeScheme != NULL)
02008         {
02009             TPSAttribTime::iterator itTime = _Time.begin(), itTimeInc = _TimeIncrement.begin();
02010             for (uint32 k = 0; k < _Size; ++k)
02011             {
02012                 *itTime += CParticleSystem::RealEllapsedTime * *itTimeInc;
02013                 if (*itTime >= 1.0f)
02014                 {
02015                     #ifdef NL_DEBUG
02016                         nlassert(CParticleSystem::_ParticleRemoveListIndex[k] == -1);
02017                     #endif
02018                     CParticleSystem::_ParticleToRemove.push_back(k);
02019                     #ifdef NL_DEBUG
02020                         nlassert(CParticleSystem::_ParticleToRemove.size() <= _Size);
02021                     #endif
02022                     CParticleSystem::_ParticleRemoveListIndex[k] = CParticleSystem::_ParticleToRemove.size() - 1;
02023                 }
02024                 ++itTime;
02025                 ++itTimeInc;
02026             }
02027         }
02028         else 
02029         {
02030             if (_InitialLife != 0)
02031             {
02032                 nlassert(_Owner);
02033                 float timeInc = CParticleSystem::RealEllapsedTime / _InitialLife;
02034                 if (_Owner->getSystemDate() + 0.1f + 2.f * timeInc >= (_InitialLife - CParticleSystem::RealEllapsedTime))
02035                 {
02036                     // NB : 0.1f + 2.f * timeInc added to avoid case were time of particle is slighty greater than 1.f after life update because that test failed
02037                     TPSAttribTime::iterator itTime = _Time.begin();
02038                     for (uint32 k = 0; k < _Size; ++k)
02039                     {
02040                         *itTime += timeInc;
02041                         if (*itTime >= 1.0f)
02042                         {
02043                             #ifdef NL_DEBUG
02044                                 nlassert(CParticleSystem::_ParticleRemoveListIndex[k] == -1);
02045                             #endif
02046                             CParticleSystem::_ParticleToRemove.push_back(k);
02047                             #ifdef NL_DEBUG
02048                                 nlassert(CParticleSystem::_ParticleToRemove.size() <= _Size);
02049                             #endif
02050                             CParticleSystem::_ParticleRemoveListIndex[k] = CParticleSystem::_ParticleToRemove.size() - 1;
02051                         }
02052                         ++ itTime;
02053                     }
02054                 }
02055                 else
02056                 {
02057                     // system has not lasted enough for any particle to die
02058                     TPSAttribTime::iterator itTime = _Time.begin(), itEndTime = _Time.end();
02059                     do
02060                     {
02061                         *itTime += timeInc;
02062                         ++itTime;
02063                     }
02064                     while (itTime != itEndTime);
02065                 }
02066             }
02067             else
02068             {
02069                 for(uint k = 0; k < _Size; ++k)
02070                 {
02071                     #ifdef NL_DEBUG
02072                         nlassert(CParticleSystem::_ParticleRemoveListIndex[k] == -1);
02073                     #endif
02074                     CParticleSystem::_ParticleToRemove.push_back(k);
02075                     #ifdef NL_DEBUG
02076                         nlassert(CParticleSystem::_ParticleToRemove.size() <= _Size);
02077                     #endif
02078                     CParticleSystem::_ParticleRemoveListIndex[k] = CParticleSystem::_ParticleToRemove.size() - 1;
02079                 }
02080             }
02081         }
02082     }
02083     else
02084     {
02085         // the time attribute gives the life in seconds
02086         TPSAttribTime::iterator itTime = _Time.begin(), endItTime = _Time.end();
02087         for (; itTime != endItTime; ++itTime)
02088         {
02089             *itTime += CParticleSystem::RealEllapsedTime;
02090         }
02091     }
02092         CHECK_PS_INTEGRITY
02093 }
02094 
02095 
02097 // When a particle is deleted, it is replaced by the last particle in the array
02098 // if this particle is to be deleted to, must update its new index
02099 static inline void removeParticleFromRemoveList(uint indexToRemove, uint arraySize)
02100 {
02101     NL_PS_FUNC(removeParticleFromRemoveList)
02102     if (indexToRemove != arraySize)
02103     {
02104         if (CParticleSystem::_ParticleRemoveListIndex[arraySize] != -1)
02105         {
02106             // when a particle is deleted, it is replaced by the last particle in the array
02107             // if this particle is to be deleted too, must update its new index (becomes the index of the particle that has just been deleted)
02108             CParticleSystem::_ParticleToRemove[CParticleSystem::_ParticleRemoveListIndex[arraySize]] = indexToRemove;
02109             CParticleSystem::_ParticleRemoveListIndex[indexToRemove] = CParticleSystem::_ParticleRemoveListIndex[arraySize];
02110             CParticleSystem::_ParticleRemoveListIndex[arraySize] = -1; // not to remove any more
02111         }
02112         else
02113         {
02114             CParticleSystem::_ParticleRemoveListIndex[indexToRemove] = -1;
02115         }
02116     }
02117     else
02118     {
02119         CParticleSystem::_ParticleRemoveListIndex[arraySize] = -1;
02120     }
02121 }
02122 
02123 void checkRemoveArray(uint size)
02124 {
02125     NL_PS_FUNC(checkRemoveArray)
02126     for(uint k = 0; k < size; ++k)
02127     {
02128         if (CParticleSystem::_ParticleRemoveListIndex[k] != -1)
02129         {
02130             nlassert(std::find(CParticleSystem::_ParticleRemoveListIndex.begin(), CParticleSystem::_ParticleRemoveListIndex.end(), CParticleSystem::_ParticleRemoveListIndex[k]) != CParticleSystem::_ParticleRemoveListIndex.end());
02131         }
02132     }
02133     for(uint k = 0; k < CParticleSystem::_ParticleToRemove.size(); ++k)
02134     {
02135         nlassert(CParticleSystem::_ParticleRemoveListIndex[CParticleSystem::_ParticleToRemove[k]] == (sint) k);
02136     }
02137 
02138 }
02139 
02140 
02142 #ifndef NL_DEBUG
02143     inline
02144 #endif
02145 TAnimationTime CPSLocated::computeDateFromCollisionToNextSimStep(uint particleIndex, float particleAgeInSeconds)
02146 {
02147     NL_PS_FUNC( CPSLocated_computeDateFromCollisionToNextSimStep)
02148     // compute time from the start of the sim step to the birth of the particle (or 0 if already born)
02149     float ageAtStart = CParticleSystem::RealEllapsedTime > particleAgeInSeconds ? CParticleSystem::RealEllapsedTime - particleAgeInSeconds : 0.f;
02150     ageAtStart /= CParticleSystem::RealEllapsedTimeRatio;
02151     // compute time to collision. The 'NewSpeed' field is swapped with speed of particle at the sim step start when 'updateCollision' is called, and thus contains the old speed.
02152     float norm = _Collisions[particleIndex].NewSpeed.norm();
02153     if (norm == 0.f) return 0.f;
02154     float timeToCollision = _Collisions[particleIndex].Dist / norm;
02155     // So time from collision to end of sim step is :
02156     TAnimationTime result = CParticleSystem::EllapsedTime - ageAtStart - timeToCollision;
02157     return std::max(0.f, result);
02158 }
02159 
02161 void CPSLocated::removeOldParticles()
02162 {
02163     NL_PS_FUNC(CPSLocated_removeOldParticles)
02164     nlassert(CParticleSystem::RealEllapsedTime > 0.f);
02165     #ifdef NL_DEBUG
02166         CParticleSystem::InsideRemoveLoop = true;
02167         checkRemoveArray(_Size);
02168     #endif
02169     // remove all elements that were marked as too old
02170     // if there are emitters marked as 'on' death, should correct position by moving backward (because motion is done on a whole time step, so particle is further than it should be)
02171     if (getLastForever())
02172     {
02173         // if the particle lasts for ever it can be destroyed only if it touch a collision zone flaged as 'destroy'
02174         // during the call to 'updateCollisions', the list of particles to remove will be updated so just test it
02175         if (hasCollisionInfos())
02176         {
02177             for(std::vector<uint>::iterator it = CParticleSystem::_ParticleToRemove.begin(); it != CParticleSystem::_ParticleToRemove.end(); ++it)
02178             {
02179                 if (_Collisions[*it].Dist != -1.f)
02180                 {
02181                     deleteElement(*it, computeDateFromCollisionToNextSimStep(*it, _Time[*it]));
02182                 }
02183                 else
02184                 {
02185                     deleteElement(*it);
02186                 }
02187                 removeParticleFromRemoveList(*it, _Size);
02188             }
02189         }
02190     }
02191     else
02192     if (hasCollisionInfos()) // particle has collision, and limited lifetime
02193     {
02194         float ellapsedTimeRatio = CParticleSystem::EllapsedTime / CParticleSystem::RealEllapsedTime;
02195         for(std::vector<uint>::iterator it = CParticleSystem::_ParticleToRemove.begin(); it != CParticleSystem::_ParticleToRemove.end(); ++it)
02196         {
02197             TAnimationTime timeUntilNextSimStep;
02198             if (_Collisions[*it].Dist == -1.f)
02199             {
02200                 // no collision occured
02201                 if (_Time[*it] > 1.f)
02202                 {
02203 
02204                     if (_LifeScheme)
02205                     {
02206                         _Pos[*it] -= _Speed[*it] * ((_Time[*it] - 1.f) / _TimeIncrement[*it]) * ellapsedTimeRatio;
02207                         timeUntilNextSimStep = (_Time[*it] - 1.f) / _TimeIncrement[*it];
02208                     }
02209                     else
02210                     {
02211                         _Pos[*it] -= _Speed[*it] * ((_Time[*it] - 1.f) * _InitialLife) * ellapsedTimeRatio;
02212                         timeUntilNextSimStep = (_Time[*it] - 1.f) * _InitialLife;
02213                     }
02214                     _Time[*it] = 0.9999f;
02215                 }
02216                 else
02217                 {
02218                     timeUntilNextSimStep = 0.f;
02219                 }
02220             }
02221             else
02222             {
02223                 // a collision occured before particle died, so pos is already good
02224                 if (_LifeScheme)
02225                 {
02226                     timeUntilNextSimStep = computeDateFromCollisionToNextSimStep(*it, _Time[*it] / _TimeIncrement[*it]);
02227                     // compute age of particle when collision occured
02228                     _Time[*it] -= timeUntilNextSimStep * _TimeIncrement[*it];
02229                     NLMISC::clamp(_Time[*it], 0.f, 1.f); // avoid imprecisions
02230                 }
02231                 else
02232                 {
02233                     timeUntilNextSimStep = computeDateFromCollisionToNextSimStep(*it, _Time[*it] * _InitialLife);
02234                     // compute age of particle when collision occured
02235                     _Time[*it] -= timeUntilNextSimStep / (_InitialLife == 0.f ? 1.f : _InitialLife);
02236                     NLMISC::clamp(_Time[*it], 0.f, 1.f); // avoid imprecisions
02237                 }
02238 
02239 
02240             }
02241             deleteElement(*it, timeUntilNextSimStep);
02242             removeParticleFromRemoveList(*it, _Size);
02243         }
02244     }
02245     else // particle has no collisions, and limited lifetime
02246     {
02247         float ellapsedTimeRatio = CParticleSystem::EllapsedTime / CParticleSystem::RealEllapsedTime;
02248         if (!isParametricMotionEnabled())
02249         {
02250             if (_LifeScheme)
02251             {
02252                 for(std::vector<uint>::iterator it = CParticleSystem::_ParticleToRemove.begin(); it != CParticleSystem::_ParticleToRemove.end(); ++it)
02253                 {
02254                     #ifdef NL_DEBUG
02255                         for(std::vector<uint>::iterator it2 = it; it2 != CParticleSystem::_ParticleToRemove.end(); ++it2)
02256                         {
02257                             nlassert(*it2 < _Size);
02258                         }
02259                     #endif
02260                     TAnimationTime timeUntilNextSimStep;
02261                     if (_Time[*it] > 1.f)
02262                     {
02263                         // move position backward (compute its position at death)
02264                         timeUntilNextSimStep = ((_Time[*it] - 1.f) / _TimeIncrement[*it]) * ellapsedTimeRatio;
02265                         _Pos[*it] -= _Speed[*it] * timeUntilNextSimStep;
02266 
02267                         // force time to 1 because emitter 'on death' may rely on the date of emitter to compute its attributes
02268                         _Time[*it] = 0.9999f;
02269                     }
02270                     else
02271                     {
02272                         timeUntilNextSimStep = 0.f;
02273                     }
02274                     deleteElement(*it, timeUntilNextSimStep);
02275                     removeParticleFromRemoveList(*it, _Size);
02276                     #ifdef NL_DEBUG
02277                         for(std::vector<uint>::iterator it2 = it + 1; it2 != CParticleSystem::_ParticleToRemove.end(); ++it2)
02278                         {
02279                             nlassert(*it2 < _Size);
02280                         }
02281                     #endif
02282                 }
02283             }
02284             else
02285             {
02286                 for(std::vector<uint>::iterator it = CParticleSystem::_ParticleToRemove.begin(); it != CParticleSystem::_ParticleToRemove.end(); ++it)
02287                 {
02288                     TAnimationTime timeUntilNextSimStep;
02289                     if (_Time[*it] > 1.f)
02290                     {
02291                         // move position backward
02292                         timeUntilNextSimStep = (_Time[*it] - 1.f) * _InitialLife * ellapsedTimeRatio;
02293                         _Pos[*it] -= _Speed[*it] * timeUntilNextSimStep;
02294                         // force time to 1 because emitter 'on death' may rely on the date of emitter to compute its attributes
02295                         _Time[*it] = 0.9999f;
02296                     }
02297                     else
02298                     {
02299                         timeUntilNextSimStep = 0.f;
02300                     }
02301                     deleteElement(*it, timeUntilNextSimStep);
02302                     removeParticleFromRemoveList(*it, _Size);
02303                 }
02304             }
02305         }
02306         else
02307         {
02308             // parametric case
02309             if (_LifeScheme)
02310             {
02311                 for(std::vector<uint>::iterator it = CParticleSystem::_ParticleToRemove.begin(); it != CParticleSystem::_ParticleToRemove.end(); ++it)
02312                 {
02313                     TAnimationTime timeUntilNextSimStep;
02314                     if (_Time[*it] > 1.f)
02315                     {
02316                         // move position backward (compute its position at death)
02317                         timeUntilNextSimStep = (_Time[*it] - 1.f) / _TimeIncrement[*it];
02318                         computeParametricPos(_Owner->getSystemDate() + CParticleSystem::RealEllapsedTime - timeUntilNextSimStep, *it, _Pos[*it]);
02319                         timeUntilNextSimStep *= ellapsedTimeRatio;
02320                         // force time to 1 because emitter 'on death' may rely on the date of emitter to compute its attributes
02321                         _Time[*it] = 0.9999f;
02322                     }
02323                     else
02324                     {
02325                         timeUntilNextSimStep = 0.f;
02326                     }
02327                     deleteElement(*it, timeUntilNextSimStep);
02328                     removeParticleFromRemoveList(*it, _Size);
02329                 }
02330             }
02331             else
02332             {
02333                 for(std::vector<uint>::iterator it = CParticleSystem::_ParticleToRemove.begin(); it != CParticleSystem::_ParticleToRemove.end(); ++it)
02334                 {
02335                     TAnimationTime timeUntilNextSimStep;
02336                     if (_Time[*it] > 1.f)
02337                     {
02338                         // move position backward
02339                         timeUntilNextSimStep = (_Time[*it] - 1.f) * _InitialLife;
02340                         computeParametricPos(_Owner->getSystemDate() + CParticleSystem::RealEllapsedTime - timeUntilNextSimStep, *it, _Pos[*it]);
02341                         timeUntilNextSimStep *= ellapsedTimeRatio;
02342                         // force time to 1 because emitter 'on death' may rely on the date of emitter to compute its attributes
02343                         _Time[*it] = 0.9999f;
02344                     }
02345                     else
02346                     {
02347                         timeUntilNextSimStep = 0.f;
02348                     }
02349                     deleteElement(*it, timeUntilNextSimStep);
02350                     removeParticleFromRemoveList(*it, _Size);
02351                 }
02352             }
02353         }
02354     }
02355     #ifdef NL_DEBUG
02356         CParticleSystem::InsideRemoveLoop = false;
02357     #endif
02358     CParticleSystem::_ParticleToRemove.clear();
02359     #ifdef NL_DEBUG
02360         if (!_LastForever)
02361         {
02362             for(uint k = 0; k < _Size; ++k)
02363             {
02364                 nlassert(_Time[k] >= 0.f && _Time[k] <= 1.f);
02365             }
02366         }
02367     #endif
02368 }
02369 
02371 void CPSLocated::addNewlySpawnedParticles()
02372 {
02373     NL_PS_FUNC(CPSLocated_addNewlySpawnedParticles)
02374     #ifdef NL_DEBUG
02375         CParticleSystem::InsideNewElementsLoop = true;
02376     #endif
02377         CParticleSystem::CSpawnVect &spawns = *CParticleSystem::_Spawns[getIndex()];
02378         if (spawns.SpawnInfos.empty()) return;
02379         uint numSpawns = 0;
02380         if (!_Owner->getAutoCountFlag())
02381         {
02382             CParticleSystem::_SpawnPos.resize(getMaxSize());
02383             numSpawns = std::min((uint) (_MaxSize - _Size), (uint) spawns.SpawnInfos.size());
02384         }
02385         else
02386         {
02387             numSpawns = (uint) spawns.SpawnInfos.size();
02388         }
02389         CParticleSystem::TSpawnInfoVect::const_iterator endIt = spawns.SpawnInfos.begin() + numSpawns;
02390         if (_LastForever)
02391         {
02392             for (CParticleSystem::TSpawnInfoVect::const_iterator it = spawns.SpawnInfos.begin(); it !=endIt; ++it)
02393             {
02394 //          sint32 insertionIndex = 
02395                 newElement(*it, false, CParticleSystem::EllapsedTime);
02396             }
02397         }
02398         else
02399         {
02400             // to avoid warning in autocount mode
02401             //CParticleSystem::InsideSimLoop = false;
02402             for (CParticleSystem::TSpawnInfoVect::const_iterator it = spawns.SpawnInfos.begin(); it !=endIt; ++it)
02403             {
02404                 sint32 insertionIndex = newElement(*it, false, CParticleSystem::EllapsedTime);
02405                 #ifdef NL_DEBUG
02406                     nlassert(insertionIndex != -1)
02407                 #endif
02408                 if (_Time[insertionIndex] >= 1.f)
02409                 {
02410                     #ifdef NL_DEBUG
02411                         nlassert(CParticleSystem::_ParticleRemoveListIndex[insertionIndex] == -1);
02412                     #endif
02413                     CParticleSystem::_ParticleToRemove.push_back(insertionIndex);
02414                     #ifdef NL_DEBUG
02415                         nlassert(CParticleSystem::_ParticleToRemove.size() <= _Size);
02416                     #endif
02417                     CParticleSystem::_ParticleRemoveListIndex[insertionIndex] = CParticleSystem::_ParticleToRemove.size() - 1;
02418                 }
02419             }
02420             //CParticleSystem::InsideSimLoop = true;
02421         }
02422         spawns.SpawnInfos.clear();
02423     #ifdef NL_DEBUG
02424         CParticleSystem::InsideNewElementsLoop = false;
02425     #endif
02426 }
02427 
02429 bool CPSLocated::computeBBox(NLMISC::CAABBox &box) const
02430 {
02431     NL_PS_FUNC(CPSLocated_computeBBox)
02432     CHECK_PS_INTEGRITY
02433     if (!_Size) return false; // something to compute ?
02434 
02435 
02436     TLocatedBoundCont::const_iterator it;
02437     TPSAttribVector::const_iterator it2;
02438 
02439     // check whether any object bound to us need a bbox
02440 
02441     for (it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
02442     {
02443         if ((*it)->doesProduceBBox())
02444         {
02445             break;
02446         }
02447     }
02448 
02449     if (it == _LocatedBoundCont.end())
02450     {
02451         return false;
02452     }
02453 
02454     CVector min = _Pos[0], max = _Pos[0];
02455 
02456     for (it2 = _Pos.begin(); it2 != _Pos.end(); ++ it2)
02457     {
02458         const CVector &v = (*it2);
02459         min.minof(min, v);
02460         max.maxof(max, v);
02461     }
02462 
02463     box.setMinMax(min, max);
02464 
02465     // we've considered that located had no extent in space
02466     // now, we must call each objects that are bound to the located in order
02467     // to complete the bbox if they have no null extent
02468 
02469     NLMISC::CAABBox tmpBox, startBox = box;
02470 
02471     for (it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
02472     {
02473         if ((*it)->doesProduceBBox())
02474         {
02475             tmpBox = startBox;
02476             if ((*it)->completeBBox(tmpBox))
02477             {
02478                 box = NLMISC::CAABBox::computeAABBoxUnion(tmpBox, box);
02479             }
02480         }
02481     }
02482     CHECK_PS_INTEGRITY
02483     return true;
02484 }
02485 
02486 
02489 void CPSLocated::setupDriverModelMatrix(void)
02490 {
02491     NL_PS_FUNC(CPSLocated_setupDriverModelMatrix)
02492     CHECK_PS_INTEGRITY
02493     getDriver()->setupModelMatrix(getLocalToWorldMatrix());
02494     CHECK_PS_INTEGRITY
02495 }
02496 
02498 void CPSLocated::queryCollisionInfo(void)
02499 {
02500     NL_PS_FUNC(CPSLocated_queryCollisionInfo)
02501     CHECK_PS_INTEGRITY
02502     if (_CollisionInfoNbRef)
02503     {
02504         ++ _CollisionInfoNbRef;
02505     }
02506     else
02507     {
02508         _CollisionNextPos = new TPSAttribVector;
02509         _CollisionInfoNbRef = 1;
02510         _CollisionNextPos ->resize(_MaxSize);
02511         for(uint k = 0; k < _Size; ++k)
02512         {
02513             _CollisionNextPos->insert();
02514         }
02515     }
02516     CHECK_PS_INTEGRITY
02517 }
02518 
02520 void CPSLocated::releaseCollisionInfo(void)
02521 {
02522     NL_PS_FUNC(CPSLocated_releaseCollisionInfo)
02523     CHECK_PS_INTEGRITY
02524     nlassert(_CollisionInfoNbRef); // check whether queryCollisionInfo was called
02525                                     // so the number of refs must not = 0
02526     --_CollisionInfoNbRef;
02527     if (_CollisionInfoNbRef == 0)
02528     {
02529         delete _CollisionNextPos;
02530         _CollisionNextPos = NULL;
02531     }
02532     CHECK_PS_INTEGRITY
02533 }
02534 
02535 
02536 
02538 void CPSLocated::registerIntegrableForce(CPSForce *f)
02539 {
02540     NL_PS_FUNC(CPSLocated_registerIntegrableForce)
02541     CHECK_PS_INTEGRITY
02542     nlassert(std::find(_IntegrableForces.begin(), _IntegrableForces.end(), f) == _IntegrableForces.end()); // force registered twice
02543     _IntegrableForces.push_back(f);
02544     if (getMatrixMode() != f->getOwner()->getMatrixMode())
02545     {
02546         ++_NumIntegrableForceWithDifferentBasis;
02547         releaseParametricInfos();
02548     }
02549     CHECK_PS_INTEGRITY
02550 }
02551 
02552 
02554 void CPSLocated::unregisterIntegrableForce(CPSForce *f)
02555 {
02556     NL_PS_FUNC(CPSLocated_unregisterIntegrableForce)
02557     CHECK_PS_INTEGRITY
02558     nlassert(f->getOwner()); // f must be attached to a located
02559     CPSVector<CPSForce *>::V::iterator it = std::find(_IntegrableForces.begin(), _IntegrableForces.end(), f);
02560     nlassert(it != _IntegrableForces.end() );
02561     _IntegrableForces.erase(it);
02562     if (getMatrixMode() != f->getOwner()->getMatrixMode())
02563     {
02564         --_NumIntegrableForceWithDifferentBasis;
02565     }
02566     CHECK_PS_INTEGRITY
02567 }
02568 
02570 void CPSLocated::addNonIntegrableForceRef(void)
02571 {
02572     NL_PS_FUNC(CPSLocated_addNonIntegrableForceRef)
02573     CHECK_PS_INTEGRITY
02574     ++_NonIntegrableForceNbRefs;
02575     releaseParametricInfos();
02576     CHECK_PS_INTEGRITY
02577 }
02578 
02580 void CPSLocated::releaseNonIntegrableForceRef(void)
02581 {
02582     NL_PS_FUNC(CPSLocated_releaseNonIntegrableForceRef)
02583     CHECK_PS_INTEGRITY
02584     nlassert(_NonIntegrableForceNbRefs != 0);
02585     --_NonIntegrableForceNbRefs;
02586     CHECK_PS_INTEGRITY
02587 }
02588 
02589 
02591 void CPSLocated::integrableForceBasisChanged(TPSMatrixMode matrixMode)
02592 {
02593     NL_PS_FUNC(CPSLocated_integrableForceBasisChanged)
02594     CHECK_PS_INTEGRITY
02595     if (getMatrixMode() != matrixMode)
02596     {
02597         ++_NumIntegrableForceWithDifferentBasis;
02598         releaseParametricInfos();
02599     }
02600     else
02601     {
02602         --_NumIntegrableForceWithDifferentBasis;
02603     }
02604     CHECK_PS_INTEGRITY
02605 }
02606 
02607 
02609 CPSLocatedBindable *CPSLocated::unbind(uint index)
02610 {
02611     NL_PS_FUNC(CPSLocated_unbind)
02612     CHECK_PS_INTEGRITY
02613     nlassert(index < _LocatedBoundCont.size());
02614     CPSLocatedBindable *lb = _LocatedBoundCont[index];
02615     lb->setOwner(NULL);
02616     _LocatedBoundCont.erase(_LocatedBoundCont.begin() + index);
02617     return lb;
02618     CHECK_PS_INTEGRITY
02619 }
02620 
02622 bool CPSLocated::isBound(const CPSLocatedBindable *lb) const
02623 {
02624     NL_PS_FUNC(CPSLocated_isBound)
02625     CHECK_PS_INTEGRITY
02626     TLocatedBoundCont::const_iterator it = std::find(_LocatedBoundCont.begin(), _LocatedBoundCont.end(), lb);
02627     return it != _LocatedBoundCont.end();
02628 }
02629 
02631 uint CPSLocated::getIndexOf(const CPSLocatedBindable *lb) const
02632 {
02633     NL_PS_FUNC(CPSLocated_getIndexOf)
02634     CHECK_PS_INTEGRITY
02635     for(uint k = 0; k < _LocatedBoundCont.size(); ++k)
02636     {
02637         if (_LocatedBoundCont[k] == lb) return k;
02638     }
02639     nlassert(0);
02640     return 0;
02641 }
02642 
02643 
02644 
02646 // CPSLocatedBindable implementation //
02648 
02649 
02651 CPSLocatedBindable::CPSLocatedBindable() : _Owner(NULL), _ExternID(0), _LOD(PSLod1n2), _Active(true)
02652 {
02653     NL_PS_FUNC(CPSLocatedBindable_CPSLocatedBindable)
02654     _Owner = NULL;
02655 }
02656 
02658 void CPSLocatedBindable::setOwner(CPSLocated *psl)
02659 {
02660     NL_PS_FUNC(CPSLocatedBindable_setOwner)
02661     if (psl == _Owner) return;
02662     if (psl == NULL)
02663     {
02664         releaseAllRef();
02665         if (_Owner)
02666         {
02667             // empty this located bindable. Need to be empty if it must be rebound to another located.
02668             for (uint k = 0; k < _Owner->getSize(); ++k)
02669             {
02670                 deleteElement(0);
02671             }
02672         }
02673     }
02674     if (_Owner && _Owner->getOwner())
02675     {
02676         _Owner->getOwner()->releaseRefForUserSysCoordInfo(getUserMatrixUsageCount());
02677     }
02678     _Owner = psl;
02679     if (_Owner && _Owner->getOwner())
02680     {
02681         _Owner->getOwner()->addRefForUserSysCoordInfo(getUserMatrixUsageCount());
02682     }
02683 }
02684 
02686 void CPSLocatedBindable::finalize(void)
02687 {
02688     NL_PS_FUNC(CPSLocatedBindable_finalize)
02689     if (_Owner && _Owner->getOwner())
02690     {
02691         _Owner->getOwner()->releaseRefForUserSysCoordInfo(getUserMatrixUsageCount());
02692     }
02693 }
02694 
02696 CPSLocatedBindable::~CPSLocatedBindable()
02697 {
02698     NL_PS_FUNC(CPSLocatedBindable_CPSLocatedBindableDtor)
02699     if (_ExternID)
02700     {
02701         if (_Owner && _Owner->getOwner())
02702         {
02703             _Owner->getOwner()->unregisterLocatedBindableExternID(this);
02704         }
02705     }
02706 }
02707 
02709 void CPSLocatedBindable::notifyTargetRemoved(CPSLocated *ptr)
02710 {
02711     NL_PS_FUNC(CPSLocatedBindable_notifyTargetRemoved)
02712     ptr->unregisterDtorObserver(this);
02713 }
02714 
02716 void CPSLocatedBindable::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02717 {
02718     NL_PS_FUNC(CPSLocatedBindable_IStream )
02719     sint ver = f.serialVersion(4);
02720     f.serialPtr(_Owner);
02721     if (ver > 1) f.serialEnum(_LOD);
02722     if (ver > 2)
02723     {
02724         if (f.isReading() && !CParticleSystem::getSerializeIdentifierFlag())
02725         {
02726             // just skip the name
02727             sint32 len;
02728             f.serial(len);
02729             f.seek(len, NLMISC::IStream::current);
02730         }
02731         else
02732         {
02733             f.serial(_Name);
02734         }
02735     }
02736     if (ver > 3)
02737     {
02738         if (f.isReading())
02739         {
02740             uint32 id;
02741             f.serial(id);
02742             setExternID(id);
02743         }
02744         else
02745         {
02746             f.serial(_ExternID);
02747         }
02748     }
02749 
02750 }
02751 
02753 void CPSLocatedBindable::displayIcon2d(const CVector tab[], uint nbSegs, float scale)
02754 {
02755     NL_PS_FUNC(CPSLocatedBindable_displayIcon2d)
02756     uint32 size = _Owner->getSize();
02757     if (!size) return;
02758     setupDriverModelMatrix();
02759 
02760     const CVector I = computeI();
02761     const CVector K = computeK();
02762 
02763     static std::vector<NLMISC::CLine> lines;
02764 
02765     lines.clear();
02766 
02767     // ugly slow code, but not for runtime
02768     for (uint  k = 0; k < size; ++k)
02769     {
02770         // center of the current particle
02771         const CVector p = _Owner->getPos()[k];
02772 
02773 
02774 
02775         for (uint l = 0; l < nbSegs; ++l)
02776         {
02777             NLMISC::CLine li;
02778             li.V0 = p + scale * (tab[l << 1].x * I + tab[l << 1].y * K);
02779             li.V1 = p + scale * (tab[(l << 1) + 1].x * I + tab[(l << 1) + 1].y * K);
02780             lines.push_back(li);
02781         }
02782 
02783         CMaterial mat;
02784 
02785         mat.setBlendFunc(CMaterial::one, CMaterial::one);
02786         mat.setZWrite(false);
02787         mat.setLighting(false);
02788         mat.setBlend(true);
02789         mat.setZFunc(CMaterial::less);
02790 
02791 
02792 
02793         CPSLocated *loc;
02794         uint32 index;
02795         CPSLocatedBindable *lb;
02796         _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
02797 
02798         mat.setColor((lb == NULL || this == lb) && loc == _Owner && index == k  ? CRGBA::Red : CRGBA(127, 127, 127));
02799 
02800 
02801         CDRU::drawLinesUnlit(lines, mat, *getDriver() );
02802     }
02803 
02804 }
02805 
02807 CFontManager *CPSLocatedBindable::getFontManager(void)
02808 {
02809     NL_PS_FUNC(CPSLocatedBindable_getFontManager)
02810     nlassert(_Owner);
02811     return _Owner->getFontManager();
02812 }
02813 
02816 const CFontManager *CPSLocatedBindable::getFontManager(void) const
02817 {
02818     NL_PS_FUNC(CPSLocatedBindable_getFontManager)
02819     nlassert(_Owner);
02820     return _Owner->getFontManager();
02821 }
02822 
02823 
02825 // Shortcut to get the matrix of the system
02826  const NLMISC::CMatrix &CPSLocatedBindable::getSysMat(void) const
02827 {
02828     NL_PS_FUNC( CPSLocatedBindable_getSysMat)
02829     nlassert(_Owner);
02830     return _Owner->getOwner()->getSysMat();
02831 }
02832 
02835 const NLMISC::CMatrix &CPSLocatedBindable::getInvertedSysMat(void) const
02836 {
02837     NL_PS_FUNC(CPSLocatedBindable_getInvertedSysMat)
02838     nlassert(_Owner);
02839         return _Owner->getOwner()->getInvertedSysMat();
02840 
02841 }
02842 
02845 const NLMISC::CMatrix &CPSLocatedBindable::getViewMat(void) const
02846 {
02847     NL_PS_FUNC(CPSLocatedBindable_getViewMat)
02848     nlassert(_Owner);
02849     return _Owner->getOwner()->getViewMat();
02850 }
02851 
02852 
02855 const NLMISC::CMatrix &CPSLocatedBindable::getInvertedViewMat(void) const
02856 {
02857     NL_PS_FUNC(CPSLocatedBindable_getInvertedViewMat)
02858     nlassert(_Owner);
02859     return _Owner->getOwner()->getInvertedViewMat();
02860 }
02861 
02864 void CPSLocatedBindable::setupDriverModelMatrix(void)
02865 {
02866     NL_PS_FUNC(CPSLocatedBindable_setupDriverModelMatrix)
02867     nlassert(_Owner);
02868     _Owner->setupDriverModelMatrix();
02869 }
02870 
02872 void    CPSLocatedBindable::setExternID(uint32 id)
02873 {
02874     NL_PS_FUNC(CPSLocatedBindable_setExternID)
02875     if (id == _ExternID) return;
02876     CParticleSystem *ps = NULL;
02877     if (_Owner && _Owner->getOwner())
02878     {
02879         ps = _Owner->getOwner();
02880     }
02881     if (ps)
02882     {
02883         ps->unregisterLocatedBindableExternID(this);
02884         _ExternID = 0;
02885     }
02886     if (id != 0)
02887     {
02888         if (ps) ps->registerLocatedBindableExternID(id, this);
02889         _ExternID = id;
02890     }
02891 }
02892 
02894 void CPSLocatedBindable::releaseAllRef()
02895 {
02896     NL_PS_FUNC(CPSLocatedBindable_releaseAllRef)
02897 }
02898 
02899 
02900 
02901 
02902 
02904 // CPSTargetLocatedBindable implementation //
02906 
02908 void CPSTargetLocatedBindable::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02909 {
02910     NL_PS_FUNC(CPSTargetLocatedBindable_serial)
02911     (void)f.serialVersion(1);
02912     f.serialPtr(_Owner);
02913     f.serial(_Name);
02914     if (f.isReading())
02915     {
02916         // delete previous attached bindables...
02917         for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
02918         {
02919             delete (*it);
02920         }
02921         _Targets.clear();
02922     }
02923     f.serialContPolyPtr(_Targets);
02924 }
02925 
02926 
02928 void CPSTargetLocatedBindable::attachTarget(CPSLocated *ptr)
02929 {
02930     NL_PS_FUNC(CPSTargetLocatedBindable_attachTarget)
02931 
02932     // a target can't be shared between different particle systems
02933     #ifdef NL_DEBUG
02934     if (_Owner)
02935     {
02936         nlassert(_Owner->getOwner() == ptr->getOwner());
02937     }
02938     #endif
02939 
02940     // see whether this target has not been registered before
02941     nlassert(std::find(_Targets.begin(), _Targets.end(), ptr) == _Targets.end());
02942     _Targets.push_back(ptr);
02943 
02944     // we register us to be notified when the target disappear
02945     ptr->registerDtorObserver(this);
02946 }
02947 
02948 
02950 void CPSTargetLocatedBindable::notifyTargetRemoved(CPSLocated *ptr)
02951 {
02952     NL_PS_FUNC(CPSTargetLocatedBindable_notifyTargetRemoved)
02953     TTargetCont::iterator it = std::find(_Targets.begin(), _Targets.end(), ptr);
02954     nlassert(it != _Targets.end());
02955     releaseTargetRsc(*it);
02956     _Targets.erase(it);
02957 
02958     CPSLocatedBindable::notifyTargetRemoved(ptr);
02959 }
02960 
02961 
02962 
02963 // dtor
02964 
02966 void CPSTargetLocatedBindable::finalize(void)
02967 {
02968     NL_PS_FUNC(CPSTargetLocatedBindable_finalize)
02972     for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
02973     {
02974         releaseTargetRsc(*it);
02975     }
02976     CPSLocatedBindable::finalize();
02977 }
02978 
02980 CPSTargetLocatedBindable::~CPSTargetLocatedBindable()
02981 {
02982     NL_PS_FUNC(CPSTargetLocatedBindable_CPSTargetLocatedBindable)
02983     // we unregister to all the targets
02984     for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
02985     {
02986         (*it)->unregisterDtorObserver(this);
02987     }
02988 }
02989 
02991 void CPSTargetLocatedBindable::releaseRefTo(const CParticleSystemProcess *other)
02992 {
02993     NL_PS_FUNC(CPSTargetLocatedBindable_releaseRefTo)
02994     TTargetCont::iterator it = std::find(_Targets.begin(), _Targets.end(), other);
02995     if (it == _Targets.end()) return;
02996     releaseTargetRsc(*it);
02997     (*it)->unregisterDtorObserver(this);
02998     _Targets.erase(it);
02999     nlassert(std::find(_Targets.begin(), _Targets.end(), other) == _Targets.end());
03000 }
03001 
03003 void CPSTargetLocatedBindable::releaseAllRef()
03004 {
03005     NL_PS_FUNC(CPSTargetLocatedBindable_releaseAllRef)
03006     for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
03007     {
03008         releaseTargetRsc(*it);
03009         (*it)->unregisterDtorObserver(this);
03010     }
03011     _Targets.clear();
03012     CPSLocatedBindable::releaseAllRef();
03013 }
03014 
03016 uint CPSLocated::getUserMatrixUsageCount() const
03017 {
03018     NL_PS_FUNC(CPSLocated_getUserMatrixUsageCount)
03019     uint count = 0;
03020     for(TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
03021     {
03022         count += (*it)->getUserMatrixUsageCount();
03023     }
03024     return count + CParticleSystemProcess::getUserMatrixUsageCount();
03025 }
03026 
03028 void CPSLocated::enumTexs(std::vector<NLMISC::CSmartPtr<ITexture> > &dest, IDriver &drv)
03029 {
03030     NL_PS_FUNC(CPSLocated_enumTexs)
03031     for(TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
03032     {
03033         (*it)->enumTexs(dest, drv);
03034     }
03035 }
03036 
03038 void CPSLocated::setZBias(float value)
03039 {
03040     NL_PS_FUNC(CPSLocated_setZBias)
03041     for(TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
03042     {
03043         (*it)->setZBias(value);
03044     }
03045 }
03046 
03048 void CPSLocated::computeCollisions(uint firstInstanceIndex, const NLMISC::CVector *posBefore, const NLMISC::CVector *posAfter)
03049 {
03050     NL_PS_FUNC(CPSLocated_computeCollisions)
03051     for(TDtorObserversVect::iterator it = _DtorObserversVect.begin(); it != _DtorObserversVect.end(); ++it)
03052     {
03053         if ((*it)->getType() == PSZone)
03054         {
03055             static_cast<CPSZone *>(*it)->computeCollisions(*this, firstInstanceIndex, posBefore, posAfter);
03056         }
03057     }
03058 }
03059 
03061 void CPSLocated::computeSpawns(uint firstInstanceIndex, bool includeEmitOnce)
03062 {
03063     NL_PS_FUNC(CPSLocated_computeSpawns)
03064     nlassert(CParticleSystem::InsideSimLoop);
03065     for(TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
03066     {
03067         if (!(*it)->isActive()) continue;
03068         if ((*it)->getType() == PSEmitter)
03069         {
03070             CPSEmitter *emit = static_cast<CPSEmitter *>(*it);
03071             emit->updateEmitTrigger();
03072             switch(emit->getEmissionType())
03073             {
03074                 case CPSEmitter::regular:
03075                     emit->computeSpawns(firstInstanceIndex);
03076                 break;
03077                 case CPSEmitter::once:
03078                     // if we're at first frame, then do emit for each emitter
03079                     nlassert(_Owner);
03080                     if (_Owner->getSystemDate() == 0.f || includeEmitOnce)
03081                     {
03082                         // if first pass, then do the emit a single time
03083                         // if firstInstanceIndex != 0 then we're dealing with newly created particles, so do the spawn too
03084                         emit->doEmitOnce(firstInstanceIndex);
03085                     }
03086                 break;
03087                 default:
03088                     break;
03089             }
03090         }
03091     }
03092 }
03093 
03095 void CPSLocated::computeForces()
03096 {
03097     NL_PS_FUNC(CPSLocated_computeForces)
03098     nlassert(CParticleSystem::InsideSimLoop);
03099     for(TDtorObserversVect::iterator it = _DtorObserversVect.begin(); it != _DtorObserversVect.end(); ++it)
03100     {
03101         if ((*it)->getType() == PSForce)
03102         {
03103             CPSForce *force = static_cast<CPSForce *>(*it);
03104             force->computeForces(*this);
03105         }
03106     }
03107 }
03108 
03110 void CPSCollisionInfo::update(const CPSCollisionInfo &other)
03111 {
03112     NL_PS_FUNC(CPSCollisionInfo_update)
03113     if (Dist == -1)
03114     {
03115         // link collision in the global list of active collisions
03116         Next = CPSLocated::_FirstCollision;
03117         CPSLocated::_FirstCollision = this;
03118         Dist = other.Dist;
03119         NewPos = other.NewPos;
03120         NewSpeed = other.NewSpeed;
03121         CollisionZone = other.CollisionZone;
03122     }
03123     else if (other.Dist < Dist) // is the new collision better (e.g it happens sooner) ?
03124     {
03125         Dist = other.Dist;
03126         NewPos = other.NewPos;
03127         NewSpeed = other.NewSpeed;
03128         CollisionZone = other.CollisionZone;
03129     }
03130 }
03131 
03133 void CPSLocated::checkLife() const
03134 {
03135     NL_PS_FUNC(CPSLocated_checkLife)
03136     if (!getLastForever())
03137     {
03138         for(uint k = 0; k < getSize(); ++k)
03139         {
03140             nlassert(getTime()[k] >= 0.f);
03141             nlassert(getTime()[k] <= 1.f);
03142         }
03143     }
03144 }
03145 
03147 void CPSLocated::onShow(bool shown)
03148 {
03149     for(TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
03150     {
03151         (*it)->onShow(shown);
03152     }
03153 }
03154 
03155 
03156 } // NL3D

Generated on Thu Jan 7 08:26:29 2010 for NeL by  doxygen 1.6.1