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

ps_located.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "std3d.h"
00027 
00028 
00029 
00030 #include <algorithm>
00031 #include "nel/misc/aabbox.h"
00032 #include "nel/misc/matrix.h"
00033 #include "3d/ps_util.h"
00034 #include "3d/particle_system.h"
00035 #include "3d/ps_zone.h"
00036 #include "3d/driver.h"
00037 #include "3d/material.h"
00038 #include "3d/dru.h"
00039 #include "3d/ps_located.h"
00040 #include "3d/ps_particle.h"
00041 #include "3d/ps_force.h"
00042 #include "3d/ps_emitter.h"
00043 #include "3d/ps_misc.h"
00044 
00045 #include "nel/misc/line.h"
00046 #include "nel/misc/system_info.h"
00047 #include "nel/misc/common.h"
00048 
00049 namespace NL3D {
00050 
00051 
00052 
00053 
00057         CPSLocated::CPSLocated() : _MaxNumFaces(0),
00058                                                            _Name(std::string("located")),
00059                                                            _NbFramesToSkip(0),
00060                                                            _MaxSize(DefaultMaxLocatedInstance),
00061                                                            _Size(0),
00062                                                            _LastForever(true),
00063                                                            _CollisionInfo(NULL),
00064                                                            _CollisionInfoNbRef(0),
00065                                                            _InitialLife(1.f),
00066                                                            _LifeScheme(NULL),
00067                                                            _InitialMass(1.f),
00068                                                            _MassScheme(NULL),
00069                                                            _UpdateLock(false),
00070                                                            _LODDegradation(false),
00071                                                            _NonIntegrableForceNbRefs(0),
00072                                                            _NumIntegrableForceWithDifferentBasis(0),
00073                                                            _TriggerOnDeath(false),
00074                                                            _TriggerID((uint32) 'NONE'),
00075                                                            _ParametricMotion(false)                                                        
00076 {               
00077 }
00078 
00079 
00080 
00082 void CPSLocated::releaseRefTo(const CParticleSystemProcess *other)
00083 {
00084         // located bindables
00085         {       
00086                 for(TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00087                 {
00088                         (*it)->releaseRefTo(other);
00089                 }
00090         }
00091         // dtor observers
00092         {       
00093                                 
00094                 for(TDtorObserversVect::iterator it = _DtorObserversVect.begin(); it != _DtorObserversVect.end(); ++it)
00095                 {       
00096                         if ((*it)->getOwner() == other)
00097                         {                                                                       
00098                                 CPSLocatedBindable *refMaker = *it;                             
00099                                 refMaker->notifyTargetRemoved(this);
00100                                 break;
00101                         }
00102                 }
00103         }
00104 }
00105 
00107 void CPSLocated::releaseAllRef()
00108 {
00109          // located bindables
00110         {       
00111                 for(TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00112                 {
00113                         (*it)->releaseAllRef();
00114                 }
00115         }
00116 
00117         // we must do a copy, because the subsequent call can modify this vector
00118         TDtorObserversVect copyVect(_DtorObserversVect.begin(), _DtorObserversVect.end());
00119         // call all the dtor observers
00120         for (TDtorObserversVect::iterator it = copyVect.begin(); it != copyVect.end(); ++it)
00121         {
00122                 (*it)->notifyTargetRemoved(this);
00123         }
00124         _DtorObserversVect.clear();     
00125         
00126         nlassert(_CollisionInfoNbRef == 0); //If this is not = 0, then someone didnt call releaseCollisionInfo
00127                                                                                  // If this happen, you can register with the registerDTorObserver
00128                                                                                  // (observer pattern)
00129                                                                                  // and override notifyTargetRemove to call releaseCollisionInfo
00130         nlassert(_IntegrableForces.size() == 0);
00131         nlassert(_NonIntegrableForceNbRefs == 0);
00132         nlassert(!_CollisionInfo);
00133 }
00134 
00135 
00137 void CPSLocated::notifyMotionTypeChanged(void)
00138 {
00139         for (TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00140         {
00141                 (*it)->motionTypeChanged(_ParametricMotion);
00142         }
00143 }
00144 
00145 
00147 void CPSLocated::integrateSingle(float startDate, float deltaT, uint numStep,                                                           
00148                                                                 uint32 indexInLocated,
00149                                                                 NLMISC::CVector *destPos,                                               
00150                                                                 uint stride /*= sizeof(NLMISC::CVector)*/)
00151 {
00152         nlassert(supportParametricMotion() && _ParametricMotion);
00153         if (_IntegrableForces.size() != 0)
00154         {
00155                 bool accumulate = false;
00156                 for (TForceVect::iterator it = _IntegrableForces.begin(); it != _IntegrableForces.end(); ++it)
00157                 {
00158                         nlassert((*it)->isIntegrable());
00159                         (*it)->integrateSingle(startDate, deltaT, numStep, this, indexInLocated, destPos, accumulate, stride);
00160                         accumulate = true;
00161                 }
00162         }
00163         else // no forces applied, just deduce position from date, initial pos and speed
00164         {
00165                         #ifdef NL_DEBUG
00166                                 NLMISC::CVector *endPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride * numStep);
00167                         #endif
00168                         const CPSLocated::CParametricInfo &pi = _PInfo[indexInLocated];
00169                         destPos = FillBufUsingSubdiv(pi.Pos, pi.Date, startDate, deltaT, numStep, destPos, stride);
00170                         if (numStep != 0)
00171                         {                       
00172                                 float currDate = startDate - pi.Date;
00173                                 nlassert(currDate >= 0);
00174                                 do
00175                                 {
00176                                         #ifdef NL_DEBUG
00177                                                 nlassert(destPos < endPos);
00178                                         #endif                                  
00179                                         destPos->x = pi.Pos.x + currDate * pi.Speed.x;
00180                                         destPos->y = pi.Pos.y + currDate * pi.Speed.y;
00181                                         destPos->z = pi.Pos.z + currDate * pi.Speed.z;
00182                                         currDate += deltaT;
00183                                         destPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride);
00184                                 }
00185                                 while (--numStep);
00186                         }       
00187         }
00188 }
00189 
00190 void CPSLocated::performParametricMotion(TAnimationTime date, TAnimationTime ellapsedTime, TAnimationTime realEllapsedTime)
00191 {
00192         if (!_Size) return;     
00193         nlassert(supportParametricMotion() && _ParametricMotion);
00194 
00195         if (_IntegrableForces.size() != 0)
00196         {
00197                 bool accumulate = false;
00198                 for (TForceVect::iterator it = _IntegrableForces.begin(); it != _IntegrableForces.end(); ++it)
00199                 {
00200                         nlassert((*it)->isIntegrable());
00201                         (*it)->integrate(date, this, 0, _Size, &_Pos[0], &_Speed[0], accumulate);
00202                         accumulate = true;
00203                 }
00204         }
00205         else
00206         {
00207                 CPSLocated::TPSAttribParametricInfo::const_iterator it = _PInfo.begin(),
00208                                                                                         endIt = _PInfo.end();
00209                 TPSAttribVector::iterator posIt = _Pos.begin();
00210                 float deltaT;
00211                 do
00212                 {
00213                         deltaT = date - it->Date;
00214                         posIt->x = it->Pos.x + deltaT * it->Speed.x;
00215                         posIt->y = it->Pos.y + deltaT * it->Speed.y;
00216                         posIt->z = it->Pos.z + deltaT * it->Speed.z;
00217                         ++posIt;
00218                         ++it;
00219                 }
00220                 while (it != endIt);
00221         }
00222         //step(PSEmit, ellapsedTime, realEllapsedTime); 
00223 }
00224 
00226 void  CPSLocated::allocateParametricInfos(void)
00227 {
00228         if (_ParametricMotion) return;
00229         nlassert(supportParametricMotion());
00230         nlassert(_Owner);
00231         const float date = _Owner->getSystemDate();
00232         _PInfo.resize(_MaxSize);
00233         // copy back infos from current position and speeds
00234         TPSAttribVector::const_iterator posIt = _Pos.begin(), endPosIt = _Pos.end();
00235         TPSAttribVector::const_iterator speedIt = _Speed.begin();
00236         while (posIt != endPosIt)
00237         {
00238                 _PInfo.insert( CParametricInfo(*posIt, *speedIt, date) );
00239                 ++posIt;
00240         }
00241         _ParametricMotion = true;
00242         notifyMotionTypeChanged();
00243 }
00244 
00246 void  CPSLocated::releaseParametricInfos(void)
00247 {
00248         if (!_ParametricMotion) return;
00249         NLMISC::contReset(_PInfo);
00250         _ParametricMotion = false;
00251         notifyMotionTypeChanged();
00252 }
00253 
00254 
00256 bool      CPSLocated::supportParametricMotion(void) const
00257 {
00258         return _NonIntegrableForceNbRefs == 0 && _NumIntegrableForceWithDifferentBasis == 0;
00259 }
00260 
00264 void    CPSLocated::enableParametricMotion(bool enable /*= true*/)
00265 {
00266         nlassert(supportParametricMotion());
00267         if (enable)
00268         {
00269                 allocateParametricInfos();
00270         }
00271         else
00272         {
00273                 releaseParametricInfos();
00274         }
00275 }
00276 
00277 
00278 void CPSLocated::setSystemBasis(bool sysBasis)
00279 {                       
00280         if (sysBasis != isInSystemBasis())
00281         {               
00282                 for (TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00283                 {
00284                         (*it)->basisChanged(sysBasis);
00285                 }
00286 
00287                 CParticleSystemProcess::setSystemBasis(sysBasis);
00288 
00289                 for (TForceVect::iterator fIt = _IntegrableForces.begin(); fIt != _IntegrableForces.end(); ++fIt)
00290                 {                       
00291                         integrableForceBasisChanged( (*fIt)->getOwner()->isInSystemBasis() );
00292                 }                               
00293         }                       
00294 }
00295 
00296 void CPSLocated::notifyMaxNumFacesChanged(void)
00297 {
00298         if (!_Owner) return;
00299         
00300         // we examine wether we have particle attached to us, and ask for the max number of faces they may want
00301         _MaxNumFaces  = 0;
00302         for (TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00303         {
00304                 if ((*it)->getType() == PSParticle)
00305                 {
00306                         uint maxNumFaces = ((CPSParticle *) (*it))->getMaxNumFaces();
00308                         _MaxNumFaces += maxNumFaces;
00309                 }
00310         }       
00311 }
00312 
00313 
00314 uint CPSLocated::querryMaxWantedNumFaces(void)
00315 {
00316         return _MaxNumFaces;
00317 }
00318 
00319 
00321 bool CPSLocated::hasParticles(void) const
00322 {
00323         for (TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00324         {
00325                 if ((*it)->getType() == PSParticle && (*it)->hasParticles()) return true;
00326         }
00327         return false;
00328 }
00329 
00331 bool CPSLocated::hasEmitters(void) const
00332 {
00333         for (TLocatedBoundCont::const_iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00334         {
00335                 if ((*it)->getType() == PSEmitter && (*it)->hasEmitters()) return true;
00336         }
00337         return false;
00338 }
00339 
00340 
00341 void CPSLocated::getLODVect(NLMISC::CVector &v, float &offset, bool systemBasis)
00342 {
00343         nlassert(_Owner);
00344         _Owner->getLODVect(v, offset, systemBasis);
00345 }
00346 
00347 
00348 
00349 float CPSLocated::getUserParam(uint numParam) const
00350 {
00351         nlassert(_Owner);
00352         return _Owner->getUserParam(numParam);
00353 }
00354 
00355 CScene *CPSLocated::getScene(void)
00356 {
00357         nlassert(_Owner);
00358         return _Owner->getScene();
00359 }
00360 
00361 
00362 void CPSLocated::incrementNbDrawnParticles(uint num)
00363 {
00364         CParticleSystem::NbParticlesDrawn += num; // for benchmark purpose      
00365 }
00366 
00367 void CPSLocated::setInitialLife(TAnimationTime lifeTime)
00368 {
00369         _LastForever = false;
00370         _InitialLife = lifeTime;
00371         delete _LifeScheme;
00372         _LifeScheme = NULL;     
00373 
00377         for (uint k = 0; k < _Size; ++k)
00378         {
00379                 _Time[k] = 0.f;
00380         }
00381 
00382 }
00383 void CPSLocated::setLifeScheme(CPSAttribMaker<float> *scheme)
00384 {
00385         nlassert(scheme);
00386         nlassert(!scheme->hasMemory()); // scheme with memory is invalid there !!
00387         _LastForever = false;
00388         delete _LifeScheme;
00389         _LifeScheme = scheme;
00390 }
00391 void CPSLocated::setInitialMass(float mass)
00392 {
00393         _InitialMass = mass;
00394         delete _MassScheme;
00395         _MassScheme = NULL;     
00396 }
00397 void CPSLocated::setMassScheme(CPSAttribMaker<float> *scheme)
00398 {
00399         nlassert(scheme);
00400         nlassert(!scheme->hasMemory()); // scheme with memory is invalid there !!
00401         delete _MassScheme;
00402         _MassScheme = scheme;   
00403 }
00404         
00405 
00406 
00408 const NLMISC::CMatrix &CPSLocated::getConversionMatrix(const CPSLocated *A, const CPSLocated *B)
00409 {
00410         nlassert(A->_Owner == B->_Owner); // conversion must be made between entity of the same system
00411         if (A->_SystemBasisEnabled == B->_SystemBasisEnabled)
00412         {
00413                 return NLMISC::CMatrix::Identity;
00414         }
00415         else
00416         {
00417                 if (B->_SystemBasisEnabled)
00418                 {
00419                         return B->_Owner->getSysMat();
00420                 }
00421                 else
00422                 {
00423                         return A->_Owner->getInvertedSysMat();
00424                 }
00425         }
00426 }
00427 
00428 
00429 NLMISC::CVector CPSLocated::computeI(void) const 
00430 {
00431         if (!_SystemBasisEnabled)
00432         {
00433                 return _Owner->getInvertedViewMat().getI();
00434         }
00435         else
00436         {
00437                 // we must express the I vector in the system basis, so we need to multiply it by the inverted matrix of the system
00438                 return _Owner->getInvertedSysMat().mulVector(_Owner->getInvertedViewMat().getI());
00439         }
00440 }
00441 
00442 
00443 NLMISC::CVector CPSLocated::computeJ(void) const 
00444 {
00445         if (!_SystemBasisEnabled)
00446         {
00447                 return _Owner->getInvertedViewMat().getJ();
00448         }
00449         else
00450         {
00451                 // we must express the J vector in the system basis, so we need to multiply it by the inverted matrix of the system
00452                 return _Owner->getInvertedSysMat().mulVector(_Owner->getInvertedViewMat().getJ());
00453         }
00454 }
00455 
00456 
00457 
00458 NLMISC::CVector CPSLocated::computeK(void) const
00459 {
00460         if (!_SystemBasisEnabled)
00461         {
00462                 return _Owner->getInvertedViewMat().getK();
00463         }
00464         else
00465         {
00466                 // we must express the K vector in the system basis, so we need to multiply it by the inverted matrix of the system
00467                 return _Owner->getInvertedSysMat().mulVector(_Owner->getInvertedViewMat().getK());
00468         }
00469 }
00470 
00471 
00472 
00473 IDriver *CPSLocated::getDriver() const 
00474 { 
00475         nlassert(_Owner);
00476         nlassert (_Owner->getDriver() ); // you haven't called setDriver on the system
00477         return _Owner->getDriver();
00478 }
00479 
00481 
00482 CPSLocated::~CPSLocated()
00483 {
00484         // we must do a copy, because the subsequent call can modify this vector
00485         TDtorObserversVect copyVect(_DtorObserversVect.begin(), _DtorObserversVect.end());
00486         // call all the dtor observers
00487         for (TDtorObserversVect::iterator it = copyVect.begin(); it != copyVect.end(); ++it)
00488         {
00489                 (*it)->notifyTargetRemoved(this);
00490         }
00491 
00492         nlassert(_CollisionInfoNbRef == 0); //If this is not = 0, then someone didnt call releaseCollisionInfo
00493                                                                                  // If this happen, you can register with the registerDTorObserver
00494                                                                                  // (observer pattern)
00495                                                                                  // and override notifyTargetRemove to call releaseCollisionInfo
00496         nlassert(_IntegrableForces.size() == 0);
00497         nlassert(_NonIntegrableForceNbRefs == 0);
00498         nlassert(!_CollisionInfo);
00499 
00500         // delete all bindable
00501 
00502         for (TLocatedBoundCont::iterator it2 = _LocatedBoundCont.begin(); it2 != _LocatedBoundCont.end(); ++it2)
00503         {                                       
00504                 (*it2)->finalize();
00505                 delete *it2;            
00506         } 
00507 
00508 
00509         delete _LifeScheme;
00510         delete _MassScheme;
00511 }
00512 
00513 
00514 
00518 void CPSLocated::bind(CPSLocatedBindable *lb)
00519 {
00520         nlassert(std::find(_LocatedBoundCont.begin(), _LocatedBoundCont.end(), lb) == _LocatedBoundCont.end()); 
00521         TLocatedBoundCont::iterator it = _LocatedBoundCont.begin();
00522         while (it != _LocatedBoundCont.end() && **it < *lb) // the "<" operator sort them correctly
00523         {
00524                 ++it;
00525         }
00526 
00527         _LocatedBoundCont.insert(it, lb);
00528         lb->setOwner(this);
00529         lb->resize(_MaxSize);
00530 
00531         // any located bindable that is bound to us should have no element in it for now !!
00532         // we resize it anyway...
00533 
00534         uint32 initialSize  = _Size;
00535         for (uint k = 0; k < initialSize; ++k)
00536         {
00537                 _Size = k;
00538                 lb->newElement(NULL, 0);
00539         }
00540         _Size = initialSize;
00541 
00542 
00543         if (_ParametricMotion) lb->motionTypeChanged(true);
00544 
00546         notifyMaxNumFacesChanged();
00547 }
00548 
00549 
00550 
00551 void CPSLocated::remove(const CPSLocatedBindable *p)
00552 {
00553         TLocatedBoundCont::iterator it = std::find(_LocatedBoundCont.begin(), _LocatedBoundCont.end(), p);
00554         nlassert(it != _LocatedBoundCont.end());        
00555         (*it)->finalize();
00556         delete *it;
00557         _LocatedBoundCont.erase(it);
00558 }
00559 
00560 
00561 void CPSLocated::registerDtorObserver(CPSLocatedBindable *anObserver)
00562 {
00563         // check wether the observer wasn't registered twice
00564         nlassert(std::find(_DtorObserversVect.begin(), _DtorObserversVect.end(), anObserver) == _DtorObserversVect.end());
00565         _DtorObserversVect.push_back(anObserver);
00566 }
00567 
00568 void CPSLocated::unregisterDtorObserver(CPSLocatedBindable *anObserver)
00569 {
00570         // check that it was registered
00571         TDtorObserversVect::iterator it = std::find(_DtorObserversVect.begin(), _DtorObserversVect.end(), anObserver);
00572         nlassert(it != _DtorObserversVect.end());
00573         _DtorObserversVect.erase(it);
00574 }
00575 
00576 
00577 
00578 
00579 
00584 sint32 CPSLocated::newElement(const CVector &pos, const CVector &speed, CPSLocated *emitter, uint32 indexInEmitter, bool basisConversionForSpeed, TAnimationTime ellapsedTime /* = 0.f */)
00585 {       
00586         if (_UpdateLock)
00587         {
00588                 postNewElement(pos, speed);
00589                 return -1;
00590         }
00591         
00592 
00593         if (_CollisionInfo)
00594         {
00595                 _CollisionInfo->insert();
00596         }
00597 
00598         sint32 creationIndex;
00599 
00600         // get the convertion matrix  from the emitter basis to the emittee basis
00601         // if the emitter is null, we assume that the coordinate are given in the chosen basis for this particle type
00602 
00603         
00604         
00605         if (_MaxSize == _Size) return -1;
00606 
00607         // 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.
00608         // 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".
00609         // For now, we manage the local to world case. The world to local is possible, but not very useful
00610         const CMatrix &convMat = emitter ? CPSLocated::getConversionMatrix(this, emitter) 
00611                                                                          :  CMatrix::Identity;
00612         if (!_SystemBasisEnabled && emitter && emitter->_SystemBasisEnabled)
00613         {
00614                 // Interpolate linearly position of the system based on the ellapsed time.
00615                 // The system keep track the ellapsed time passed in the call to step(), so it can compute the right position for us
00616                 #ifdef NL_DEBUG
00617                         nlassert(_Owner);
00618                 #endif
00619                 CVector sysPosDelta;
00620                 _Owner->interpolatePosDelta(sysPosDelta, ellapsedTime);
00621                 creationIndex  =_Pos.insert(convMat * pos + sysPosDelta);
00622         }
00623         else
00624         {
00625                 creationIndex  =_Pos.insert(convMat * pos);
00626         }       
00627         nlassert(creationIndex != -1); // all attributs must contains the same number of elements
00628         
00629         _Speed.insert(basisConversionForSpeed ? convMat.mulVector(speed) : speed);
00630         
00631 
00632                         
00633         _InvMass.insert(1.f / ((_MassScheme && emitter) ? _MassScheme->get(emitter, indexInEmitter) : _InitialMass ) );
00634         _Time.insert(0.0f);     
00635         const float lifeTime = (_LifeScheme && emitter) ?  _LifeScheme->get(emitter, indexInEmitter) : _InitialLife ;
00636         _TimeIncrement.insert( lifeTime ? 1.f / lifeTime : 10E6f);
00637 
00638         // test wether parametric motion is used, and generate the infos that are needed then
00639         if (_ParametricMotion)
00640         {
00641                 _PInfo.insert( CParametricInfo(_Pos[creationIndex], _Speed[creationIndex], _Owner->getSystemDate() ) );
00642         }
00643 
00644 
00646         // generate datas for all bound objects  //
00648         _UpdateLock = true;     
00649 
00650         
00651         for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00652         {
00653                 (*it)->newElement(emitter, indexInEmitter);
00654         }
00655 
00656         
00657         _UpdateLock = false;    
00658         ++_Size;        // if this is modified, you must also modify the getNewElementIndex in this class
00659                                 // because that method give the index of the element being created for overrider of the newElement method
00660                                 // of the CPSLocatedClass (which is called just above)
00661 
00662         
00663 
00664         return creationIndex;
00665 }
00666 
00667 void CPSLocated::postNewElement(const CVector &pos, const CVector &speed)
00668 {
00669         _RequestStack.push(CPostNewElementRequestInfo(pos, speed));
00670 }
00671 
00672 
00673                 
00674 static inline uint32 IDToLittleEndian(uint32 input)
00675 {
00676         #ifdef NL_LITTLE_ENDIAN
00677                 return input;
00678         #else
00679                 return ((input & (0xff<<24))>>24)
00680                                 || ((input & (0xff<<16))>>8)
00681                                 || ((input & (0xff<<8))<<8)
00682                                 || ((input & 0xff)<<24);
00683         #endif
00684 }
00685 
00690 void CPSLocated::deleteElement(uint32 index)
00691 {
00692         nlassert(index < _Size);
00693         
00694         // delete all bindable before : they may need our coordinate
00695         // to perform a destruction task
00696         
00697         _UpdateLock = true;
00698         
00699 
00700         for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00701         {
00702                 (*it)->deleteElement(index);
00703         }       
00704 
00705         
00706         _UpdateLock = false;    
00707 
00708         // remove common located's attributes
00709 
00710         _InvMass.remove(index);
00711         _Pos.remove(index);
00712         _Speed.remove(index);
00713         _Time.remove(index);
00714         _TimeIncrement.remove(index);
00715 
00716         if (_CollisionInfo)
00717         {
00718                 _CollisionInfo->remove(index);
00719         }
00720 
00721         if (_ParametricMotion)
00722         {
00723                 _PInfo.remove(index);
00724         }
00725 
00726         --_Size;
00727 
00728         if (_TriggerOnDeath)
00729         {
00730                 const uint32 id = IDToLittleEndian(_TriggerID);
00731                 nlassert(_Owner);               
00732                 uint numLb  = _Owner->getNumLocatedBindableByExternID(id);              
00733                 for (uint k = 0; k < numLb; ++k)
00734                 {
00735                         CPSLocatedBindable *lb = _Owner->getLocatedBindableByExternID(id, k);           
00736                         if (lb->getType() == PSEmitter)
00737                         {
00738                                 CPSEmitter *e = NLMISC::safe_cast<CPSEmitter *>(lb);
00739                                 nlassert(e->getOwner());
00740                                 uint nbInstances = e->getOwner()->getSize();                            
00741                                 for (uint l = 0; l < nbInstances; ++l)
00742                                 {
00743                                         e->singleEmit(l, 1);
00744                                 }
00745                         }
00746                 }
00747         }
00748 }
00749 
00750 
00752 
00753 void CPSLocated::resize(uint32 newSize)
00754 {
00755         nlassert(newSize < (1 << 16));
00756         if (newSize < _Size)
00757         {
00758                 for (uint32 k = _Size - 1; k >= newSize; --k)
00759                 {
00760                         deleteElement(k);
00761                         
00762                         if (k == 0) break; // we're dealing with unsigned quantities
00763                 }
00764                 _Size = newSize;
00765         }
00766 
00767 
00768         _MaxSize = newSize;
00769         _InvMass.resize(newSize);
00770         _Pos.resize(newSize);
00771         _Speed.resize(newSize);
00772         _Time.resize(newSize);
00773         _TimeIncrement.resize(newSize);
00774 
00775         if (_ParametricMotion)
00776         {
00777                 _PInfo.resize(newSize);
00778         }       
00779 
00780         if (_CollisionInfo)
00781         {
00782                 _CollisionInfo->resize(newSize);
00783         }
00784 
00785         
00786 
00787         // resize attributes for all bound objects
00788         for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
00789         {
00790                 (*it)->resize(newSize);
00791         }
00792 
00793 
00795         notifyMaxNumFacesChanged();
00796 }
00797 
00798 
00799 void CPSLocated::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00800 {
00801         sint ver = f.serialVersion(4);
00802         CParticleSystemProcess::serial(f);
00803         
00804         f.serial(_Name);
00805 
00806         f.serial(_InvMass);
00807         f.serial(_Pos);
00808         f.serial(_Speed);
00809         f.serial(_Time);
00810         f.serial(_TimeIncrement);
00811 
00812         f.serial(_Size); 
00813         f.serial(_MaxSize);
00814 
00815         f.serial(_LastForever);
00816 
00817         f.serialPtr(_CollisionInfo);
00818         f.serial(_CollisionInfoNbRef);
00819 
00820         
00821         if (f.isReading())
00822         {
00823                 delete _LifeScheme;
00824                 delete _MassScheme;
00825 
00826                 bool useScheme;
00827                 f.serial(useScheme);
00828                 if (useScheme)
00829                 {
00830                         f.serialPolyPtr(_LifeScheme);
00831                 }
00832                 else
00833                 {
00834                         f.serial(_InitialLife);
00835                         _LifeScheme = NULL;
00836                 }
00837 
00838                 f.serial(useScheme);
00839                 if (useScheme)
00840                 {
00841                         f.serialPolyPtr(_MassScheme);
00842                 }
00843                 else
00844                 {
00845                         f.serial(_InitialMass);
00846                         nlassert(_InitialMass > 0);
00847                         _MassScheme = NULL;
00848                 }
00849         }
00850         else
00851         {
00852                 bool bFalse = false, bTrue = true;
00853                 if (_LifeScheme)
00854                 {
00855                         f.serial(bTrue);
00856                         f.serialPolyPtr(_LifeScheme);
00857                 }
00858                 else
00859                 {
00860                         f.serial(bFalse);
00861                         f.serial(_InitialLife);
00862                 }
00863                 if (_MassScheme)
00864                 {
00865                         f.serial(bTrue);
00866                         f.serialPolyPtr(_MassScheme);
00867                 }
00868                 else
00869                 {
00870                         f.serial(bFalse);
00871                         nlassert(_InitialMass > 0);
00872                         f.serial(_InitialMass);                 
00873                 }
00874         }
00875 
00876 
00877         f.serial(_NbFramesToSkip);
00878 
00879         f.serialContPolyPtr(_DtorObserversVect);
00880 
00881         if (f.isReading())
00882         {
00883                 while(!_RequestStack.empty())
00884                 {
00885                         _RequestStack.pop();
00886                 }
00887                 uint32 size;
00888                 f.serial(size);
00889                 for (uint32 k = 0; k < size; ++k)
00890                 {
00891                         TNewElementRequestStack::value_type t;
00892                         f.serial(t);
00893                         _RequestStack.push(t);
00894                 }
00895         }
00896         else
00897         {
00898                 // when writing the stack, we must make a copy because we can't access elements by their index
00899                 // so the stack must be destroyed
00900                 TNewElementRequestStack r2;
00901                 uint32 size = (uint32) _RequestStack.size();
00902                 f.serial(size);
00903 
00904                 while(!_RequestStack.empty())
00905                 {
00906                         r2.push(_RequestStack.top());
00907                         _RequestStack.pop();
00908                 }
00909                 // now rebuild the stack while serializing it;
00910                 while (!r2.empty())
00911                 {                       
00912                         f.serial(r2.top());
00913                         _RequestStack.push(r2.top());
00914                         r2.pop();
00915                 }
00916 
00917         }
00918 
00919         
00920 
00921 
00922         f.serial(_UpdateLock);  
00923 
00924         f.serialContPolyPtr(_LocatedBoundCont);
00925         
00926         if (ver > 1)
00927         {
00928                 f.serial(_LODDegradation);
00929         }
00930 
00931         if (ver > 2)
00932         {
00933                 f.serial(_ParametricMotion);
00934         }
00935 
00936         if (f.isReading())
00937         {
00938                 // evaluate our max number of faces
00939                 notifyMaxNumFacesChanged();
00940 
00941                 if (_ParametricMotion)
00942                 {
00943                         allocateParametricInfos();                      
00944                 }
00945         }
00946 
00947         if (ver > 3)
00948         {
00949                 f.serial(_TriggerOnDeath, _TriggerID);
00950         }
00951 }
00952 
00953 
00954 // integrate speed of particles. Makes eventually use of SSE instructions when present
00955 static void IntegrateSpeed(uint count, float *src1, const float *src2 ,float ellapsedTime)
00956 {       
00957         #if 0 // this works, but is not enabled for now. The precision is not that good...
00958                 #ifdef NL_OS_WINDOWS
00959 
00960 
00961 
00962                 if (NLMISC::CCpuInfo::hasSSE()
00963                         && ((uint) src1 & 15) == ((uint) src2 & 15)
00964                         && ! ((uint) src1 & 3)
00965                         && ! ((uint) src2 & 3)                          
00966                    )   // must must be sure that memory alignment is identical     
00967                 {
00968 
00969                         // compute first datas in order to align to 16 byte boudary
00970 
00971                         uint alignCount =  ((uint) src1 >> 2) & 3; // number of float to process
00972 
00973                         while (alignCount --)
00974                         {
00975                                 *src1++ += ellapsedTime * *src2 ++;
00976                         }
00977 
00978 
00979 
00980                         count -= alignCount;
00981                         if (count > 3)
00982                         {
00983                                 float et[4] = { ellapsedTime, ellapsedTime, ellapsedTime, ellapsedTime};
00984                                 // sse part of computation
00985                                 __asm
00986                                 {
00987                                                 mov  ecx, count
00988                                                 shr  ecx, 2
00989                                                 
00990 
00991                                                 xor   edx, edx
00992 
00993                                                 mov    eax, src1                        
00994                                                 mov    ebx, src2                        
00995                                                 movups  xmm0, et[0]
00996                                         myLoop:
00997                                                 movaps xmm2, [ebx + 8 * edx]
00998                                                 movaps xmm1, [eax + 8 * edx]
00999                                                 mulps  xmm2, xmm0                       
01000                                                 addps  xmm1, xmm2
01001                                                 movaps [eax + 8 * edx], xmm1                    
01002                                                 add edx, 2                                      
01003                                                 dec ecx
01004                                                 jne myLoop                              
01005                                 }
01006                         }
01007                         // proceed with left float
01008                         count &= 3;
01009 
01010                         if (count)
01011                         {
01012                                 src1 += alignCount;     
01013                                 src2 += alignCount;
01014                                 do
01015                                 {
01016                                         *src1 += ellapsedTime * *src2;
01017 
01018                                         ++src1;
01019                                         ++src2;
01020                                 }
01021                                 while (--count);
01022                         }
01023 
01024                 }
01025                 else
01026                 #endif
01027         #endif
01028         {
01029                 // standard version     
01030                 
01031         /*      for (float *src1End = src1 + count; src1 != src1End; ++src1, ++src2)
01032                 {                               
01033                         *src1 += ellapsedTime * *src2;                  
01034                 } */
01035 
01036 
01037                 // standard version     
01038                 uint countDiv8 = count>>3;
01039                 count &= 7; // takes count % 8
01040 
01041                 while (countDiv8 --)
01042                 {               
01043                         src1[0] += ellapsedTime * src2[0];
01044                         src1[1] += ellapsedTime * src2[1];
01045                         src1[2] += ellapsedTime * src2[2];
01046                         src1[3] += ellapsedTime * src2[3];
01047 
01048                         src1[4] += ellapsedTime * src2[4];
01049                         src1[5] += ellapsedTime * src2[5];
01050                         src1[6] += ellapsedTime * src2[6];
01051                         src1[7] += ellapsedTime * src2[7];
01052 
01053                         src2 += 8;
01054                         src1 += 8;
01055                 }
01056                 
01057                 while (count--)
01058                 {
01059                         *src1++ += ellapsedTime * *src2++;                      
01060                 }
01061 
01062 
01063         }
01064 }
01065 
01066 
01067 void CPSLocated::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEt)
01068 {       
01069         if (!_Size) return;     
01070 
01071 
01072         if (pass == PSMotion)
01073         {               
01074 
01075                 
01076                 // check wether we must perform LOD degradation
01077                 if (_LODDegradation)
01078                 {
01079                         if (ellapsedTime > 0)
01080                         {
01081                                 nlassert(_Owner);
01082                                 // compute the number of particles to show
01083                                 const uint maxToHave = (uint) (_MaxSize * _Owner->getOneMinusCurrentLODRatio());
01084                                 if (_Size > maxToHave) // too much instances ?
01085                                 {
01086                                         // choose a random element to start at, and a random step
01087                                         // this will avoid a pulse effect when the system is far away
01088                                         
01089                                         uint pos = maxToHave ? rand() % maxToHave : 0;
01090                                         uint step  = maxToHave ? rand() % maxToHave : 0;
01091 
01092                                         do
01093                                         {
01094                                                 deleteElement(pos);
01095                                                 pos += step;
01096                                                 if (pos >= maxToHave) pos -= maxToHave;
01097                                         }
01098                                         while (_Size !=maxToHave);                              
01099                                 }
01100                         }
01101                 }
01102 
01103 
01104                 // check if we must skip frames
01105                 if (!_NbFramesToSkip || !( (uint32) _Owner->getDate() % (_NbFramesToSkip + 1)))
01106                 {
01107                         
01108 
01109                         // update the located creation requests that may have been posted
01110                         updateNewElementRequestStack();
01111 
01112 
01113                         // there are 2 integration steps : with and without collisions
01114 
01115                         if (!_CollisionInfo) // no collisionner are used
01116                         {
01117                                 if (_Size != 0) // avoid referencing _Pos[0] if there's no size, causes STL vectors to assert...
01118                                         IntegrateSpeed(_Size * 3, &_Pos[0].x, &_Speed[0].x, ellapsedTime);
01119                         }
01120                         else
01121                         {
01122                                 // integration with collisions
01123 
01124                                 nlassert(_CollisionInfo);
01125                                 TPSAttribCollisionInfo::iterator itc = _CollisionInfo->begin();
01126                                 TPSAttribVector::iterator itSpeed = _Speed.begin();             
01127                                 TPSAttribVector::iterator itPos = _Pos.begin();         
01128 
01129                                 for (uint k = 0; k < _Size;)
01130                                 {
01131                                         if (itc->dist != -1)
01132                                         {
01133                                                 (*itPos) = itc->newPos;
01134                                                 (*itSpeed) = itc->newSpeed;
01135                                                 // notify each located bindable that a bounce occured ...
01136                                                 for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01137                                                 {       
01138                                                         (*it)->bounceOccured(k);
01139                                                 }
01140                                                 switch(itc->collisionZone->getCollisionBehaviour())
01141                                                 {
01142                                                         case CPSZone::bounce:
01143                                                                 itc->reset();
01144                                                                 ++k, ++itPos, ++itSpeed, ++itc;
01145                                                         break;
01146                                                         case CPSZone::destroy:
01147                                                                 deleteElement(k);
01148                                                         break;
01149                                                 }
01150                                         }
01151                                         else
01152                                         {
01153                                                 (*itPos) += ellapsedTime * (*itSpeed) * itc->TimeSliceRatio;
01154                                                 itc->reset();
01155                                                 ++k, ++itPos, ++itSpeed, ++itc;
01156                                         }
01157                                 }
01158 
01159                                 
01160                                 // reset collision info for the next time => done during the traversal
01162                                 
01163                         }               
01164                 }
01165                 else
01166                 {
01167                         return; // we skip the frame...
01168                 }
01169         }
01170 
01171         if (pass != PSMotion)
01172         {
01173                 // apply the pass to all bound objects
01174                 for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01175                 {
01176                         if ((*it)->isActive())
01177                         {                       
01178                                 if ((*it)->getLOD() == PSLod1n2 || _Owner->getLOD() == (*it)->getLOD()) // has this object the right LOD ?
01179                                 {
01180                                         (*it)->step(pass, ellapsedTime, realEt);
01181                                 }
01182                         }
01183                 }
01184         }
01185         else
01186         {
01187                 for (TLocatedBoundCont::iterator it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01188                 {       
01189                         if ((*it)->isActive())
01190                         {                       
01191                                 (*it)->step(pass, ellapsedTime, realEt);
01192                         }
01193                 }
01194 
01195         }
01196 }
01197 
01198 void CPSLocated::updateLife(TAnimationTime ellapsedTime)
01199 {
01200         if (!_Size) return;
01201         if (! _LastForever)
01202         {
01203                 if (_LifeScheme != NULL)
01204                 {                       
01205                         TPSAttribTime::iterator itTime = _Time.begin(), itTimeInc = _TimeIncrement.begin();                     
01206                         for (uint32 k = 0; k < _Size;)
01207                         {
01208                                 *itTime += ellapsedTime * *itTimeInc;
01209                                 if (*itTime >= 1.0f)
01210                                 {
01211                                         deleteElement(k);
01212                                 }
01213                                 else
01214                                 {
01215                                         ++k;
01216                                         ++itTime;
01217                                         ++itTimeInc;
01218                                 }
01219                         }
01220                 }
01221                 else 
01222                 {
01223                         if (_InitialLife != 0)
01224                         {
01225                                 nlassert(_Owner);
01226                                 float timeInc = ellapsedTime * 1.f / _InitialLife;
01227                                 if (_Owner->getSystemDate() >= (_InitialLife - ellapsedTime))
01228                                 {
01229                                         TPSAttribTime::iterator itTime = _Time.begin();
01230                                         for (uint32 k = 0; k < _Size;)
01231                                         {
01232                                                 *itTime += timeInc;
01233                                                 if (*itTime >= 1.0f)
01234                                                 {
01235                                                         deleteElement(k);
01236                                                 }
01237                                                 else
01238                                                 {
01239                                                         ++k;
01240                                                         ++itTime;                                       
01241                                                 }
01242                                         }
01243                                 }
01244                                 else
01245                                 {
01246                                         TPSAttribTime::iterator itTime = _Time.begin(), itEndTime = _Time.end();
01247                                         do
01248                                         {
01249                                                 *itTime += timeInc;
01250                                                 ++itTime;
01251                                         }
01252                                         while (itTime != itEndTime);
01253                                 }
01254                         }
01255                         else
01256                         {
01257                                 uint size = _Size;
01258                                 do
01259                                 {
01260                                         deleteElement(0);
01261                                 }
01262                                 while (--size);                         
01263                         }
01264                 }
01265         }
01266         else
01267         {
01268                 // the time attribute gives the life in seconds
01269                 TPSAttribTime::iterator itTime = _Time.begin(), endItTime = _Time.end();
01270                 for (; itTime != endItTime; ++itTime)
01271                 {
01272                         *itTime += ellapsedTime;
01273                 }
01274         }
01275 }
01276 
01277 
01278 
01279 
01280 void CPSLocated::updateNewElementRequestStack(void)
01281 {
01282         while (!_RequestStack.empty())
01283         {
01284                 newElement(_RequestStack.top()._Pos, _RequestStack.top()._Speed);
01285                 _RequestStack.pop();
01286         }
01287 }
01288 
01289 
01290 bool CPSLocated::computeBBox(NLMISC::CAABBox &box) const
01291 {
01292         if (!_Size) return false; // something to compute ?
01293 
01294 
01295         TLocatedBoundCont::const_iterator it;
01296         TPSAttribVector::const_iterator it2;
01297 
01298         // check whether any object bound to us need a bbox
01299 
01300         for (it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01301         {
01302                 if ((*it)->doesProduceBBox()) 
01303                 {
01304                         break;
01305                 }
01306         }
01307 
01308         if (it == _LocatedBoundCont.end()) 
01309         {
01310                 return false;
01311         }
01312 
01313         CVector min = _Pos[0], max = _Pos[0];
01314 
01315         for (it2 = _Pos.begin(); it2 != _Pos.end(); ++ it2)
01316         {
01317                 const CVector &v = (*it2);
01318                 min.minof(min, v);      
01319                 max.maxof(max, v);              
01320         }
01321 
01322         box.setMinMax(min, max);        
01323 
01324         // we've considered that located had no extent in space
01325         // now, we must call each objects that are bound to the located in order
01326         // to complete the bbox if they have no null extent
01327 
01328         NLMISC::CAABBox tmpBox, startBox = box;
01329 
01330         for (it = _LocatedBoundCont.begin(); it != _LocatedBoundCont.end(); ++it)
01331         {
01332                 if ((*it)->doesProduceBBox())
01333                 {
01334                         tmpBox = startBox;
01335                         if ((*it)->completeBBox(tmpBox))
01336                         {
01337                                 box = NLMISC::CAABBox::computeAABBoxUnion(tmpBox, box);
01338                         }
01339                 }
01340         }
01341 
01342         return true;
01343 }
01344 
01345 
01347 void CPSLocated::setupDriverModelMatrix(void) 
01348 {
01349         if (_SystemBasisEnabled)
01350         {
01351                 getDriver()->setupModelMatrix(_Owner->getSysMat());             
01352         }
01353         else
01354         {
01355                 getDriver()->setupModelMatrix(CMatrix::Identity);
01356         }
01357 }
01358 
01359 
01360 
01361 
01362 void CPSLocated::queryCollisionInfo(void)
01363 {
01364         if (_CollisionInfoNbRef)
01365         {
01366                 ++ _CollisionInfoNbRef;
01367         }
01368         else
01369         {
01370                 _CollisionInfo = new TPSAttribCollisionInfo;
01371                 _CollisionInfoNbRef = 1;
01372                 _CollisionInfo->resize(_MaxSize);               
01373 
01374                 for(uint k = 0; k < _Size; ++k)
01375                 {
01376                         _CollisionInfo->insert();
01377                 }               
01378         }
01379 }
01380 
01381 void CPSLocated::releaseCollisionInfo(void)
01382 {
01383         nlassert(_CollisionInfoNbRef); // check whether queryCollisionInfo was called
01384                                                                         // so the number of refs must not = 0                                                                   
01385     --_CollisionInfoNbRef;
01386         if (_CollisionInfoNbRef == 0)
01387         {
01388                 delete _CollisionInfo;
01389                 _CollisionInfo = NULL;
01390         }
01391 }
01392 
01393 
01394 void CPSLocated::resetCollisionInfo(void)
01395 {
01396         nlassert(_CollisionInfo);
01397 
01398         TPSAttribCollisionInfo::iterator it = _CollisionInfo->begin(), endIt = _CollisionInfo->end();
01399 
01400         for (; it != endIt; ++it)
01401         {
01402                 it->reset();
01403         }
01404 }
01405 
01406 void CPSLocated::registerIntegrableForce(CPSForce *f)
01407 {       
01408         nlassert(std::find(_IntegrableForces.begin(), _IntegrableForces.end(), f) == _IntegrableForces.end()); // force registered twice
01409         _IntegrableForces.push_back(f);
01410         if (_SystemBasisEnabled != f->getOwner()->isInSystemBasis())
01411         {
01412                 ++_NumIntegrableForceWithDifferentBasis;
01413                 releaseParametricInfos();
01414         }
01415 }
01416 
01417 
01418 void CPSLocated::unregisterIntegrableForce(CPSForce *f)
01419 {
01420         nlassert(f->getOwner()); // f must be attached to a located
01421         std::vector<CPSForce *>::iterator it = std::find(_IntegrableForces.begin(), _IntegrableForces.end(), f);
01422         nlassert(it != _IntegrableForces.end() );       
01423         _IntegrableForces.erase(it);
01424         if (_SystemBasisEnabled != f->getOwner()->isInSystemBasis())
01425         {
01426                 --_NumIntegrableForceWithDifferentBasis;
01427         }
01428 }
01429 
01430 void CPSLocated::addNonIntegrableForceRef(void)
01431 {
01432         ++_NonIntegrableForceNbRefs;
01433         releaseParametricInfos();
01434 }
01435 
01436 void CPSLocated::releaseNonIntegrableForceRef(void)
01437 {
01438         nlassert(_NonIntegrableForceNbRefs != 0);
01439         --_NonIntegrableForceNbRefs;
01440 }
01441 
01442 
01443 void CPSLocated::integrableForceBasisChanged(bool basis)
01444 {       
01445         if (_SystemBasisEnabled != basis)
01446         {
01447                 ++_NumIntegrableForceWithDifferentBasis;
01448                 releaseParametricInfos();
01449         }
01450         else
01451         {
01452                 --_NumIntegrableForceWithDifferentBasis;
01453         }
01454 }
01455 
01456 
01458 CPSLocatedBindable *CPSLocated::unbind(uint index)
01459 {       
01460         nlassert(index < _LocatedBoundCont.size());
01461         CPSLocatedBindable *lb = _LocatedBoundCont[index];              
01462         lb->setOwner(NULL);     
01463         _LocatedBoundCont.erase(_LocatedBoundCont.begin() + index);
01464         return lb;
01465 }
01466 
01468 bool CPSLocated::isBound(const CPSLocatedBindable *lb) const
01469 {
01470         TLocatedBoundCont::const_iterator it = std::find(_LocatedBoundCont.begin(), _LocatedBoundCont.end(), lb);
01471         return it != _LocatedBoundCont.end();
01472 }
01473 
01475 uint CPSLocated::getIndexOf(const CPSLocatedBindable *lb) const
01476 {
01477         for(uint k = 0; k < _LocatedBoundCont.size(); ++k)
01478         {
01479                 if (_LocatedBoundCont[k] == lb) return k;
01480         }
01481         nlassert(0);
01482         return 0;
01483 }
01484 
01485 
01486 
01488 // CPSLocatedBindable implementation //
01490 
01491 
01493 CPSLocatedBindable::CPSLocatedBindable() : _LOD(PSLod1n2), _Owner(NULL), _ExternID(0), _Active(true)
01494 {
01495         _Owner = NULL;
01496 }
01497 
01498 void CPSLocatedBindable::setOwner(CPSLocated *psl)
01499 { 
01500         if (psl == NULL)
01501         {
01502                 releaseAllRef();
01503                 if (_Owner)
01504                 {
01505                         // empty this located bindable. Need to be empty if it must be rebound to another located.
01506                         for (uint k = 0; k < _Owner->getSize(); ++k)
01507                         {
01508                                 deleteElement(0);
01509                         }
01510                 }
01511         }
01512         _Owner = psl; 
01513 }
01514 
01516 CPSLocatedBindable::~CPSLocatedBindable()
01517 {
01518         if (_ExternID)
01519         {
01520                 if (_Owner && _Owner->getOwner())
01521                 {
01522                         _Owner->getOwner()->unregisterLocatedBindableExternID(this);
01523                 }
01524         }
01525 }
01526 
01528 const NLMISC::CMatrix &CPSLocatedBindable::getLocatedMat(void) const
01529 {
01530         nlassert(_Owner);
01531         if (_Owner->isInSystemBasis())
01532         {
01533                 return _Owner->getOwner()->getSysMat();
01534         }
01535         else
01536         {
01537                 return NLMISC::CMatrix::Identity;
01538         }
01539 }
01540 
01541 
01543 void CPSLocatedBindable::notifyTargetRemoved(CPSLocated *ptr)
01544 {
01545         ptr->unregisterDtorObserver(this);
01546 }
01547 
01549 void CPSLocatedBindable::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01550 {
01551         sint ver = f.serialVersion(4);
01552         f.serialPtr(_Owner);
01553         if (ver > 1) f.serialEnum(_LOD);
01554         if (ver > 2) f.serial(_Name);
01555         if (ver > 3) 
01556         {
01557                 if (f.isReading())
01558                 {
01559                         uint32 id;
01560                         f.serial(id);
01561                         setExternID(id);
01562                 }
01563                 else
01564                 {
01565                         f.serial(_ExternID);
01566                 }
01567         }
01568         
01569 }
01570 
01572 void CPSLocatedBindable::displayIcon2d(const CVector tab[], uint nbSegs, float scale)
01573 {
01574         uint32 size = _Owner->getSize();
01575         if (!size) return;              
01576         setupDriverModelMatrix();       
01577 
01578         const CVector I = computeI();
01579         const CVector K = computeK();
01580 
01581         static std::vector<NLMISC::CLine> lines;
01582         
01583         lines.clear();
01584 
01585         // ugly slow code, but not for runtime
01586         for (uint  k = 0; k < size; ++k)
01587         {
01588                 // center of the current particle
01589                 const CVector p = _Owner->getPos()[k];
01590                 
01591                 
01592 
01593                 for (uint l = 0; l < nbSegs; ++l)
01594                 {
01595                         NLMISC::CLine li;
01596                         li.V0 = p + scale * (tab[l << 1].x * I + tab[l << 1].y * K);
01597                         li.V1 = p + scale * (tab[(l << 1) + 1].x * I + tab[(l << 1) + 1].y * K);
01598                         lines.push_back(li);
01599                 }
01600         
01601                 CMaterial mat;
01602 
01603                 mat.setBlendFunc(CMaterial::one, CMaterial::one);
01604                 mat.setZWrite(false);
01605                 mat.setLighting(false);
01606                 mat.setBlend(true);
01607                 mat.setZFunc(CMaterial::less);
01608                 
01609         
01610 
01611                 CPSLocated *loc;
01612                 uint32 index;           
01613                 CPSLocatedBindable *lb;
01614                 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
01615         
01616                 mat.setColor((lb == NULL || this == lb) && loc == _Owner && index == k  ? CRGBA::Red : CRGBA(127, 127, 127));
01617                 
01618 
01619                 CDRU::drawLinesUnlit(lines, mat, *getDriver() );
01620         }
01621 
01622 }
01623 
01625 CFontManager *CPSLocatedBindable::getFontManager(void)
01626 {
01627         nlassert(_Owner);
01628         return _Owner->getFontManager();
01629 }
01630 
01633 const CFontManager *CPSLocatedBindable::getFontManager(void) const
01634 {
01635         nlassert(_Owner);
01636         return _Owner->getFontManager();
01637 }
01638 
01639 
01641 // Shortcut to get the matrix of the system     
01642  const NLMISC::CMatrix &CPSLocatedBindable::getSysMat(void) const 
01643 {
01644         nlassert(_Owner);               
01645         return _Owner->getOwner()->getSysMat();
01646 }
01647 
01650 const NLMISC::CMatrix &CPSLocatedBindable::getInvertedSysMat(void) const 
01651 {
01652         nlassert(_Owner);
01653                 return _Owner->getOwner()->getInvertedSysMat();
01654 
01655 }
01656 
01658 const NLMISC::CMatrix &CPSLocatedBindable::getInvertedLocatedMat(void) const
01659 {
01660         nlassert(_Owner);
01661         if (_Owner->isInSystemBasis())
01662         {
01663                 return _Owner->getOwner()->getInvertedSysMat();
01664         }
01665         else
01666         {
01667                 return NLMISC::CMatrix::Identity;
01668         }
01669 }
01670 
01673 const NLMISC::CMatrix &CPSLocatedBindable::getViewMat(void) const 
01674 {
01675         nlassert(_Owner);
01676         return _Owner->getOwner()->getViewMat();        
01677 }       
01678 
01679 
01682 const NLMISC::CMatrix &CPSLocatedBindable::getInvertedViewMat(void) const 
01683 {
01684         nlassert(_Owner);
01685         return _Owner->getOwner()->getInvertedViewMat();        
01686 }       
01687 
01690 void CPSLocatedBindable::setupDriverModelMatrix(void)  
01691 {
01692         nlassert(_Owner);
01693         _Owner->setupDriverModelMatrix();
01694 }
01695 
01697 void    CPSLocatedBindable::setExternID(uint32 id)
01698 {
01699         if (id == _ExternID) return;
01700         nlassert(_Owner && _Owner->getOwner()); // to call this method, this locatedBindable must be inserted in a system!! 
01701                                                                                         // (e.g not standalone)
01702         _Owner->getOwner()->unregisterLocatedBindableExternID(this);
01703         if (id != 0)
01704         {       
01705                 _Owner->getOwner()->registerLocatedBindableExternID(id, this);
01706                 _ExternID = id;
01707         }       
01708 }
01709 
01711 void CPSLocatedBindable::releaseAllRef()
01712 {
01713 }
01714 
01715          
01716 
01717 
01718 
01720 // CPSTargetLocatedBindable implementation //
01722 
01724 void CPSTargetLocatedBindable::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01725 {
01726         (void)f.serialVersion(1);       
01727         f.serialPtr(_Owner);
01728         f.serial(_Name);
01729         if (f.isReading())
01730         {
01731                 // delete previous attached bindables...
01732                 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
01733                 {
01734                         delete (*it);
01735                 }
01736                 _Targets.clear();               
01737         }
01738         f.serialContPolyPtr(_Targets);  
01739 }
01740 
01741 
01743 void CPSTargetLocatedBindable::attachTarget(CPSLocated *ptr)
01744 {
01745 
01746         // a target can't be shared between different particle systems
01747         #ifdef NL_DEBUG
01748         if (_Owner)
01749         {
01750                 nlassert(_Owner->getOwner() == ptr->getOwner());
01751         }
01752         #endif
01753 
01754         // see wether this target has not been registered before 
01755         nlassert(std::find(_Targets.begin(), _Targets.end(), ptr) == _Targets.end());
01756         _Targets.push_back(ptr);
01757 
01758         // we register us to be notified when the target disappear
01759         ptr->registerDtorObserver(this);
01760 }
01761 
01762 
01764 void CPSTargetLocatedBindable::notifyTargetRemoved(CPSLocated *ptr) 
01765 {       
01766         TTargetCont::iterator it = std::find(_Targets.begin(), _Targets.end(), ptr);
01767         nlassert(it != _Targets.end());
01768         releaseTargetRsc(*it);  
01769         _Targets.erase(it);
01770 
01771         CPSLocatedBindable::notifyTargetRemoved(ptr);   
01772 }
01773 
01774 
01775 
01776 // dtor
01777 
01779 void CPSTargetLocatedBindable::finalize(void)
01780 {       
01784         for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
01785         {               
01786                 releaseTargetRsc(*it);
01787         }
01788 }
01789 
01791 CPSTargetLocatedBindable::~CPSTargetLocatedBindable()
01792 {       
01793         // we unregister to all the targets
01794         for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
01795         {               
01796                 (*it)->unregisterDtorObserver(this);
01797         }
01798 }
01799 
01801 void CPSTargetLocatedBindable::releaseRefTo(const CParticleSystemProcess *other)
01802 {
01803         TTargetCont::iterator it = std::find(_Targets.begin(), _Targets.end(), other);
01804         if (it == _Targets.end()) return;
01805         releaseTargetRsc(*it);
01806         (*it)->unregisterDtorObserver(this);
01807         _Targets.erase(it);
01808         nlassert(std::find(_Targets.begin(), _Targets.end(), other) == _Targets.end());
01809 }
01810 
01812 void CPSTargetLocatedBindable::releaseAllRef()
01813 {
01814         for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
01815         {
01816                 releaseTargetRsc(*it);
01817                 (*it)->unregisterDtorObserver(this);            
01818         }
01819         _Targets.clear();
01820         CPSLocatedBindable::releaseAllRef();
01821 }
01822 
01823 
01824 
01825 
01826 } // NL3D