# 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_emitter.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "std3d.h"
00027 
00028 #include <stdlib.h>
00029 #include "3d/ps_emitter.h"
00030 #include "3d/material.h"
00031 #include "nel/misc/line.h"
00032 #include "3d/dru.h"
00033 #include "3d/particle_system.h"
00034 
00035 namespace NL3D {
00036 
00037 
00038 
00039 // number of emitter to be processed at once
00040 const uint emitterBuffSize = 512;
00041 
00043 // CPSEmitter implementation //
00045 CPSEmitter::CPSEmitter() : _EmittedType(NULL),
00046                                                    _SpeedInheritanceFactor(0.f),
00047                                                    _EmissionType(regular),
00048                                                    _Period(0.02f),
00049                                                    _PeriodScheme(NULL), 
00050                                                    _GenNb(1), 
00051                                                    _GenNbScheme(NULL), 
00052                                                    _EmitDelay(0),
00053                                                    _MaxEmissionCount(0),
00054                                                    _SpeedBasisEmission(false),
00055                                                    _EmitDirBasis(true),
00056                                                    _ConsistentEmission(true)
00057 {
00058 }
00059 
00060 
00062 CPSEmitter::~CPSEmitter()
00063 {
00064         delete _PeriodScheme;
00065         delete _GenNbScheme;
00066         // if a located is emitted, unregister us as an observer
00067         if (_EmittedType)
00068         {
00069                 _EmittedType->unregisterDtorObserver(this);
00070         }
00071 }
00072 
00074 void CPSEmitter::releaseRefTo(const CParticleSystemProcess *other)
00075 {
00076         if (_EmittedType == other)
00077         {
00078                 setEmittedType(NULL);
00079         }
00080 }
00081 
00082 void CPSEmitter::releaseAllRef()
00083 {
00084         setEmittedType(NULL);
00085 }
00086 
00087 
00089 inline void CPSEmitter::processEmit(uint32 index, sint nbToGenerate)
00090 {       
00091         static NLMISC::CVector speed, pos;
00092         
00093         if (!_SpeedBasisEmission)
00094         {
00095                 if (_SpeedInheritanceFactor == 0.f)
00096                 {               
00097                         if (_EmitDirBasis)
00098                         {
00099                                 while (nbToGenerate > 0)
00100                                 {
00101                                         nbToGenerate --;
00102                                         emit(_Owner->getPos()[index], index, pos, speed);
00103                                         _EmittedType->newElement(pos, speed, this->_Owner, index);
00104                                 }
00105                         }
00106                         else
00107                         {
00108                                 while (nbToGenerate > 0)
00109                                 {
00110                                         nbToGenerate --;
00111                                         emit(_Owner->getPos()[index], index, pos, speed);
00112                                         _EmittedType->newElement(pos, speed, this->_Owner, index, false);
00113                                 }
00114                         }
00115                 }
00116                 else
00117                 {
00118                         while (nbToGenerate --)
00119                         {
00120                                 emit(_Owner->getPos()[index], index, pos, speed);
00121                                 _EmittedType->newElement(pos, speed + _SpeedInheritanceFactor * _Owner->getSpeed()[index], this->_Owner);
00122                         }
00123                 }
00124         }
00125         else
00126         {
00127                 NLMISC::CMatrix m;
00128                 CPSUtil::buildSchmidtBasis(_Owner->getSpeed()[index], m);
00129                 if (_SpeedInheritanceFactor == 0.f)
00130                 {               
00131                         while (nbToGenerate > 0)
00132                         {
00133                                 nbToGenerate --;
00134                                 emit(_Owner->getPos()[index], index, pos, speed);
00135                                 _EmittedType->newElement(pos, m * speed, this->_Owner, index);
00136                         }
00137                 }
00138                 else
00139                 {
00140                         while (nbToGenerate --)
00141                         {
00142                                 emit(_Owner->getPos()[index], index, pos, speed);
00143                                 _EmittedType->newElement(pos, m * speed + _SpeedInheritanceFactor * _Owner->getSpeed()[index], this->_Owner, index);
00144                         }
00145                 }
00146         }
00147 }
00148 
00152 static inline void CompensateEmission(CPSLocated *emittedType, uint emittedIndex, TAnimationTime deltaT, TAnimationTime ellapsedTime, float realEllapsedTimeRatio)
00153 {       
00154         // now, update emitted element life time        
00155         if (emittedType->getLastForever())
00156         {               
00157                 emittedType->getTime()[emittedIndex] += realEllapsedTimeRatio * deltaT;
00158 
00159                 if (emittedType->isParametricMotionEnabled())
00160                 {
00161                         emittedType->getParametricInfos()[emittedIndex].Date -= realEllapsedTimeRatio * deltaT;
00162                 }
00163                 else
00164                 {
00165                         if (!emittedType->hasCollisionInfos())
00166                         {
00167                                 // no collision case
00168                                 emittedType->getPos()[emittedIndex] += deltaT * emittedType->getSpeed()[emittedIndex];
00169                         }
00170                         else // if there are collisions, we delay the step to the next iteration to ensure correct collisions
00171                         {
00172                                 emittedType->getCollisionInfo()[emittedIndex].TimeSliceRatio = deltaT / ellapsedTime;                           
00173                         }
00174                 }
00175         }
00176         else
00177         {               
00178                 TAnimationTime &destTime = emittedType->getTime()[emittedIndex];
00179                 if (emittedType->getLifeScheme() != NULL)
00180                 {
00181                         destTime = realEllapsedTimeRatio * deltaT * emittedType->getTimeIncrement()[emittedIndex];
00182                 }
00183                 else
00184                 {                               
00185                         if (emittedType->getInitialLife() != 0.f)
00186                         {
00187                                 destTime = realEllapsedTimeRatio * deltaT / emittedType->getInitialLife();
00188                         }
00189                 }
00190                 if (destTime >= 1.f)
00191                 {                                       
00192                         emittedType->deleteElement(emittedIndex);                       
00193                 }
00194                 else
00195                 {       
00196                         if (emittedType->isParametricMotionEnabled())
00197                         {
00198                                 emittedType->getParametricInfos()[emittedIndex].Date -= realEllapsedTimeRatio * deltaT;
00199                         }
00200                         else
00201                         {
00202                                 if (!emittedType->hasCollisionInfos())
00203                                 {
00204                                         // no collision case
00205                                         emittedType->getPos()[emittedIndex] += deltaT * emittedType->getSpeed()[emittedIndex];
00206                                 }
00207                                 else // if there are collisions, we delay the step to the next iteration to ensure correct collisions
00208                                 {
00209                                         emittedType->getCollisionInfo()[emittedIndex].TimeSliceRatio = deltaT / ellapsedTime;                           
00210                                 }
00211                         }
00212                 }
00213         }
00214 }
00215 
00217 inline void CPSEmitter::processEmitConsistent(const NLMISC::CVector &emitterPos,
00218                                                                                           uint32 index,
00219                                                                                           sint nbToGenerate,
00220                                                                                           TAnimationTime deltaT,
00221                                                                                           TAnimationTime ellapsedTime,
00222                                                                                           float realEllapsedTimeRatio
00223                                                                                          )
00224 {               
00225         static NLMISC::CVector speed, pos; 
00226         sint emittedIndex;
00227         if (!_SpeedBasisEmission)
00228         {
00229                 if (_SpeedInheritanceFactor == 0.f)
00230                 {               
00231                         if (_EmitDirBasis)
00232                         {
00233                                 while (nbToGenerate > 0)
00234                                 {
00235                                         nbToGenerate --;
00236                                         emit(emitterPos, index, pos, speed);
00237                                         emittedIndex = _EmittedType->newElement(pos, speed, this->_Owner, index, true, deltaT);
00238                                         if (emittedIndex != - 1) CompensateEmission(_EmittedType, emittedIndex, deltaT, ellapsedTime, realEllapsedTimeRatio);
00239                                         else break;
00240                                 }
00241                         }
00242                         else
00243                         {
00244                                 while (nbToGenerate > 0)
00245                                 {
00246                                         nbToGenerate --;
00247                                         emit(emitterPos, index, pos, speed);
00248                                         emittedIndex = _EmittedType->newElement(pos, speed, this->_Owner, index, false, deltaT);
00249                                         if (emittedIndex != - 1) CompensateEmission(_EmittedType, emittedIndex, deltaT, ellapsedTime, realEllapsedTimeRatio);
00250                                         else break;
00251                                 }
00252                         }
00253                 }
00254                 else
00255                 {
00256                         while (nbToGenerate --)
00257                         {
00258                                 emit(emitterPos, index, pos, speed);
00259                                 emittedIndex = _EmittedType->newElement(pos, speed + _SpeedInheritanceFactor * _Owner->getSpeed()[index], this->_Owner, index, true, deltaT);
00260                                 if (emittedIndex != - 1) CompensateEmission(_EmittedType, emittedIndex, deltaT, ellapsedTime, realEllapsedTimeRatio);
00261                                         else break;
00262                         }
00263                 }
00264         }
00265         else
00266         {
00267                 NLMISC::CMatrix m;
00268                 CPSUtil::buildSchmidtBasis(_Owner->getSpeed()[index], m);
00269                 if (_SpeedInheritanceFactor == 0.f)
00270                 {               
00271                         while (nbToGenerate > 0)
00272                         {
00273                                 nbToGenerate --;
00274                                 emit(emitterPos, index, pos, speed);
00275                                 emittedIndex = _EmittedType->newElement(pos, m * speed, this->_Owner, index, true, deltaT);
00276                                 if (emittedIndex != - 1) CompensateEmission(_EmittedType, emittedIndex, deltaT, ellapsedTime, realEllapsedTimeRatio);
00277                                         else break;
00278                         }
00279                 }
00280                 else
00281                 {
00282                         while (nbToGenerate --)
00283                         {
00284                                 emit(emitterPos, index, pos, speed);
00285                                 emittedIndex = _EmittedType->newElement(pos, m * speed + _SpeedInheritanceFactor * _Owner->getSpeed()[index], this->_Owner, index, true, deltaT);
00286                                 if (emittedIndex != - 1) CompensateEmission(_EmittedType, emittedIndex, deltaT, ellapsedTime, realEllapsedTimeRatio);
00287                                         else break;
00288                         }
00289                 }
00290         }
00291 }
00292 
00293 
00295 void    CPSEmitter::setEmissionType(TEmissionType freqType)
00296 { 
00297         _EmissionType = freqType; 
00298 }
00299 
00301 void CPSEmitter::setEmittedType(CPSLocated *et) 
00302 {
00303         if (_EmittedType)
00304         {
00305                 _EmittedType->unregisterDtorObserver(this);
00306         }
00307         if (et)
00308         {
00309                 et->registerDtorObserver(this);
00310         }       
00311 
00312         _EmittedType = et;
00313 }
00314 
00316 void CPSEmitter::notifyTargetRemoved(CPSLocated *ptr)
00317 {
00318         nlassert(ptr == _EmittedType && _EmittedType);
00319         setEmittedType(NULL);   
00320 }
00321 
00323 void CPSEmitter::setPeriod(float period)
00324 {
00325         if (_PeriodScheme)
00326         {
00327                 delete _PeriodScheme;
00328                 _PeriodScheme = NULL;
00329         }
00330         _Period = period;
00331 }
00332 
00334 void CPSEmitter::setPeriodScheme(CPSAttribMaker<float> *scheme)
00335 {       
00336         delete _PeriodScheme;   
00337         _PeriodScheme = scheme;
00338         if (_Owner && scheme->hasMemory()) scheme->resize(_Owner->getMaxSize(), _Owner->getSize());
00339 }
00340 
00342 void CPSEmitter::setGenNb(uint32 genNb)
00343 {
00344         if (_GenNbScheme)
00345         {
00346                 delete _GenNbScheme;
00347                 _GenNbScheme = NULL;
00348         }
00349         _GenNb = genNb; 
00350 }
00351 
00353 void CPSEmitter::setGenNbScheme(CPSAttribMaker<uint32> *scheme)
00354 {
00355         delete _GenNbScheme;    
00356         _GenNbScheme = scheme;
00357         if (_Owner && scheme->hasMemory()) scheme->resize(_Owner->getMaxSize(), _Owner->getSize());
00358 }
00359 
00361 void CPSEmitter::showTool(void) 
00362 {
00363         uint32 size = _Owner->getSize();
00364         if (!size) return;              
00365         setupDriverModelMatrix();       
00366 
00367         const CVector I = computeI();
00368         const CVector K = computeK();
00369 
00370         // ugly slow code, but not for runtime
00371         for (uint  k = 0; k < size; ++k)
00372         {
00373                 // center of the current particle
00374                 const CVector p = _Owner->getPos()[k];
00375                 const float sSize =0.1f;        
00376                 std::vector<NLMISC::CLine> lines;
00377                 NLMISC::CLine l;
00378                 l.V0 = p - sSize * I; l.V1 =  p + sSize * I; lines.push_back(l);
00379                 l.V0 = p - sSize * K; l.V1 =  p + sSize * K; lines.push_back(l);
00380                 l.V0 = p - sSize * (I + K); l.V1 = p + sSize * (I + K); lines.push_back(l);
00381                 l.V0 = p - sSize * (I - K); l.V1 = p + sSize * (I - K); lines.push_back(l);
00382                                                                                                                                                 
00383                 CMaterial mat;
00384                 mat.setBlendFunc(CMaterial::one, CMaterial::one);
00385                 mat.setZWrite(false);
00386                 mat.setLighting(false);
00387                 mat.setBlend(true);
00388                 mat.setZFunc(CMaterial::less);
00389                 
00390         
00391                 CPSLocated *loc;                
00392                 uint32 index;
00393                 CPSLocatedBindable *lb;
00394                 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00395 
00396                 mat.setColor((lb == NULL || this == lb) && loc == _Owner && index == k  ? CRGBA::Red : CRGBA(127, 127, 127));
00397                 
00398 
00399                 CDRU::drawLinesUnlit(lines, mat, *getDriver() );
00400         }
00401 }
00402 
00404 void CPSEmitter::singleEmit(uint32 index, uint quantity)
00405 {
00406         nlassert(_Owner);
00407         const uint32 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner,0) : _GenNb;                
00408         processEmit(index, quantity * nbToGenerate);
00409 }
00410 
00411 
00413 void CPSEmitter::processRegularEmission(TAnimationTime ellapsedTime)
00414 {
00415         nlassert(_Owner);
00416         const uint size = _Owner->getSize();
00417         uint leftToDo = size, toProcess;
00418         float emitPeriod[emitterBuffSize]; 
00419         float *currEmitPeriod;
00420         uint currEmitPeriodPtrInc = _PeriodScheme ? 1 : 0;                      
00421         sint32 nbToGenerate;
00422 
00423         TPSAttribTime::iterator phaseIt = _Phase.begin(), endPhaseIt; 
00424         TPSAttribUInt8::iterator numEmitIt = _NumEmission.begin(); 
00425 
00426         // we don't use an iterator here
00427         // because it could be invalidated if size change (a located could generate itself)     
00428         do
00429         {
00430                 toProcess = leftToDo < emitterBuffSize ? leftToDo : emitterBuffSize;
00431 
00432 
00433                 if (_PeriodScheme)
00434                 {
00435                         currEmitPeriod = (float *) (_PeriodScheme->make(_Owner, size - leftToDo, emitPeriod, sizeof(float), toProcess, true));                          
00436                 }
00437                 else
00438                 {
00439                         currEmitPeriod = &_Period;
00440                 }
00441 
00442                 endPhaseIt = phaseIt + toProcess;
00443 
00444                 if (_MaxEmissionCount == 0) // no emission count limit
00445                 {
00447                         if (_EmitDelay == 0.f) // no emission delay
00448                         {
00449                                 do                      
00450                                 {
00451                                         *phaseIt += ellapsedTime;
00452                                         if ( *phaseIt >= *currEmitPeriod) // phase is greater than period -> must emit
00453                                         {                                       
00454                                                 if (*currEmitPeriod != 0)
00455                                                 {
00456                                                         *phaseIt -= ::floorf(*phaseIt / *currEmitPeriod) * *currEmitPeriod;
00457                                                 }
00458                                                 const uint32 k = phaseIt - (_Phase.begin());
00459                                                 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, k) : _GenNb;                                    
00460                                                 processEmit(k, nbToGenerate);                                                                           
00461                                         }       
00462                                         
00463                                         ++phaseIt;
00464                                         currEmitPeriod += currEmitPeriodPtrInc;
00465                                 }
00466                                 while (phaseIt != endPhaseIt);
00467                         }
00468                         else // thhere's an emission delay
00469                         {
00470                                 do                      
00471                                 {
00472                                         *phaseIt += ellapsedTime;
00473                                         if ( *phaseIt >= *currEmitPeriod + _EmitDelay) // phase is greater than period -> must emit
00474                                         {
00475                                                 if (*currEmitPeriod != 0)
00476                                                 {
00477                                                         *phaseIt -= ::floorf((*phaseIt - _EmitDelay)  / *currEmitPeriod) * *currEmitPeriod;
00478                                                 }
00479                                                 const uint32 k = phaseIt - (_Phase.begin());
00480                                                 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, k) : _GenNb;                                    
00481                                                 processEmit(k, nbToGenerate);                                                                           
00482                                         }       
00483                                         
00484                                         ++phaseIt;
00485                                         currEmitPeriod += currEmitPeriodPtrInc;
00486                                 }
00487                                 while (phaseIt != endPhaseIt);
00488                         }
00489                 }
00490                 else // there's an emission count limit
00491                 {
00493                         if (_EmitDelay == 0.f) // no emission delay
00494                         {
00495                                 do                      
00496                                 {
00497                                         if (*numEmitIt < _MaxEmissionCount)
00498                                         {
00499                                                 *phaseIt += ellapsedTime;
00500                                                 if ( *phaseIt >= *currEmitPeriod) // phase is greater than period -> must emit
00501                                                 {
00502                                                         if (*currEmitPeriod != 0)
00503                                                         {
00504                                                                 *phaseIt -= ::floorf(*phaseIt / *currEmitPeriod) * *currEmitPeriod;
00505                                                         }
00506                                                         const uint32 k = phaseIt - (_Phase.begin());
00507                                                         nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, k) : _GenNb;                                    
00508                                                         processEmit(k, nbToGenerate);
00509                                                         ++*numEmitIt;
00510                                                 }       
00511                                         }       
00512                                         ++phaseIt;
00513                                         currEmitPeriod += currEmitPeriodPtrInc;                                                 
00514                                         ++ numEmitIt;
00515                                 }
00516                                 while (phaseIt != endPhaseIt);
00517                         }
00518                         else // there's an emission delay
00519                         {
00520                                 do                      
00521                                 {
00522                                         if (*numEmitIt < _MaxEmissionCount)
00523                                         {
00524                                                 *phaseIt += ellapsedTime;
00525                                                 if ( *phaseIt >= *currEmitPeriod + _EmitDelay) // phase is greater than period -> must emit
00526                                                 {
00527                                                         if (*currEmitPeriod != 0)
00528                                                         {
00529                                                                 *phaseIt -= ::floorf((*phaseIt - _EmitDelay) / *currEmitPeriod) * *currEmitPeriod;
00530                                                         }
00531                                                         const uint32 k = phaseIt - (_Phase.begin());
00532                                                         nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, k) : _GenNb;                                    
00533                                                         processEmit(k, nbToGenerate);
00534                                                         ++*numEmitIt;
00535                                                 }
00536                                         }                                                       
00537                                         ++phaseIt;
00538                                         currEmitPeriod += currEmitPeriodPtrInc;
00539                                         ++numEmitIt;
00540                                 }
00541                                 while (phaseIt != endPhaseIt);
00542                         }
00543                 }
00544 
00545                 leftToDo -= toProcess;
00546         }
00547         while (leftToDo);
00548 }
00549 
00551 //  depending on wether its motion is parametric or incremental. This is used to create emittees at the right position
00552 
00553 static inline uint GenEmitterPositions(CPSLocated *emitter,
00554                                                                            CPSLocated *emittee,
00555                                                                            uint emitterIndex,
00556                                                                            uint numStep,
00557                                                                            TAnimationTime deltaT, /* fraction of time needed to reach the first emission */
00558                                                                            TAnimationTime step,
00559                                                                            std::vector<NLMISC::CVector> &dest
00560                                                                           )
00561 {
00562         const uint toProcess = std::max(1U, std::min(numStep, (uint) emittee->getMaxSize()));   
00563         dest.resize(toProcess);
00564         
00565         
00566         if (!emitter->isParametricMotionEnabled()) // standard case : take current pos and integrate
00567         {
00568                 if (toProcess == 1) // only one emission -> takes current pos
00569                 {
00570                         dest[0] = emitter->getPos()[emitterIndex] - deltaT * emitter->getSpeed()[emitterIndex];
00571                 }
00572                 else
00573                 {
00574                         std::vector<NLMISC::CVector>::iterator outIt = dest.end();
00575                         std::vector<NLMISC::CVector>::iterator endIt = dest.begin();
00576                         NLMISC::CVector pos = emitter->getPos()[emitterIndex] - deltaT * emitter->getSpeed()[emitterIndex];
00577                         NLMISC::CVector speed = step * emitter->getSpeed()[emitterIndex];
00578                         do
00579                         {
00580                                 -- outIt;
00581                                 *outIt = pos;
00582                                 pos -= speed;                           
00583                         }
00584                         while (outIt != endIt);
00585                 }
00586         }
00587         else // compute parametric trajectory
00588         {
00589                 emitter->integrateSingle(emitter->getOwner()->getSystemDate() - deltaT - step * toProcess,
00590                                                                  step,
00591                                                                  toProcess,                                                                      
00592                                                                  emitterIndex,
00593                                                                  &dest[0]
00594                                                                 );                              
00595         }
00596         
00597         return toProcess;
00598 }
00599 
00601 void CPSEmitter::processRegularEmissionConsistent(TAnimationTime ellapsedTime, float realEllapsedTimeRatio)
00602 {
00604 
00605         static std::vector<NLMISC::CVector> emitterPositions; 
00606         // Positions for the emitter. They are computed by using a parametric trajectory or by using integration
00607 
00608         const uint size = _Owner->getSize();
00609         uint leftToDo = size, toProcess;
00610         float emitPeriod[emitterBuffSize]; 
00611         float *currEmitPeriod;
00612         uint currEmitPeriodPtrInc = _PeriodScheme ? 1 : 0;                      
00613         sint32 nbToGenerate;
00614 
00615 
00616         TPSAttribTime::iterator phaseIt = _Phase.begin(), endPhaseIt; 
00617         TPSAttribUInt8::iterator numEmitIt = _NumEmission.begin(); 
00618 
00619         // we don't use an iterator here
00620         // because it could be invalidated if size change (a located could generate itself)     
00621         do
00622         {
00623                 toProcess = leftToDo < emitterBuffSize ? leftToDo : emitterBuffSize;
00624 
00625 
00626                 if (_PeriodScheme)
00627                 {
00628                         currEmitPeriod = (float *) (_PeriodScheme->make(_Owner, size - leftToDo, emitPeriod, sizeof(float), toProcess, true));                          
00629                 }
00630                 else
00631                 {
00632                         currEmitPeriod = &_Period;
00633                 }
00634 
00635                 endPhaseIt = phaseIt + toProcess;
00636 
00637                 if (_MaxEmissionCount == 0) // no emission count limit
00638                 {
00640                         if (_EmitDelay == 0.f) // no emission delay
00641                         {
00642                                 do                      
00643                                 {
00644                                         *phaseIt += ellapsedTime;
00645                                         if ( *phaseIt >= *currEmitPeriod) // phase is greater than period -> must emit
00646                                         {                                                                       
00647                                                 if (*currEmitPeriod != 0)
00648                                                 {               
00651                                                         *phaseIt = std::min(*phaseIt, *currEmitPeriod + ellapsedTime);
00652                                                         //
00654                                                         uint numEmissions = (uint) ::floorf(*phaseIt / *currEmitPeriod);
00655                                                         *phaseIt -= *currEmitPeriod * numEmissions;
00656                                                         float deltaT = std::max(0.f, *phaseIt);
00657                                                         //nlassert(deltaT >= 0.f);
00658                                                         uint emitterIndex = phaseIt - _Phase.begin();
00659 
00661                                                         numEmissions = GenEmitterPositions(_Owner,
00662                                                                                                                                 _EmittedType,
00663                                                                                                                                 emitterIndex,
00664                                                                                                                                 numEmissions,
00665                                                                                                                                 deltaT,
00666                                                                                                                                 *currEmitPeriod,
00667                                                                                                                                 emitterPositions
00668                                                                                                                            );
00669 
00671                                                         nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00672                                                         uint k = numEmissions;                                                  
00673                                                         do
00674                                                         {       
00675                                                                 --k;
00676                                                                 processEmitConsistent(emitterPositions[k],
00677                                                                                                           emitterIndex,
00678                                                                                                           nbToGenerate,
00679                                                                                                           deltaT,
00680                                                                                                           ellapsedTime,
00681                                                                                                           realEllapsedTimeRatio);
00682                                                                 deltaT += *currEmitPeriod;                                                              
00683                                                         }
00684                                                         while (k);                                                                                                                                      
00685                                                 }
00686                                                 else
00687                                                 {
00688                                                         const uint32 emitterIndex = phaseIt - (_Phase.begin());
00689                                                         nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00690                                                         processEmit(emitterIndex, nbToGenerate);
00691                                                 }
00692                                         }       
00693                                         
00694                                         ++phaseIt;                                      
00695                                         currEmitPeriod += currEmitPeriodPtrInc;
00696                                 }
00697                                 while (phaseIt != endPhaseIt);
00698                         }
00699                         else // thhere's an emission delay
00700                         {
00701                                 do                      
00702                                 {
00703                                         *phaseIt += ellapsedTime;
00704                                         if ( *phaseIt >= *currEmitPeriod + _EmitDelay) // phase is greater than period -> must emit
00705                                         {                                               
00706                                                 if (*currEmitPeriod != 0)
00707                                                 {               
00710                                                         *phaseIt = std::min(*phaseIt, *currEmitPeriod + ellapsedTime + _EmitDelay);
00711                                                         //
00712                                                         uint numEmissions = (uint) ::floorf((*phaseIt - _EmitDelay) / *currEmitPeriod);
00713                                                         *phaseIt -= *currEmitPeriod * numEmissions;
00714                                                         float deltaT = std::max(*phaseIt - _EmitDelay, 0.f);
00715                                                         //nlassert(deltaT >= 0.f);
00716 
00717                                                         uint emitterIndex = phaseIt - _Phase.begin();
00719                                                         numEmissions = GenEmitterPositions(_Owner,
00720                                                                                         _EmittedType,
00721                                                                                                 emitterIndex,
00722                                                                                 numEmissions,
00723                                                                                                 deltaT,
00724                                                                                             *currEmitPeriod,
00725                                                                                             emitterPositions
00726                                                                                            );
00728                                                         nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;                                                 
00729                                                         uint k = numEmissions;                                                  
00730                                                         do
00731                                                         {       
00732                                                                 --k;
00733                                                                 processEmitConsistent(emitterPositions[k],
00734                                                                                                           emitterIndex,
00735                                                                                                           nbToGenerate,
00736                                                                                                           deltaT,
00737                                                                                                           ellapsedTime,
00738                                                                                                           realEllapsedTimeRatio);
00739                                                                 deltaT += *currEmitPeriod;                                                              
00740                                                         }
00741                                                         while (k);                                                                                                      
00742                                                 }
00743                                                 else
00744                                                 {               
00745                                                         const uint32 emitterIndex = phaseIt - (_Phase.begin());
00746                                                         nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00747                                                         processEmit(emitterIndex, nbToGenerate);                                                        
00748                                                 }                                                                       
00749                                         }       
00750                                         
00751                                         ++phaseIt;                                      
00752                                         currEmitPeriod += currEmitPeriodPtrInc;
00753                                 }
00754                                 while (phaseIt != endPhaseIt);
00755                         }
00756                 }
00757                 else // there's an emission count limit
00758                 {
00760                         if (_EmitDelay == 0.f) // no emission delay
00761                         {
00762                                 do                      
00763                                 {
00764                                         if (*numEmitIt < _MaxEmissionCount)
00765                                         {
00766                                                 *phaseIt += ellapsedTime;
00767                                                 if ( *phaseIt >= *currEmitPeriod) // phase is greater than period -> must emit
00768                                                 {
00769                                                         if (*currEmitPeriod != 0)
00770                                                         {
00773                                                                 *phaseIt = std::min(*phaseIt, *currEmitPeriod + ellapsedTime);
00774                                                                 //
00775                                                                 uint numEmissions = (uint) ::floorf(*phaseIt / *currEmitPeriod);
00776                                                                 *numEmitIt +=  numEmissions;                                                            
00777                                                                 *phaseIt -= *currEmitPeriod * numEmissions;
00778                                                                 float deltaT = std::max(*phaseIt, 0.f);
00779                                                                 //nlassert(deltaT >= 0.f);
00780                                                                 uint emitterIndex = phaseIt - _Phase.begin();
00781                                                                 if (*numEmitIt > _MaxEmissionCount) // make sure we don't go over the emission limit
00782                                                                 {
00783                                                                         numEmissions -= *numEmitIt - _MaxEmissionCount;
00784                                                                         *numEmitIt = _MaxEmissionCount;
00785                                                                 }
00787                                                                 numEmissions = GenEmitterPositions(_Owner,
00788                                                                                                         _EmittedType,
00789                                                                                                         emitterIndex,
00790                                                                                                         numEmissions,
00791                                                                                                         deltaT,
00792                                                                                                         *currEmitPeriod,
00793                                                                                                         emitterPositions
00794                                                                                                    );
00795                                                                 uint k = numEmissions;                                                          
00797                                                                 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;                                                         
00798                                                                 do
00799                                                                 {
00800                                                                         --k;
00801                                                                         processEmitConsistent(emitterPositions[k],
00802                                                                                                                   emitterIndex,
00803                                                                                                                   nbToGenerate,
00804                                                                                                                   deltaT,
00805                                                                                                                   ellapsedTime,
00806                                                                                                                   realEllapsedTimeRatio);
00807                                                                         deltaT += *currEmitPeriod;                                                                      
00808                                                                 }
00809                                                                 while (k);                                                                                                              
00810                                                         }
00811                                                         else
00812                                                         {
00813                                                                 const uint32 emitterIndex = phaseIt - _Phase.begin();
00814                                                                 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00815                                                                 processEmit(emitterIndex, nbToGenerate);                                                                
00816                                                                 ++*numEmitIt;
00817                                                         }
00818                                                 }       
00819                                         }       
00820                                         ++phaseIt;                                      
00821                                         currEmitPeriod += currEmitPeriodPtrInc;                                                 
00822                                         ++ numEmitIt;
00823                                 }
00824                                 while (phaseIt != endPhaseIt);
00825                         }
00826                         else // there's an emission delay
00827                         {
00828                                 do                      
00829                                 {
00830                                         if (*numEmitIt < _MaxEmissionCount)
00831                                         {
00832                                                 *phaseIt += ellapsedTime;
00833                                                 if ( *phaseIt >= *currEmitPeriod + _EmitDelay) // phase is greater than period -> must emit
00834                                                 {                                                       
00835                                                         if (*currEmitPeriod != 0)
00836                                                         {               
00839                                                                 *phaseIt = std::min(*phaseIt, *currEmitPeriod + ellapsedTime + _EmitDelay);
00840                                                                 //
00841                                                                 uint numEmissions = (uint) ::floorf((*phaseIt - _EmitDelay) / *currEmitPeriod);
00842                                                                 *numEmitIt +=  numEmissions;                                                            
00843                                                                 *phaseIt -= *currEmitPeriod * numEmissions;
00844                                                                 float deltaT = std::max(*phaseIt - _EmitDelay, 0.f);
00845                                                                 //nlassert(deltaT >= 0.f);
00846                                                                 uint emitterIndex = phaseIt - _Phase.begin();
00847                                                                 if (*numEmitIt > _MaxEmissionCount) // make sure we don't go over the emission limit
00848                                                                 {
00849                                                                         numEmissions -= *numEmitIt - _MaxEmissionCount;
00850                                                                         *numEmitIt = _MaxEmissionCount;
00851                                                                 }
00853                                                                 numEmissions = GenEmitterPositions(_Owner,
00854                                                                                                                                         _EmittedType,
00855                                                                                                                                         emitterIndex,
00856                                                                                                                                         numEmissions,
00857                                                                                                                                         deltaT,
00858                                                                                                                                         *currEmitPeriod,
00859                                                                                                                                         emitterPositions
00860                                                                                                                                    );
00861                                                                 uint k = numEmissions;                                                          
00863                                                                 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;                                                         
00864                                                                 do
00865                                                                 {       
00866                                                                         --k;
00867                                                                         processEmitConsistent(emitterPositions[k],
00868                                                                                                                   emitterIndex,
00869                                                                                                                   nbToGenerate,
00870                                                                                                                   deltaT,
00871                                                                                                                   ellapsedTime,
00872                                                                                                                   realEllapsedTimeRatio);
00873                                                                         deltaT += *currEmitPeriod;                                                                      
00874                                                                 }
00875                                                                 while (k);                                                              
00876                                                         }
00877                                                         else
00878                                                         {
00879                                                                 const uint32 emitterIndex = phaseIt - (_Phase.begin());
00880                                                                 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, emitterIndex) : _GenNb;
00881                                                                 processEmit(emitterIndex, nbToGenerate);                                                                
00882                                                                 ++*numEmitIt;
00883                                                         }
00884                                                 }
00885                                         }                                                       
00886                                         ++phaseIt;                                      
00887                                         currEmitPeriod += currEmitPeriodPtrInc;
00888                                         ++numEmitIt;
00889                                 }
00890                                 while (phaseIt != endPhaseIt);
00891                         }
00892                 }
00893 
00894                 leftToDo -= toProcess;
00895         }
00896         while (leftToDo);
00897 }
00898 
00900 void CPSEmitter::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEllapsedTime)
00901 {       
00902         if (pass == PSToolRender)
00903         {
00904                 showTool();
00905                 return;
00906         }
00907         if (pass != PSEmit || !_EmittedType) return;
00908         const uint32 size = _Owner->getSize();
00909         if (!size) return;
00910 
00911         if (ellapsedTime == 0.f) return; // do nothing when paused
00912 
00913         // our behaviour depend of the frequency
00914         switch (_EmissionType)
00915         {
00916                 case CPSEmitter::once :
00917                 {
00918                         TPSAttribTime::iterator timeIt = _Phase.begin()
00919                                                                                   , timeEndIt = _Phase.end();
00920 
00921                         while (timeIt != timeEndIt)
00922                         {
00923                                 if (*timeIt == 0.f)
00924                                 {
00925                                         const uint32 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, timeIt - _Phase.begin()) : _GenNb;         
00926                                         processEmit(timeIt - _Phase.begin(), nbToGenerate);             
00927                                         *timeIt = 1.f;
00928                                 }
00929                                 ++timeIt;
00930                         }                       
00931                 }
00932                 break;
00933                 case (CPSEmitter::regular):
00934                 {
00935                         if (!_ConsistentEmission)
00936                         {
00937                                 processRegularEmission(ellapsedTime);
00938                         }
00939                         else
00940                         {
00941                                 processRegularEmissionConsistent(ellapsedTime, realEllapsedTime / ellapsedTime);
00942                         }
00943                 }
00944                 break;  
00945                 default: break;
00946         }
00947 }
00948 
00950 void CPSEmitter::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00951 {       
00952         nlassert(_Phase.getSize() != _Phase.getMaxSize());      
00953 
00954         _Phase.insert(0.f);
00955         if (_MaxEmissionCount != 0)
00956         {
00957                 _NumEmission.insert(0); 
00958         }
00959         if (_PeriodScheme && _PeriodScheme->hasMemory()) _PeriodScheme->newElement(emitterLocated, emitterIndex);
00960         if (_GenNbScheme && _GenNbScheme->hasMemory()) _GenNbScheme->newElement(emitterLocated, emitterIndex);
00961 
00962 }
00963 
00965 void CPSEmitter::deleteElement(uint32 index)
00966 {       
00967 
00968         if (_EmissionType == CPSEmitter::onDeath && _EmittedType)
00969         {
00970                 const uint32 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, index) : _GenNb;           
00971                 processEmit(index, nbToGenerate);               
00972         }               
00973 
00974         if (_PeriodScheme && _PeriodScheme->hasMemory()) _PeriodScheme->deleteElement(index);
00975         if (_GenNbScheme && _GenNbScheme->hasMemory()) _GenNbScheme->deleteElement(index);
00976         _Phase.remove(index);
00977         if (_MaxEmissionCount != 0)
00978         {
00979                 _NumEmission.remove(index);
00980         }
00981 }
00982 
00984 void CPSEmitter::resize(uint32 size)
00985 {
00986         nlassert(size < (1 << 16));
00987         if (_PeriodScheme && _PeriodScheme->hasMemory()) _PeriodScheme->resize(size, _Owner->getSize());
00988         if (_GenNbScheme && _GenNbScheme->hasMemory()) _GenNbScheme->resize(size, _Owner->getSize());
00989         _Phase.resize(size);
00990         if (_MaxEmissionCount != 0)
00991         {
00992                 _NumEmission.resize(size);
00993         }
00994 }
00995 
00997 void CPSEmitter::bounceOccured(uint32 index)
00998 {
00999         // TODO : avoid duplication with deleteElement
01000         if (_EmissionType == CPSEmitter::onBounce)
01001         {
01002                 const uint32 nbToGenerate = _GenNbScheme ? _GenNbScheme->get(_Owner, index) : _GenNb;           
01003                 processEmit(index, nbToGenerate);
01004         }               
01005 }
01006 
01008 void CPSEmitter::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01009 {
01010 
01012         sint ver = f.serialVersion(4);  
01013         CPSLocatedBindable::serial(f);
01014         
01015         f.serialPolyPtr(_EmittedType);
01016         f.serial(_Phase);
01017         f.serial(_SpeedInheritanceFactor);
01018         f.serial(_SpeedBasisEmission);
01019         
01020         f.serialEnum(_EmissionType);
01021 
01022         // this is for use with serial
01023         bool trueB = true, falseB = false;
01024 
01025         if (!f.isReading())
01026         {
01027                 switch (_EmissionType)
01028                 {
01029                         case CPSEmitter::regular:                       
01030                                 if (_PeriodScheme)
01031                                 {
01032                                         f.serial(trueB);
01033                                         f.serialPolyPtr(_PeriodScheme);
01034                                 }
01035                                 else
01036                                 {
01037                                          f.serial(falseB);
01038                                          f.serial(_Period);
01039                                 }
01040                                 if (ver >= 3)
01041                                 {
01042                                         f.serial(_EmitDelay, _MaxEmissionCount);                                                                                                        
01043                                 }
01044                         break;
01045                         default:
01046                         break;
01047                 }
01048                 if (_GenNbScheme)
01049                 {
01050                         f.serial(trueB);
01051                         f.serialPolyPtr(_GenNbScheme);
01052                 }
01053                 else
01054                 {
01055                          f.serial(falseB);
01056                          f.serial(_GenNb);
01057                 }
01058         }
01059         else
01060         {
01061                 bool useScheme;
01062                 switch (_EmissionType)
01063                 {
01064                         case CPSEmitter::regular:
01065                         {                               
01066                                 f.serial(useScheme);
01067                                 if (useScheme)
01068                                 {
01069                                         delete _PeriodScheme;                                   
01070                                         f.serialPolyPtr(_PeriodScheme);
01071                                 }
01072                                 else
01073                                 {                                        
01074                                          f.serial(_Period);
01075                                 }
01076                                 if (ver >= 3)
01077                                 {
01078                                         f.serial(_EmitDelay, _MaxEmissionCount);
01079                                         updateMaxCountVect();
01080                                 }                               
01081                         }
01082                         break;
01083                         default:
01084                         break;
01085                 }
01086 
01087                 f.serial(useScheme); 
01088                 if (useScheme)
01089                 {
01090                         delete _GenNbScheme;
01091                         f.serialPolyPtr(_GenNbScheme);
01092                 }
01093                 else
01094                 {                               
01095                          f.serial(_GenNb);
01096                 }
01097         }
01098         if (ver > 1)
01099         {
01100                 f.serial(_EmitDirBasis);
01101         }
01102         if (ver >= 4)
01103         {
01104                 f.serial(_ConsistentEmission);
01105         }
01106 }
01107 
01109 void    CPSEmitter::updateMaxCountVect()
01110 {
01111         if (!_MaxEmissionCount)
01112         {
01113                 _NumEmission.resize(0);
01114         }
01115         else
01116         {
01117                 nlassert(_Owner);
01118                 _NumEmission.resize(_Owner->getMaxSize());
01119                 while (_NumEmission.getSize() != 0) 
01120                 {               
01121                         _NumEmission.remove(0);
01122                 }
01123                 while (_NumEmission.getSize() != _Owner->getSize())
01124                 {
01125                         _NumEmission.insert(0);
01126                 }               
01127         }
01128 }
01129 
01131 void    CPSEmitter::setMaxEmissionCount(uint8 count)
01132 {
01133         if (count == _MaxEmissionCount) return;
01134         _MaxEmissionCount = count;
01135         updateMaxCountVect();   
01136 }
01137 
01138 
01139 
01141 // implementation of CPSModulatedEmitter  //
01143 
01144 void CPSModulatedEmitter::serialEmitteeSpeedScheme(NLMISC::IStream &f) throw(NLMISC::EStream)
01145 {
01146         bool useScheme;                 
01147         if (!f.isReading())
01148         {
01149                 useScheme = useEmitteeSpeedScheme();
01150         }
01151         f.serial(useScheme);
01152         if (useScheme)
01153         {
01154                 f.serialPolyPtr(_EmitteeSpeedScheme);
01155         }
01156         else
01157         {
01158                 f.serial(_EmitteeSpeed);
01159         }
01160 }
01161 
01162 
01163 
01165 // implementation of CPSEmitterOmni               //
01167 
01169 void CPSEmitterOmni::emit(const NLMISC::CVector &srcPos, uint32 index, CVector &pos, CVector &speed)
01170 {
01171         // TODO : verifier que ca marche si une particule s'emet elle-mem
01172         nlassert(_EmittedType); 
01173         
01174         CVector v( ((rand() % 1000) - 500) / 500.0f
01175                                    , ((rand() % 1000) - 500) / 500.0f
01176                                    , ((rand() % 1000) - 500) / 500.0f);
01177         v.normalize();
01178         v *= _EmitteeSpeedScheme ? _EmitteeSpeedScheme->get(_Owner, index) : _EmitteeSpeed;             
01179 
01180         pos = srcPos;
01181         speed = v;      
01182 }
01183 
01185 void CPSEmitterOmni::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01186 {
01187         f.serialVersion(1);     
01188         CPSEmitter::serial(f);
01189         CPSModulatedEmitter::serialEmitteeSpeedScheme(f);
01190 }
01191 
01193 void CPSEmitterOmni::newElement(CPSLocated *emitter, uint32 emitterIndex)
01194 {
01195         CPSEmitter::newElement(emitter, emitterIndex);
01196         newEmitteeSpeedElement(emitter, emitterIndex);
01197 }
01198 
01200 void CPSEmitterOmni::deleteElement(uint32 index)
01201 {       
01202         CPSEmitter::deleteElement(index);
01203         deleteEmitteeSpeedElement(index);
01204 }
01205 
01207 void CPSEmitterOmni::resize(uint32 capacity)
01208 {
01209         nlassert(capacity < (1 << 16));
01210         CPSEmitter::resize(capacity);
01211         resizeEmitteeSpeed(capacity);
01212 }
01213 
01215 void CPSEmitterDirectionnal::emit(const NLMISC::CVector &srcPos, uint32 index, CVector &pos, CVector &speed)
01216 {
01217         // TODO : verifier que ca marche si une particule s'emet elle-mem
01218         nlassert(_EmittedType); 
01219         
01220 
01221         speed = (_EmitteeSpeedScheme ? _EmitteeSpeedScheme->get(_Owner, index) : _EmitteeSpeed) * _Dir;         
01222         pos = srcPos;   
01223 }
01224 
01226 void CPSEmitterDirectionnal::newElement(CPSLocated *emitter, uint32 emitterIndex)
01227 {
01228         CPSEmitter::newElement(emitter, emitterIndex);
01229         newEmitteeSpeedElement(emitter, emitterIndex);
01230 }
01231 
01233 void CPSEmitterDirectionnal::deleteElement(uint32 index)
01234 {       
01235         CPSEmitter::deleteElement(index);
01236         deleteEmitteeSpeedElement(index);
01237 }
01238 
01240 void CPSEmitterDirectionnal::resize(uint32 capacity)
01241 {
01242         nlassert(capacity < (1 << 16));
01243         CPSEmitter::resize(capacity);
01244         resizeEmitteeSpeed(capacity);
01245 }
01246 
01248 void CPSEmitterDirectionnal::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01249 {
01250         f.serialVersion(1);     
01251         CPSEmitter::serial(f);
01252         CPSModulatedEmitter::serialEmitteeSpeedScheme(f);
01253         f.serial(_Dir);
01254 }
01255 
01257 // implementation of CPSEmitterRectangle  //
01259 
01261 void CPSEmitterRectangle::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01262 {
01263         f.serialVersion(1);     
01264         CPSEmitter::serial(f);
01265         CPSModulatedEmitter::serialEmitteeSpeedScheme(f);
01266         f.serial(_Basis);       
01267         f.serial(_Width);
01268         f.serial(_Height);
01269         f.serial(_Dir);
01270 
01271 }
01272 
01274 void CPSEmitterRectangle::emit(const NLMISC::CVector &srcPos, uint32 index, CVector &pos, CVector &speed)
01275 {
01276         CVector N = _Basis[index].X ^ _Basis[index].Y;
01277         pos = srcPos + ((rand() % 32000) * (1.f / 16000) - 1.f) *  _Width[index] *  _Basis[index].X 
01278                                  + ((rand() % 32000) * (1.f / 16000) - 1.f) *  _Height[index] * _Basis[index].Y;
01279         speed = (_EmitteeSpeedScheme ? _EmitteeSpeedScheme->get(_Owner, index) : _EmitteeSpeed) 
01280                                         * (_Dir.x * _Basis[index].X+ _Dir.y * _Basis[index].Y + _Dir.z *  N);
01281 }
01282 
01284 void CPSEmitterRectangle::setMatrix(uint32 index, const CMatrix &m)
01285 {
01286         _Owner->getPos()[index] = m.getPos();
01287 
01288         
01289          _Basis[index].X = m.getI();
01290          _Basis[index].Y = m.getJ();
01291 }
01292 
01294 CMatrix CPSEmitterRectangle::getMatrix(uint32 index) const
01295 {
01296         CMatrix m;
01297         m.setPos(_Owner->getPos()[index]);
01298         m.setRot(_Basis[index].X, _Basis[index].Y, _Basis[index].X ^ _Basis[index].Y, true);
01299         return m;
01300 }
01301 
01303 void CPSEmitterRectangle::setScale(uint32 index, float scale)
01304 {
01305         _Width[index] = scale;
01306         _Height[index] = scale;
01307 }
01308 
01310 void CPSEmitterRectangle::setScale(uint32 index, const CVector &s)
01311 {
01312         _Width[index] = s.x;
01313         _Height[index] = s.y;
01314 }
01315 
01317 CVector CPSEmitterRectangle::getScale(uint32 index) const
01318 {       
01319         return CVector(_Width[index], _Height[index], 1.f); 
01320 }
01321 
01323                 void CPSEmitterRectangle::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
01324 {
01325         CPSEmitter::newElement(emitterLocated, emitterIndex);
01326         newEmitteeSpeedElement(emitterLocated, emitterIndex);
01327         _Basis.insert(CPlaneBasis(CVector::K));
01328         _Width.insert(1.f);
01329         _Height.insert(1.f);
01330 }
01331 
01333 void CPSEmitterRectangle::deleteElement(uint32 index)
01334 {
01335         CPSEmitter::deleteElement(index);
01336         deleteEmitteeSpeedElement(index);
01337         _Basis.remove(index);
01338         _Width.remove(index);
01339         _Height.remove(index);
01340 }
01341 
01343 void CPSEmitterRectangle::resize(uint32 size)
01344 {
01345         nlassert(size < (1 << 16));
01346         CPSEmitter::resize(size);
01347         resizeEmitteeSpeed(size);
01348         _Basis.resize(size);
01349         _Width.resize(size);
01350         _Height.resize(size);
01351 }
01352 
01354 void CPSEmitterRectangle::showTool(void)
01355 {
01356         nlassert(_Owner);
01357         const uint size = _Owner->getSize();
01358         if (!size) return;
01359         setupDriverModelMatrix();       
01360         CMatrix mat;
01361         
01362         CPSLocated *loc;
01363         uint32 index;
01364         CPSLocatedBindable *lb;
01365         _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
01366 
01367         for (uint k = 0; k < size; ++k) 
01368         {       
01369                 const CVector &I = _Basis[k].X;
01370                 const CVector &J = _Basis[k].Y;
01371                 mat.setRot(I, J , I ^J);
01372                 mat.setPos(_Owner->getPos()[k]);
01373                 CPSUtil::displayBasis(getDriver() ,getLocatedMat(), mat, 1.f, *getFontGenerator(), *getFontManager());                          
01374                 setupDriverModelMatrix();       
01375 
01376                 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k  ? CRGBA::Red : CRGBA(127, 127, 127));
01377         
01378 
01379 
01380                 const CVector &pos = _Owner->getPos()[k];
01381                 CPSUtil::display3DQuad(*getDriver(), pos + I * _Width[k] + J * _Height[k]
01382                                                                                    , pos + I * _Width[k] - J * _Height[k]
01383                                                                                    , pos - I * _Width[k] - J * _Height[k]
01384                                                                                    , pos - I * _Width[k] + J * _Height[k], col);
01385         }
01386 }
01387 
01388 
01389 
01391 // CPSEmitterconic implementation //
01393 
01395 void CPSEmitterConic::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01396 {
01397         f.serialVersion(1);     
01398         CPSEmitterDirectionnal::serial(f);
01399         f.serial(_Radius);      
01400 }
01401         
01403 void CPSEmitterConic::setDir(const CVector &v)
01404 {
01405         CPSEmitterDirectionnal::setDir(v);
01406         
01407 }
01408 
01410 void CPSEmitterConic::emit(const NLMISC::CVector &srcPos, uint32 index, CVector &pos, CVector &speed)
01411 {
01412         // TODO : optimize that
01413         nlassert(_EmittedType); 
01414         
01415         // we choose a custom direction like with omnidirectionnal emitter
01416         // then we force the direction vect to have the unit size
01417 
01418         static const double divRand = (2.0 / RAND_MAX);
01419 
01420         CVector dir((float) (rand() * divRand - 1)
01421                                 , (float) (rand() * divRand - 1)
01422                                 , (float) (rand() * divRand - 1) );
01423 
01424         const float n =dir.norm();
01425 
01426         dir *= _Radius / n;
01427 
01428         dir -= (_Dir * dir) * _Dir;
01429         dir += _Dir;
01430         dir.normalize();
01431         
01432         
01433         speed = (_EmitteeSpeedScheme ? _EmitteeSpeedScheme->get(_Owner, index) : _EmitteeSpeed) 
01434                     * dir;
01435         pos = srcPos;   
01436 }
01437 
01439 // CPSSphericalEmitter implementation //
01441 
01443 void CPSSphericalEmitter::emit(const NLMISC::CVector &srcPos, uint32 index, CVector &pos, CVector &speed)
01444 {
01445         static const double divRand = (2.0 / RAND_MAX);
01446         CVector dir((float) (rand() * divRand - 1), (float) (rand() * divRand - 1) , (float) (rand() * divRand - 1) );
01447         dir.normalize();
01448         pos = srcPos + _Radius[index] * dir;
01449         speed = (_EmitteeSpeedScheme ? _EmitteeSpeedScheme->get(_Owner, index) : _EmitteeSpeed)  * dir; 
01450 }
01451 
01452 
01454 void CPSSphericalEmitter::showTool(void)
01455 {
01456         CPSLocated *loc;
01457         uint32 index;
01458         CPSLocatedBindable *lb;
01459         _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
01460 
01461 
01462         TPSAttribFloat::const_iterator radiusIt = _Radius.begin();
01463         TPSAttribVector::const_iterator posIt = _Owner->getPos().begin(), endPosIt = _Owner->getPos().end();
01464         setupDriverModelMatrix();       
01465         for (uint k = 0; posIt != endPosIt; ++posIt, ++radiusIt, ++k) 
01466         {       
01467                 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k  ? CRGBA::Red : CRGBA(127, 127, 127));             
01468                 CPSUtil::displaySphere(*getDriver(), *radiusIt, *posIt, 5, col);
01469         }
01470 }
01471 
01472 
01474 void CPSSphericalEmitter::setMatrix(uint32 index, const CMatrix &m)
01475 {
01476         nlassert(index < _Radius.getSize());            
01477         // compute new pos
01478         _Owner->getPos()[index] = m.getPos();
01479         
01480 }
01481 
01483 CMatrix CPSSphericalEmitter::getMatrix(uint32 index) const
01484 {
01485         nlassert(index < _Radius.getSize());
01486         CMatrix m;
01487         m.identity();
01488         m.translate(_Owner->getPos()[index]);   
01489         return m; 
01490 }
01491                 
01493 void CPSSphericalEmitter::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01494 {
01495         f.serialVersion(1);     
01496         CPSEmitter::serial(f);
01497         CPSModulatedEmitter::serialEmitteeSpeedScheme(f);
01498         f.serial(_Radius);
01499 }
01500                 
01502 void CPSSphericalEmitter::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
01503 {
01504         CPSEmitter::newElement(emitterLocated, emitterIndex);
01505         newEmitteeSpeedElement(emitterLocated, emitterIndex);   
01506         _Radius.insert(1.f);
01507 }
01508 
01510 void CPSSphericalEmitter::deleteElement(uint32 index)
01511 {
01512         CPSEmitter::deleteElement(index);
01513         deleteEmitteeSpeedElement(index);       
01514         _Radius.remove(index);
01515 }
01516 
01518 void CPSSphericalEmitter::resize(uint32 size)
01519 {
01520         nlassert(size < (1 << 16));
01521         CPSEmitter::resize(size);
01522         resizeEmitteeSpeed(size);       
01523         _Radius.resize(size);
01524 }
01525 
01527 // CPSRadialEmitter implementation //
01529 
01531 void CPSRadialEmitter::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01532 {
01533         f.serialVersion(1);
01534         CPSEmitterDirectionnal::serial(f);
01535 }
01536 
01538 void CPSRadialEmitter::emit(const NLMISC::CVector &srcPos, uint32 index, NLMISC::CVector &pos, NLMISC::CVector &speed)
01539 {
01540         // TODO : verifier que ca marche si une particule s'emet elle-mem
01541         nlassert(_EmittedType); 
01542 
01543         static const double divRand = (2.0 / RAND_MAX);
01544         CVector dir((float) (rand() * divRand - 1)
01545                                 , (float) (rand() * divRand - 1)
01546                                 , (float) (rand() * divRand - 1) );
01547         dir -= (dir * _Dir) * _Dir; //keep tangential direction
01548         dir.normalize();
01549         
01550         speed = (_EmitteeSpeedScheme ? _EmitteeSpeedScheme->get(_Owner, index) : _EmitteeSpeed) * dir;          
01551         pos = srcPos;
01552 }
01553 
01554 
01555 
01556 } // NL3D