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

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "std3d.h"
00027 
00028 #include "3d/ps_force.h"
00029 #include "3d/driver.h"
00030 #include "3d/primitive_block.h"
00031 #include "3d/material.h"
00032 #include "3d/vertex_buffer.h"
00033 #include "3d/computed_string.h"
00034 #include "3d/font_manager.h"
00035 #include "3d/particle_system.h"
00036 #include "nel/misc/common.h"
00037 #include "3d/ps_util.h"
00038 #include "3d/ps_misc.h"
00039 
00040 namespace NL3D {
00041 
00042 
00043 /*
00044  * Constructor
00045  */
00046 CPSForce::CPSForce()
00047 {
00048 }
00049 
00050 
00051 
00052 void CPSForce::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00053 {
00054         
00055                 f.serialVersion(1);     
00056                 CPSTargetLocatedBindable::serial(f);    
00057                 CPSLocatedBindable::serial(f);
00058         
00059 }
00060 
00061 
00062 void CPSForce::registerToTargets(void)
00063 {
00064         for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00065         {
00066                 if (this->isIntegrable())
00067                 {                                               
00068                         (*it)->registerIntegrableForce(this);
00069                 }
00070                 else
00071                 {
00072                         (*it)->addNonIntegrableForceRef();
00073                 }
00074         }
00075 }
00076 
00077 
00078 void CPSForce::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEllapsedTime)
00079 {
00080         switch(pass)
00081         {
00082                 case PSMotion:
00083                         performDynamic(ellapsedTime);
00084                         break;
00085                 case PSToolRender:
00086                         show(ellapsedTime);
00087                         break;
00088                 default: break;
00089         }
00090 }
00091 
00092 
00093 
00094 void    CPSForce::attachTarget(CPSLocated *ptr)
00095 {
00096         nlassert(_Owner);       
00097         CPSTargetLocatedBindable::attachTarget(ptr);
00098         // check wether we are integrable, and if so, add us to the list
00099         if (this->isIntegrable())
00100         {
00101                 ptr->registerIntegrableForce(this);
00102         }
00103         else
00104         {
00105                 ptr->addNonIntegrableForceRef();
00106         }
00107 }
00108 
00109 void    CPSForce::releaseTargetRsc(CPSLocated *target)
00110 {
00111         if (this->isIntegrable())
00112         {
00113                 target->unregisterIntegrableForce(this);
00114         }
00115         else
00116         {
00117                 target->releaseNonIntegrableForceRef();
00118         }       
00119 }
00120 
00121 
00122 
00123 void    CPSForce::basisChanged(bool systemBasis)
00124 {
00125         if (!this->isIntegrable()) return;
00126         for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00127         {       
00128                 (*it)->integrableForceBasisChanged(systemBasis);
00129         }               
00130 }
00131 
00132 
00133 void    CPSForce::cancelIntegrable(void)
00134 {
00135         nlassert(_Owner);
00136         bool useSystemBasis = _Owner->isInSystemBasis();
00137         for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00138         {
00139                 if ((*it)->isInSystemBasis() == useSystemBasis)
00140                 {
00141                         (*it)->unregisterIntegrableForce(this);
00142                         (*it)->addNonIntegrableForceRef();
00143                 }
00144         }
00145 }
00146 
00147 
00148 void    CPSForce::renewIntegrable(void)
00149 {
00150         nlassert(_Owner);
00151         bool useSystemBasis = _Owner->isInSystemBasis();
00152         for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00153         {
00154                 if ((*it)->isInSystemBasis() == useSystemBasis)
00155                 {
00156                         (*it)->registerIntegrableForce(this);
00157                         (*it)->releaseNonIntegrableForceRef();
00158                 }
00159         }
00160 }
00161 
00162 
00163 
00165 //  CPSForceIntensity implementation //
00167 
00168 void CPSForceIntensity::setIntensity(float value)
00169 {
00170         if (_IntensityScheme)
00171         {
00172                 delete _IntensityScheme;
00173                 _IntensityScheme = NULL;
00174         }
00175         _K = value;
00176         
00177 }
00178 
00179 CPSForceIntensity::~CPSForceIntensity()
00180 {
00181         delete _IntensityScheme;
00182 }
00183 
00184 void CPSForceIntensity::setIntensityScheme(CPSAttribMaker<float> *scheme)
00185 {
00186         nlassert(scheme);
00187         delete _IntensityScheme;
00188         _IntensityScheme = scheme;
00189         if (getForceIntensityOwner() && scheme->hasMemory()) scheme->resize(getForceIntensityOwner()->getMaxSize(), getForceIntensityOwner()->getSize());
00190 }
00191 
00192 void CPSForceIntensity::serialForceIntensity(NLMISC::IStream &f) throw(NLMISC::EStream)
00193 {       
00194         f.serialVersion(1);
00195         if (!f.isReading())
00196         {
00197                 if (_IntensityScheme)
00198                 {
00199                         bool bFalse = false;
00200                         f.serial(bFalse);
00201                         f.serialPolyPtr(_IntensityScheme);
00202                 }
00203                 else
00204                 {
00205                         bool bTrue = true;
00206                         f.serial(bTrue);
00207                         f.serial(_K);
00208                 }
00209         }
00210         else
00211         {
00212                 bool constantIntensity;
00213                 f.serial(constantIntensity);
00214                 if (constantIntensity)
00215                 {
00216                         f.serial(_K);
00217                 }
00218                 else
00219                 {
00220                         f.serialPolyPtr(_IntensityScheme);
00221                 }
00222         }       
00223 }
00224 
00225 
00227 // CPSForceIntensityHelper            //
00229 
00230 
00231 void CPSForceIntensityHelper::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00232 {
00233         f.serialVersion(1);
00234         CPSForce::serial(f);
00235         serialForceIntensity(f);
00236         if (f.isReading())
00237         {
00238                 registerToTargets();
00239         }
00240 }
00241 
00242 
00243 
00245 // CPSDirectionalForce implementation //
00247 
00248 
00249 void CPSDirectionnalForce::performDynamic(TAnimationTime ellapsedTime)
00250 {
00251         // perform the operation on each target
00252         CVector toAdd;
00253         for (uint32 k = 0; k < _Owner->getSize(); ++k)
00254         {       
00255                 CVector toAddLocal;
00256                 CVector dir;
00257                 
00258                 if (_GlobalValueHandle.isValid()) // is direction a global variable ?
00259                 {               
00260                         dir = _GlobalValueHandle.get(); // takes direction from global variable instead                 
00261                 }
00262                 else
00263                 {
00264                         dir = _Dir;
00265                 }
00266                 
00267                 toAddLocal = ellapsedTime * (_IntensityScheme ? _IntensityScheme->get(_Owner, k) : _K ) * dir;                  
00268                 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00269                 {
00270 
00271                         toAdd = CPSLocated::getConversionMatrix(*it, this->_Owner).mulVector(toAddLocal); // express this in the target basis
00272                         TPSAttribVector::iterator it2 = (*it)->getSpeed().begin(), it2end = (*it)->getSpeed().end();
00273                         // 1st case : non-constant mass
00274                         if ((*it)->getMassScheme())
00275                         {
00276                                 TPSAttribFloat::const_iterator invMassIt = (*it)->getInvMass().begin();                 
00277                                 for (; it2 != it2end; ++it2, ++invMassIt)
00278                                 {
00279                                         (*it2) += *invMassIt * toAdd;                           
00280                                         
00281                                 }
00282                         }
00283                         else
00284                         {
00285                                 // the mass is constant
00286                                 toAdd /= (*it)->getInitialMass();
00287                                 for (; it2 != it2end; ++it2)
00288                                 {
00289                                         (*it2) += toAdd;                                                                        
00290                                 }
00291                         }
00292                 }
00293         }
00294 }
00295 
00296 
00297 void CPSDirectionnalForce::show(TAnimationTime ellapsedTime)
00298 {
00299         CPSLocated *loc;
00300         uint32 index;
00301         CPSLocatedBindable *lb;
00302         _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00303 
00304         setupDriverModelMatrix();
00305 
00306         CVector dir;            
00307         if (_GlobalValueHandle.isValid()) // is direction a global variable ?
00308         {               
00309                 dir = _GlobalValueHandle.get(); // takes direction from global variable instead                 
00310         }
00311         else
00312         {
00313                 dir = _Dir;
00314         }
00315         
00316         // for each element, see if it is the selected element, and if yes, display in red
00317         for (uint k = 0; k < _Owner->getSize(); ++k)
00318         {
00319                 const CRGBA col = (((lb == NULL || this == lb) && loc == _Owner && index == k)  ? CRGBA::Red : CRGBA(127, 127, 127));
00320                 CPSUtil::displayArrow(getDriver(), _Owner->getPos()[k], dir, 1.f, col, CRGBA(80, 80, 0));
00321         }
00322 }
00323 
00324 void CPSDirectionnalForce::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00325 {
00326         // Version 2 : added link to a global vector value
00327         //
00328         sint ver = f.serialVersion(2);          
00329         CPSForceIntensityHelper::serial(f);     
00330         if (ver == 1)
00331         {       
00332                 f.serial(_Dir);
00333                 _GlobalValueHandle.reset();
00334         }
00335         else
00336         {
00337                 bool useHandle = _GlobalValueHandle.isValid();
00338                 f.serial(useHandle);
00339                 if (useHandle)
00340                 {
00341                         // a global value is used
00342                         if (f.isReading())
00343                         {
00344                                 std::string handleName;
00345                                 f.serial(handleName);
00346                                 // retrieve a handle to the global value from the particle system
00347                                 _GlobalValueHandle = CParticleSystem::getGlobalVectorValueHandle(handleName);
00348                         }
00349                         else
00350                         {
00351                                 std::string handleName = _GlobalValueHandle.getName();
00352                                 f.serial(handleName);
00353                         }
00354                 }
00355                 else
00356                 {
00357                         f.serial(_Dir);
00358                 }
00359         }
00360 }
00361 
00362 void CPSDirectionnalForce::enableGlobalVectorValue(const std::string &name)
00363 {
00364         if (name.empty())
00365         {
00366                 _GlobalValueHandle.reset();
00367                 return;
00368         }
00369         _GlobalValueHandle = CParticleSystem::getGlobalVectorValueHandle(name);
00370 }
00371 
00372 std::string CPSDirectionnalForce::getGlobalVectorValueName() const
00373 {
00374         return _GlobalValueHandle.isValid() ? _GlobalValueHandle.getName() : "";
00375 }
00376 
00378 // gravity implementation //
00380 
00381 
00382 void CPSGravity::performDynamic(TAnimationTime ellapsedTime)
00383 {       
00384         
00385         // perform the operation on each target
00386         CVector toAdd;
00387         for (uint32 k = 0; k < _Owner->getSize(); ++k)
00388         {       
00389                 CVector toAddLocal = ellapsedTime * CVector(0, 0, _IntensityScheme ? - _IntensityScheme->get(_Owner, k) : - _K);
00390                 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00391                 {
00392                         toAdd = CPSLocated::getConversionMatrix(*it, this->_Owner).mulVector(toAddLocal); // express this in the target basis
00393                         TPSAttribVector::iterator it2 = (*it)->getSpeed().begin(), it2end = (*it)->getSpeed().end();
00394                         
00395                         if (toAdd.x && toAdd.y)
00396                         {
00397                                 for (; it2 != it2end; ++it2)
00398                                 {
00399                                         (*it2) += toAdd;                                
00400                                         
00401                                 }
00402                         }
00403                         else // only the z component is not null, which should be the majority of cases ...
00404                         {
00405                                 for (; it2 != it2end; ++it2)
00406                                 {
00407                                         it2->z += toAdd.z;                              
00408                                         
00409                                 }
00410                         }
00411                 }
00412         }
00413 }
00414 
00415 void CPSGravity::show(TAnimationTime ellapsedTime) 
00416 {       
00417         CVector I = computeI();
00418         CVector K = CVector(0,0,1);         
00419 
00420         // this is not designed for efficiency (target : edition code)
00421         CPrimitiveBlock  pb;
00422         CVertexBuffer vb;
00423         CMaterial material;
00424         IDriver *driver = getDriver();
00425         const float toolSize = 0.2f;
00426 
00427         vb.setVertexFormat(CVertexBuffer::PositionFlag);
00428         vb.setNumVertices(6);
00429         vb.setVertexCoord(0, -toolSize * I);
00430         vb.setVertexCoord(1, toolSize * I);
00431         vb.setVertexCoord(2, CVector(0, 0, 0));
00432         vb.setVertexCoord(3, -6.0f * toolSize * K);
00433         vb.setVertexCoord(4, -toolSize * I  - 5.0f * toolSize * K);
00434         vb.setVertexCoord(5, toolSize * I - 5.0f * toolSize * K);
00435 
00436         pb.reserveLine(4);
00437         pb.addLine(0, 1);
00438         pb.addLine(2, 3);
00439         pb.addLine(4, 3);
00440         pb.addLine(3, 5);       
00441         
00442         material.setColor(CRGBA(127, 127, 127));
00443         material.setLighting(false);
00444         material.setBlendFunc(CMaterial::one, CMaterial::one);
00445         material.setZWrite(false);
00446         material.setBlend(true);
00447 
00448         
00449         CMatrix mat;
00450 
00451         for (TPSAttribVector::const_iterator it = _Owner->getPos().begin(); it != _Owner->getPos().end(); ++it)
00452         {
00453                 mat.identity();
00454                 mat.translate(*it);
00455                 if (_Owner->isInSystemBasis())
00456                 {
00457                         mat = getSysMat() * mat;
00458                 }
00459                 
00460                 driver->setupModelMatrix(mat);
00461                 driver->activeVertexBuffer(vb);
00462                 driver->render(pb, material);
00463         
00464 
00465 
00466                 // affiche un g a cote de la force
00467 
00468                 CVector pos = *it + CVector(1.5f * toolSize, 0, -1.2f * toolSize);
00469 
00470                 if (_Owner->isInSystemBasis())
00471                 {
00472                         pos = getSysMat() * pos;
00473                 }
00474 
00475                 // must have set this
00476                 nlassert(getFontGenerator() && getFontGenerator());
00477                 
00478                 CPSUtil::print(driver, std::string("G")
00479                                                         , *getFontGenerator()
00480                                                         , *getFontManager()
00481                                                         , pos
00482                                                         , 80.0f * toolSize );                                                           
00483         }
00484 
00485         
00486 }
00487 
00488 void CPSGravity::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00489 {
00490         f.serialVersion(1);     
00491         CPSForceIntensityHelper::serial(f);     
00492 }
00493 
00494 
00495 bool    CPSGravity::isIntegrable(void) const
00496 {
00497         return _IntensityScheme == NULL;
00498 }
00499 
00500 void CPSGravity::integrate(float date, CPSLocated *src, uint32 startIndex, uint32 numObjects, NLMISC::CVector *destPos, NLMISC::CVector *destSpeed,
00501                                                         bool accumulate,
00502                                                         uint posStride, uint speedStride
00503                                                         )
00504 {
00505         #define NEXT_SPEED destSpeed = (NLMISC::CVector *) ((uint8 *) destSpeed + speedStride);
00506         #define NEXT_POS   destPos   = (NLMISC::CVector *) ((uint8 *) destPos   + posStride);
00507 
00508         float deltaT;
00509 
00510         if (!destPos && !destSpeed) return;
00511 
00512         CPSLocated::TPSAttribParametricInfo::const_iterator it = src->_PInfo.begin() + startIndex,
00513                                                                                                                 endIt = src->_PInfo.begin() + startIndex + numObjects;  
00514         if (!accumulate) // compute coords from initial condition, and applying this force
00515         {
00516                 if (destPos && !destSpeed) // fills dest pos only
00517                 {
00518                         while (it != endIt)
00519                         {
00520                                 deltaT = date - it->Date;                               
00521                                 destPos->x = it->Pos.x + deltaT * it->Speed.x;                          
00522                                 destPos->y = it->Pos.y + deltaT * it->Speed.y;
00523                                 destPos->z = it->Pos.z + deltaT * it->Speed.z - 0.5f * deltaT * deltaT * _K;
00524                                 ++it;
00525                                 NEXT_POS;       
00526                         }
00527                 }
00528                 else if (!destPos && destSpeed) // fills dest speed only
00529                 {
00530                         while (it != endIt)
00531                         {
00532                                 deltaT = date - it->Date;                               
00533                                 destSpeed->x = it->Speed.x;                             
00534                                 destSpeed->y = it->Speed.y;
00535                                 destSpeed->z = it->Speed.z - deltaT * _K;
00536                                 ++it;
00537                                 NEXT_SPEED;     
00538                         }
00539                 }
00540                 else // fills both speed and pos
00541                 {
00542                         while (it != endIt)
00543                         {
00544                                 deltaT = date - it->Date;                               
00545                                 destPos->x = it->Pos.x + deltaT * it->Speed.x;                          
00546                                 destPos->y = it->Pos.y + deltaT * it->Speed.y;
00547                                 destPos->z = it->Pos.z + deltaT * it->Speed.z - 0.5f * deltaT * deltaT * _K;
00548 
00549                                 destSpeed->x = it->Speed.x;                             
00550                                 destSpeed->y = it->Speed.y;
00551                                 destSpeed->z = it->Speed.z - deltaT * _K;
00552 
00553                                 ++it;
00554                                 NEXT_POS;
00555                                 NEXT_SPEED;
00556                         }
00557                 }
00558         }
00559         else // accumulate datas
00560         {
00561                 if (destPos && !destSpeed) // fills dest pos only
00562                 {
00563                         while (it != endIt)
00564                         {
00565                                 deltaT = date - it->Date;                                                               
00566                                 destPos->z -= 0.5f * deltaT * deltaT * _K;                              
00567                                 ++it;
00568                                 NEXT_POS;       
00569                         }
00570                 }
00571                 else if (!destPos && destSpeed) // fills dest speed only
00572                 {
00573                         while (it != endIt)
00574                         {
00575                                 deltaT = date - it->Date;                                                               
00576                                 destSpeed->z -= deltaT * _K;                            
00577                                 ++it;
00578                                 NEXT_SPEED;     
00579                         }
00580                 }
00581                 else // fills both speed and pos
00582                 {
00583                         while (it != endIt)
00584                         {
00585                                 deltaT = date - it->Date;                                                               
00586                                 destPos->z -= 0.5f * deltaT * deltaT * _K;
00587                                 destSpeed->z -= deltaT * _K;
00588                                 ++it;
00589                                 NEXT_POS;
00590                                 NEXT_SPEED;
00591                         }
00592                 }
00593         }
00594         
00595 }
00596 
00597 
00598 
00599 void CPSGravity::integrateSingle(float startDate, float deltaT, uint numStep,                                                            
00600                                                                  CPSLocated *src, uint32 indexInLocated,
00601                                                                  NLMISC::CVector *destPos,
00602                                                                  bool accumulate /*= false*/,
00603                                                                  uint stride/* = sizeof(NLMISC::CVector)*/)
00604 {               
00605         nlassert(src->isParametricMotionEnabled());
00606         nlassert(deltaT > 0);
00607         nlassert(numStep > 0);
00608         #ifdef NL_DEBUG
00609                 NLMISC::CVector *endPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride * numStep);
00610         #endif
00611         const CPSLocated::CParametricInfo &pi = src->_PInfo[indexInLocated];
00612         const NLMISC::CVector &startPos   = pi.Pos;     
00613         if (numStep != 0)
00614         {
00615                 if (!accumulate)
00616                 {                               
00617                         destPos = FillBufUsingSubdiv(startPos, pi.Date, startDate, deltaT, numStep, destPos, stride);
00618                         if (numStep != 0)
00619                         {
00620                                 float currDate = startDate - pi.Date;
00621                                 nlassert(currDate >= 0);
00622                                 const NLMISC::CVector &startSpeed = pi.Speed;                   
00623                                 do
00624                                 {
00625                                         #ifdef NL_DEBUG
00626                                                 nlassert(destPos < endPos);
00627                                         #endif
00628                                         float halfTimeSquare  = 0.5f * currDate * currDate;
00629                                         destPos->x = startPos.x + currDate * startSpeed.x;
00630                                         destPos->y = startPos.y + currDate * startSpeed.y;
00631                                         destPos->z = startPos.z + currDate * startSpeed.z - _K * halfTimeSquare;
00632                                         currDate += deltaT;
00633                                         destPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride);
00634                                 }
00635                                 while (--numStep);
00636                         }
00637                 }
00638                 else
00639                 {
00640                         uint numToSkip = ScaleFloatGE(startDate, deltaT, pi.Date, numStep);             
00641                         if (numToSkip < numStep)
00642                         {
00643                                 numStep -= numToSkip;
00644                                 float currDate = startDate + deltaT * numToSkip - pi.Date;
00645                                 do
00646                                 {
00647                                         #ifdef NL_DEBUG
00648                                                 nlassert(destPos < endPos);
00649                                         #endif
00650                                         float halfTimeSquare  = 0.5f * currDate * currDate;                             
00651                                         destPos->z -=  _K * halfTimeSquare;
00652                                         currDate += deltaT;
00653                                         destPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride);
00654                                 }
00655                                 while (--numStep);
00656                         }                               
00657                 }
00658         }
00659 }
00660 
00661 
00662 void CPSGravity::setIntensity(float value)
00663 {
00664         if (_IntensityScheme)
00665         {
00666                 CPSForceIntensityHelper::setIntensity(value);
00667                 renewIntegrable(); // integrable again
00668         }
00669         else
00670         {
00671                 CPSForceIntensityHelper::setIntensity(value);
00672         }
00673 }
00674         
00675 void CPSGravity::setIntensityScheme(CPSAttribMaker<float> *scheme)
00676 {
00677         if (!_IntensityScheme)
00678         {
00679                 cancelIntegrable(); // not integrable anymore
00680         }                       
00681         CPSForceIntensityHelper::setIntensityScheme(scheme);    
00682 }
00683 
00684 
00686 // CPSCentralGravity  implementation   //
00688 
00689 
00690 void CPSCentralGravity::performDynamic(TAnimationTime ellapsedTime)
00691 {
00692         // for each central gravity, and each target, we check if they are in the same basis
00693         // if not, we need to transform the central gravity attachment pos into the target basis
00694         
00695 
00696         uint32 size = _Owner->getSize();
00697 
00698         // a vector that goes from the gravity to the object
00699         CVector centerToObj;
00700         float dist;
00701         
00702         for (uint32 k = 0; k < size; ++k)
00703         {       
00704                 const float ellapsedTimexK = ellapsedTime  * (_IntensityScheme ? _IntensityScheme->get(_Owner, k) : _K);
00705 
00706                 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00707                 {
00708                         const CMatrix &m = CPSLocated::getConversionMatrix(*it, this->_Owner);
00709                         const CVector center = m * (_Owner->getPos()[k]);
00710                                                 
00711                         TPSAttribVector::iterator it2 = (*it)->getSpeed().begin(), it2End = (*it)->getSpeed().end();
00712                         TPSAttribFloat::const_iterator invMassIt = (*it)->getInvMass().begin();
00713                         TPSAttribVector::const_iterator posIt = (*it)->getPos().begin();
00714                         
00715                         for (; it2 != it2End; ++it2, ++invMassIt, ++posIt)
00716                         {
00717                                 // our equation does 1 / r attenuation, which is not realistic, but fast ...
00718                                 centerToObj = center - *posIt;
00719         
00720                                 dist = centerToObj * centerToObj;
00721                                 if (dist > 10E-6f)
00722                                 {
00723                                         (*it2) += (*invMassIt) * ellapsedTimexK * (1.f / dist) *  centerToObj;                                                          
00724                                 }
00725                         }
00726                 }
00727         }
00728 
00729 }
00730 
00731 void CPSCentralGravity::show(TAnimationTime ellapsedTime)
00732 {
00733         CVector I = CVector::I;
00734         CVector J = CVector::J;
00735 
00736         const CVector tab[] = { -I - J, I - J
00737                                                         ,-I + J, I + J
00738                                                         , I - J, I + J
00739                                                         , -I - J, -I + J
00740                                                         , I + J, -I - J
00741                                                         , I - J, J - I
00742                                                         };
00743         const uint tabSize = sizeof(tab) / (2 * sizeof(CVector));
00744 
00745         const float sSize = 0.08f;
00746         displayIcon2d(tab, tabSize, sSize);
00747 }       
00748 
00749 void CPSCentralGravity::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00750 {
00751         f.serialVersion(1);     
00752         CPSForceIntensityHelper::serial(f);     
00753 }
00754 
00755 
00757 // CPSSpring  implementation   //
00759 
00760 
00761 
00762 void CPSSpring::performDynamic(TAnimationTime ellapsedTime)
00763 {
00764         // for each spring, and each target, we check if they are in the same basis
00765         // if not, we need to transform the spring attachment pos into the target basis
00766         
00767 
00768         uint32 size = _Owner->getSize();
00769 
00770         
00771         for (uint32 k = 0; k < size; ++k)
00772         {       
00773                 const float ellapsedTimexK = ellapsedTime  * (_IntensityScheme ? _IntensityScheme->get(_Owner, k) : _K);
00774 
00775                 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00776                 {
00777                         const CMatrix &m = CPSLocated::getConversionMatrix(*it, this->_Owner);
00778                         const CVector center = m * (_Owner->getPos()[k]);
00779                                                 
00780                         TPSAttribVector::iterator it2 = (*it)->getSpeed().begin(), it2End = (*it)->getSpeed().end();
00781                         TPSAttribFloat::const_iterator invMassIt = (*it)->getInvMass().begin();
00782                         TPSAttribVector::const_iterator posIt = (*it)->getPos().begin();
00783                         
00784                         for (; it2 != it2End; ++it2, ++invMassIt, ++posIt)
00785                         {
00786                                 // apply the spring equation
00787                                 (*it2) += (*invMassIt) * ellapsedTimexK * (center - *posIt);                                                            
00788                         }
00789                 }
00790         }
00791 }
00792 
00793 
00794 void CPSSpring::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00795 {
00796         f.serialVersion(1);     
00797         CPSForceIntensityHelper::serial(f);     
00798 }
00799 
00800 
00801 
00802 void CPSSpring::show(TAnimationTime ellapsedTime)
00803 {
00804         CVector I = CVector::I;
00805         CVector J = CVector::J;
00806         static const CVector tab[] = 
00807         { 
00808            -I + 2 * J,
00809            I + 2 * J,
00810            I + 2 * J, -I + J,
00811            -I + J, I + J,
00812            I + J, -I,
00813            -I, I,
00814            I, -I - J,
00815            -I - J, I - J,
00816            I - J,
00817            - I - 2 * J,
00818            - I - 2 * J,
00819            I - 2 * J
00820         };
00821         const uint tabSize = sizeof(tab) / (2 * sizeof(CVector));
00822         const float sSize = 0.08f;
00823         displayIcon2d(tab, tabSize, sSize);
00824 }
00825 
00826 
00828 //  CPSCylindricVortex implementation  //
00830 
00831 void CPSCylindricVortex::performDynamic(TAnimationTime ellapsedTime)
00832 {
00833         uint32 size = _Owner->getSize();
00834                 
00835         for (uint32 k = 0; k < size; ++k) // for each vortex
00836         {                                       
00837                 
00838                 const float invR = 1.f  / _Radius[k];
00839                 const float radius2 = _Radius[k] * _Radius[k];
00840 
00841                 // intensity for this vortex
00842                 nlassert(_Owner);
00843                 float intensity =  (_IntensityScheme ? _IntensityScheme->get(_Owner, k) : _K);
00844 
00845                 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00846                 {
00847                         // express the vortex position and plane normal in the located basis
00848                         const CMatrix &m = CPSLocated::getConversionMatrix(*it, this->_Owner);
00849                         const CVector center = m * (_Owner->getPos()[k]);
00850                         const CVector n = m.mulVector(_Normal[k]);
00851 
00852                         TPSAttribVector::iterator speedIt = (*it)->getSpeed().begin(), speedItEnd = (*it)->getSpeed().end();
00853                         TPSAttribFloat::const_iterator invMassIt = (*it)->getInvMass().begin();
00854                         TPSAttribVector::const_iterator posIt = (*it)->getPos().begin();
00855                         
00856 
00857                         // projection of the current located pos on the vortex axis
00858                         CVector p;
00859                         // a vector that go from the vortex center to the point we're dealing with
00860                         CVector v2p;
00861 
00862                         // the square of the dist of the projected pos
00863                         float d2 , d;
00864 
00865                         CVector realTangentialSpeed;
00866                         CVector tangentialSpeed;
00867 
00868                         
00869                         CVector radialSpeed;
00870 
00871 
00872                         for (; speedIt != speedItEnd; ++speedIt, ++invMassIt, ++posIt)
00873                         {
00874                                 v2p = *posIt - center;
00875                                 p = v2p - (v2p * n) * n;
00876 
00877                                 d2 = p * p;
00878 
00879                                 
00880 
00881                                 if (d2 < radius2) // not out of range ?
00882                                 {
00883                                         if (d2 > 10E-6)
00884                                         {
00885                                                 d = sqrtf(d2);
00886 
00887                                                 p *= 1.f / d;
00888                                                 // compute the speed vect that we should have (normalized) 
00889                                                 realTangentialSpeed = n ^ p;
00890 
00891                                                 tangentialSpeed = (*speedIt * realTangentialSpeed) * realTangentialSpeed;
00892                                                 radialSpeed =  (p * *speedIt) * p;
00893                                                 
00894                                                 // update radial speed;
00895                                                 *speedIt -= _RadialViscosity * ellapsedTime * radialSpeed;
00896                                                 
00897                                                 // update tangential speed                                      
00898                                                 *speedIt -= _TangentialViscosity * intensity * ellapsedTime * (tangentialSpeed - (1.f - d * invR) * realTangentialSpeed);
00899                                         }
00900                                 }                               
00901                         }
00902                 }
00903         }
00904 }
00905 
00906 
00907 void CPSCylindricVortex::show(TAnimationTime ellapsedTime)
00908 {
00909         
00910         CPSLocated *loc;
00911         uint32 index;
00912         CPSLocatedBindable *lb;
00913         _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00914 
00915 
00916         // must have set this
00917         nlassert(getFontGenerator() && getFontGenerator());
00918         setupDriverModelMatrix();
00919         
00920         for (uint k = 0; k < _Owner->getSize(); ++k)
00921         {
00922                 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k  ? CRGBA::Red : CRGBA(127, 127, 127));
00923                 CMatrix m;
00924                 CPSUtil::buildSchmidtBasis(_Normal[k], m);
00925                 CPSUtil::displayDisc(*getDriver(), _Radius[k], _Owner->getPos()[k], m, 32, col);
00926                 CPSUtil::displayArrow(getDriver(), _Owner->getPos()[k], _Normal[k], 1.f, col, CRGBA(200, 0, 200));
00927                 // display a V letter at the center
00928                 CPSUtil::print(getDriver(), std::string("v"), *getFontGenerator(), *getFontManager(), _Owner->getPos()[k], 80.f);
00929         }
00930 
00931 }
00932 
00933 void CPSCylindricVortex::setMatrix(uint32 index, const CMatrix &m)
00934 {
00935         nlassert(index < _Normal.getSize());
00936         _Normal[index] = m.getK();
00937         _Owner->getPos()[index] = m.getPos();   
00938 }
00939 
00940 CMatrix CPSCylindricVortex::getMatrix(uint32 index) const
00941 {
00942         CMatrix m;
00943         CPSUtil::buildSchmidtBasis(_Normal[index], m);
00944         m.setPos(_Owner->getPos()[index] ); 
00945         return m;
00946 }
00947 
00948 
00949 void CPSCylindricVortex::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00950 {
00951         f.serialVersion(1);     
00952         CPSForceIntensityHelper::serial(f);     
00953         f.serial(_Normal);
00954         f.serial(_Radius);
00955         f.serial(_RadialViscosity);
00956         f.serial(_TangentialViscosity);
00957 }
00958 
00959 void CPSCylindricVortex::newElement(CPSLocated *emitterLocated, uint32 emitterIndex) 
00960 { 
00961         CPSForceIntensityHelper::newElement(emitterLocated, emitterIndex); 
00962         _Normal.insert(CVector::K);
00963         _Radius.insert(1.f); 
00964 }
00965 void CPSCylindricVortex::deleteElement(uint32 index) 
00966 { 
00967         CPSForceIntensityHelper::deleteElement(index);
00968         _Normal.remove(index); 
00969         _Radius.remove(index);
00970 }
00971 void CPSCylindricVortex::resize(uint32 size) 
00972 { 
00973         nlassert(size < (1 << 16));
00974         CPSForceIntensityHelper::resize(size); 
00975         _Normal.resize(size);
00976         _Radius.resize(size);
00977 }
00978 
00979 
00984 void CPSMagneticForce::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00985 {
00986         f.serialVersion(1);
00987         CPSDirectionnalForce::serial(f);
00988 }
00989 
00990 void CPSMagneticForce::performDynamic(TAnimationTime ellapsedTime)
00991 {       
00992         // perform the operation on each target
00993         for (uint32 k = 0; k < _Owner->getSize(); ++k)
00994         {       
00995                 float intensity = ellapsedTime * (_IntensityScheme ? _IntensityScheme->get(_Owner, k) : _K);
00996                 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00997                 {
00998 
00999                         NLMISC::CVector toAdd = CPSLocated::getConversionMatrix(*it, this->_Owner).mulVector(_Dir); // express this in the target basis                 
01000 
01001                         TPSAttribVector::iterator it2 = (*it)->getSpeed().begin(), it2end = (*it)->getSpeed().end();
01002 
01003                         // 1st case : non-constant mass
01004                         if ((*it)->getMassScheme())
01005                         {
01006                                 TPSAttribFloat::const_iterator invMassIt = (*it)->getInvMass().begin();                 
01007                                 for (; it2 != it2end; ++it2, ++invMassIt)
01008                                 {
01009                                         (*it2) += intensity * *invMassIt * (*it2 ^ toAdd);
01010                                         
01011                                 }
01012                         }
01013                         else
01014                         {
01015                                 float i = intensity / (*it)->getInitialMass();
01016                                 for (; it2 != it2end; ++it2)
01017                                 {
01018                                         (*it2) += i * (*it2 ^ toAdd);
01019                                 }
01020                         }
01021                 }
01022         }
01023 }
01024 
01025 
01030 const uint BFNumPredefinedPos    = 8192;        // should be a power of 2
01031 const uint BFPredefinedNumInterp = 256;     
01035 const uint BFNumPrecomputedImpulsions = 1024; 
01036 
01037 NLMISC::CVector CPSBrownianForce::PrecomputedPos[BFNumPredefinedPos]; // after the sequence we must be back to the start position
01038 NLMISC::CVector CPSBrownianForce::PrecomputedSpeed[BFNumPredefinedPos];
01039 NLMISC::CVector CPSBrownianForce::PrecomputedImpulsions[BFNumPrecomputedImpulsions];
01040 
01042 CPSBrownianForce::CPSBrownianForce(float intensity /* = 1.f*/) : _ParametricFactor(1.f)
01043 {
01044         setIntensity(intensity);
01045         _Name = std::string("BrownianForce");
01046 
01047 }
01048 
01050 bool    CPSBrownianForce::isIntegrable(void) const
01051 {
01052         return _IntensityScheme == NULL;
01053 }
01054 
01055 
01057 void CPSBrownianForce::integrate(float date, CPSLocated *src,
01058                                                                  uint32 startIndex,
01059                                                                  uint32 numObjects,
01060                                                                  NLMISC::CVector *destPos,
01061                                                                  NLMISC::CVector *destSpeed,
01062                                                                  bool accumulate,
01063                                                                  uint posStride, uint speedStride
01064                                                             )
01065 {
01067         float deltaT;
01068         if (!destPos && !destSpeed) return;
01069         CPSLocated::TPSAttribParametricInfo::const_iterator it = src->_PInfo.begin() + startIndex,
01070                                                                                                                 endIt = src->_PInfo.begin() + startIndex + numObjects;
01071         float lookUpFactor = _ParametricFactor * BFNumPredefinedPos;
01072         float speedFactor  = _ParametricFactor * _K;
01073         if (!accumulate) // compute coords from initial condition, and applying this force
01074         {
01075                 if (destPos && !destSpeed) // fills dest pos only
01076                 {
01077                         while (it != endIt)
01078                         {
01079                                 float deltaT = date - it->Date;
01080                                 uint index = (uint) (lookUpFactor * deltaT) & (BFNumPredefinedPos - 1);
01081                                 destPos->set(it->Pos.x + deltaT * it->Speed.x + _K * PrecomputedPos[index].x,
01082                                                          it->Pos.y + deltaT * it->Speed.y + _K * PrecomputedPos[index].y,
01083                                                          it->Pos.z + deltaT * it->Speed.z + _K * PrecomputedPos[index].z );
01084                                 ++it;
01085                                 NEXT_POS;       
01086                         }
01087                 }
01088                 else if (!destPos && destSpeed) // fills dest speed only
01089                 {
01090                         while (it != endIt)
01091                         {
01092                                 deltaT = date - it->Date;
01093                                 uint index = (uint) (lookUpFactor * deltaT) & (BFNumPredefinedPos - 1);
01094                                 destSpeed->x = it->Speed.x  + speedFactor * PrecomputedSpeed[index].x;                          
01095                                 destSpeed->y = it->Speed.y  + speedFactor * PrecomputedSpeed[index].y;
01096                                 destSpeed->z = it->Speed.z  + speedFactor * PrecomputedSpeed[index].z;
01097                                 ++it;
01098                                 NEXT_SPEED;     
01099                         }
01100                 }
01101                 else // fills both speed and pos
01102                 {
01103                         while (it != endIt)
01104                         {
01105                                 deltaT = date - it->Date;
01106                                 uint index = (uint) (lookUpFactor * deltaT) & (BFNumPredefinedPos - 1);
01107                                 destPos->x = it->Pos.x + deltaT * it->Speed.x + _K * PrecomputedPos[index].x;                           
01108                                 destPos->y = it->Pos.y + deltaT * it->Speed.y + _K * PrecomputedPos[index].y;
01109                                 destPos->z = it->Pos.z + deltaT * it->Speed.z + _K * PrecomputedPos[index].z;
01110 
01111                                 destSpeed->x = it->Speed.x + speedFactor * PrecomputedSpeed[index].x;                           
01112                                 destSpeed->y = it->Speed.y + speedFactor * PrecomputedSpeed[index].y;
01113                                 destSpeed->z = it->Speed.z + speedFactor * PrecomputedSpeed[index].z;
01114 
01115                                 ++it;
01116                                 NEXT_POS;
01117                                 NEXT_SPEED;
01118                         }
01119                 }
01120         }
01121         else // accumulate datas
01122         {
01123                 if (destPos && !destSpeed) // fills dest pos only
01124                 {
01125                         while (it != endIt)
01126                         {
01127                                 deltaT = date - it->Date;
01128                                 uint index = (uint) (lookUpFactor * deltaT) & (BFNumPredefinedPos - 1);
01129                                 destPos->set(destPos->x + _K * PrecomputedPos[index].x,
01130                                                          destPos->y + _K * PrecomputedPos[index].y,
01131                                                          destPos->z + _K * PrecomputedPos[index].z);
01132                                 ++it;
01133                                 NEXT_POS;       
01134                         }
01135                 }
01136                 else if (!destPos && destSpeed) // fills dest speed only
01137                 {
01138                         while (it != endIt)
01139                         {
01140                                 deltaT = date - it->Date;
01141                                 uint index = (uint) (lookUpFactor * deltaT) & (BFNumPredefinedPos - 1);
01142                                 destSpeed->set(destSpeed->x + speedFactor * PrecomputedSpeed[index].x,
01143                                                            destSpeed->y + speedFactor * PrecomputedSpeed[index].y,
01144                                                            destSpeed->z + speedFactor * PrecomputedSpeed[index].z);
01145                                 ++it;
01146                                 NEXT_SPEED;     
01147                         }
01148                 }
01149                 else // fills both speed and pos
01150                 {
01151                         while (it != endIt)
01152                         {
01153                                 deltaT = date - it->Date;
01154                                 uint index = (uint) (lookUpFactor * deltaT) & (BFNumPredefinedPos - 1);
01155                                 destPos->set(destPos->x + _K * PrecomputedPos[index].x,
01156                                                          destPos->y + _K * PrecomputedPos[index].y,
01157                                                          destPos->z + _K * PrecomputedPos[index].z);
01158                                 destSpeed->set(destSpeed->x + speedFactor * PrecomputedSpeed[index].x,
01159                                                            destSpeed->y + speedFactor * PrecomputedSpeed[index].y,
01160                                                            destSpeed->z + speedFactor * PrecomputedSpeed[index].z);     
01161                                 ++it;
01162                                 NEXT_POS;
01163                                 NEXT_SPEED;
01164                         }
01165                 }
01166         }       
01167 }
01168 
01169 
01171 void CPSBrownianForce::integrateSingle(float startDate, float deltaT, uint numStep,                                                              
01172                                                                  CPSLocated *src, uint32 indexInLocated,
01173                                                                  NLMISC::CVector *destPos,
01174                                                                  bool accumulate,
01175                                                                  uint stride)
01176 {
01177         nlassert(src->isParametricMotionEnabled());
01178         nlassert(deltaT > 0);
01179         nlassert(numStep > 0);
01180         #ifdef NL_DEBUG
01181                 NLMISC::CVector *endPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride * numStep);
01182         #endif
01183         const CPSLocated::CParametricInfo &pi = src->_PInfo[indexInLocated];
01184         const NLMISC::CVector &startPos   = pi.Pos;     
01185         if (numStep != 0)
01186         {
01187                 float lookUpFactor = _ParametricFactor * BFPredefinedNumInterp;
01188                 if (!accumulate)
01189                 {                               
01191                         destPos = FillBufUsingSubdiv(startPos, pi.Date, startDate, deltaT, numStep, destPos, stride);
01192                         if (numStep != 0)
01193                         {
01194                                 float currDate = startDate - pi.Date;
01195                                 nlassert(currDate >= 0);                                
01196                                 const NLMISC::CVector &startSpeed = pi.Speed;                   
01197                                 do
01198                                 {
01199                                         #ifdef NL_DEBUG
01200                                                 nlassert(destPos < endPos);
01201                                         #endif
01202                                         uint index = (uint) (lookUpFactor * currDate) & (BFNumPredefinedPos - 1);
01203                                         destPos->x = startPos.x + currDate * startSpeed.x + _K * PrecomputedPos[index].x;
01204                                         destPos->y = startPos.y + currDate * startSpeed.y + _K * PrecomputedPos[index].y;
01205                                         destPos->z = startPos.z + currDate * startSpeed.z + _K * PrecomputedPos[index].z;
01206                                         currDate += deltaT;
01207                                         destPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride);
01208                                 }
01209                                 while (--numStep);
01210                         }
01211                 }
01212                 else
01213                 {
01214                         uint numToSkip = ScaleFloatGE(startDate, deltaT, pi.Date, numStep);             
01215                         if (numToSkip < numStep)
01216                         {
01217                                 numStep -= numToSkip;                           
01218                                 float currDate = startDate + deltaT * numToSkip - pi.Date;
01219                                 do
01220                                 {
01221                                         #ifdef NL_DEBUG
01222                                                 nlassert(destPos < endPos);
01223                                         #endif
01224                                         uint index = (uint) (lookUpFactor * currDate) & (BFNumPredefinedPos - 1);
01225                                         destPos->x += _K * PrecomputedPos[index].x;
01226                                         destPos->y += _K * PrecomputedPos[index].y;
01227                                         destPos->z += _K * PrecomputedPos[index].z;
01228                                         currDate += deltaT;
01229                                         destPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride);
01230                                 }
01231                                 while (--numStep);                              
01232                         }
01233                 }
01234         }       
01235 }
01236 
01237 
01239 void CPSBrownianForce::initPrecalc()
01240 {
01242         nlassert(BFNumPredefinedPos % BFPredefinedNumInterp == 0);
01243         
01244         NLMISC::CVector p0(0, 0, 0), p1;
01245         const uint numStep = BFNumPredefinedPos / BFPredefinedNumInterp;
01246         NLMISC::CVector *dest = PrecomputedPos;
01247         uint k, l;
01248         for (k = 0; k < numStep; ++k)
01249         {
01250                 if (k != numStep - 1)
01251                 {
01252                         p1.set(2.f * (NLMISC::frand(1.f) - 0.5f),
01253                                    2.f * (NLMISC::frand(1.f) - 0.5f),
01254                                    2.f * (NLMISC::frand(1.f) - 0.5f));
01255                 }
01256                 else
01257                 {
01258                         p1.set(0, 0, 0);
01259                 }
01260                 float lambda     = 0.f;
01261                 float lambdaStep = 1.f / BFPredefinedNumInterp;
01262                 for (l = 0; l < BFPredefinedNumInterp; ++l)
01263                 {
01264                         *dest++ = lambda * p1 + (1.f - lambda) * p0;
01265                         lambda += lambdaStep;
01266                 }
01267                 p0 = p1;                                
01268         }
01269 
01270         // now, filter the table several time to get something more smooth
01271         for (k = 0; k < (BFPredefinedNumInterp << 2) ; ++k)
01272         {
01273                 for (l = 1; l < (BFNumPredefinedPos - 1); ++l)
01274                 {
01275                         PrecomputedPos[l] = 0.5f * (PrecomputedPos[l - 1] + PrecomputedPos[l + 1]);
01276                 }
01277         }
01278 
01279 
01280         // compute the table of speeds, by using on a step of 1.s
01281         for (l = 1; l < (BFNumPredefinedPos - 1); ++l)
01282         {
01283                 PrecomputedSpeed[l] = 0.5f * (PrecomputedPos[l + 1] - PrecomputedPos[l - 1]);
01284         }
01285         PrecomputedSpeed[BFNumPredefinedPos - 1] = NLMISC::CVector::Null;
01286 
01287         // compute the table of impulsion
01288         for (k = 0; k < BFNumPrecomputedImpulsions; ++k)
01289         {
01290                 static double divRand = (2.f / RAND_MAX);
01291                 PrecomputedImpulsions[k].set( (float) (rand() * divRand - 1),
01292                                                                           (float) (rand() * divRand - 1),
01293                                                                           (float) (rand() * divRand - 1) 
01294                                                                         );
01295         }
01296 }
01297 
01299 void CPSBrownianForce::setIntensity(float value)
01300 {
01301         if (_IntensityScheme)
01302         {
01303                 CPSForceIntensity::setIntensity(value);
01304                 renewIntegrable(); // integrable again
01305         }
01306         else
01307         {
01308                 CPSForceIntensity::setIntensity(value);
01309         }
01310 }
01311 
01312 
01314 void CPSBrownianForce::setIntensityScheme(CPSAttribMaker<float> *scheme)
01315 {
01316         if (!_IntensityScheme)
01317         {
01318                 cancelIntegrable(); // not integrable anymore
01319         }                       
01320         CPSForceIntensity::setIntensityScheme(scheme);  
01321 }
01322 
01324 void CPSBrownianForce::performDynamic(TAnimationTime ellapsedTime)
01325 {
01326         // perform the operation on each target 
01327         for (uint32 k = 0; k < _Owner->getSize(); ++k)
01328         {               
01329                 float intensity = _IntensityScheme ? _IntensityScheme->get(_Owner, k) : _K;
01330                 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
01331                 {                       
01332                         uint32 size = (*it)->getSize();
01333 
01334                         if (!size) continue;
01335 
01336                         TPSAttribVector::iterator it2 = (*it)->getSpeed().begin(), it2End;
01338                         uint startPos = (uint) ::rand() % BFNumPrecomputedImpulsions;
01339                         NLMISC::CVector *imp = PrecomputedImpulsions + startPos;
01340 
01341                         if ((*it)->getMassScheme())
01342                         {
01343                                 float intensityXtime = intensity * ellapsedTime;
01344                                 TPSAttribFloat::const_iterator invMassIt = (*it)->getInvMass().begin();                                         
01345                                 do
01346                                 {                       
01347                                         uint toProcess = std::min((uint) (BFNumPrecomputedImpulsions - startPos), (uint) size);
01348                                         it2End = it2 + toProcess;
01349                                         do
01350                                         {
01351                                                 float factor = intensityXtime * *invMassIt;
01352                                                 it2->set(it2->x + factor * imp->x,
01353                                                                 it2->y + factor * imp->y,
01354                                                                 it2->z + factor * imp->x);
01355                                                 ++invMassIt;
01356                                                 ++imp;
01357                                                 ++it2;
01358                                         }
01359                                         while (it2 != it2End);
01360                                         startPos = 0;
01361                                         imp = PrecomputedImpulsions;    
01362                                         size -= toProcess;
01363                                 }
01364                                 while (size != 0);
01365                         }
01366                         else
01367                         {                               
01368                                 do
01369                                 {                       
01370                                         uint toProcess = std::min((uint) (BFNumPrecomputedImpulsions - startPos) , (uint) size);
01371                                         it2End = it2 + toProcess;
01372                                         float factor = intensity * ellapsedTime / (*it)->getInitialMass();
01373                                         do
01374                                         {                                               
01375                                                 it2->set(it2->x + factor * imp->x,
01376                                                                 it2->y + factor * imp->y,
01377                                                                 it2->z + factor * imp->x);                                              
01378                                                 ++imp;
01379                                                 ++it2;
01380                                         }
01381                                         while (it2 != it2End);
01382                                         startPos = 0;
01383                                         imp = PrecomputedImpulsions;    
01384                                         size -= toProcess;
01385                                 }
01386                                 while (size != 0);
01387                         }                       
01388                 }
01389         }       
01390 }
01391 
01393 void CPSBrownianForce::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01394 {
01395         sint ver = f.serialVersion(3);          
01396         if (ver <= 2)
01397         {
01398                 uint8 dummy;
01399                 f.serial(dummy); // old data in version 2 not used anymore      
01400                 CPSForce::serial(f);
01401                 f.serial(dummy); // old data in version 2 not used anymore      
01402                 serialForceIntensity(f);
01403                 if (f.isReading())
01404                 {
01405                         registerToTargets();
01406                 }
01407         }
01408 
01409         if (ver >= 2)
01410         {
01411                 CPSForceIntensityHelper::serial(f);
01412                 f.serial(_ParametricFactor);
01413         }
01414 }
01415 
01416 
01417 } // NL3D