ps_ribbon_base.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_ribbon_base.h"
00029 #include "3d/particle_system.h"
00030 
00031 namespace NL3D 
00032 {
00033 
00035 //  CPSRibbonBase implementation  //
00037 
00038 
00040 static inline void BuildHermiteVector(const NLMISC::CVector &P0,
00041                                                            const NLMISC::CVector &P1,
00042                                                            const NLMISC::CVector &T0,
00043                                                            const NLMISC::CVector &T1,
00044                                                                          NLMISC::CVector &dest,                                                                  
00045                                                            float lambda
00046                                                            )
00047 {       
00048         const float lambda2 = lambda * lambda;
00049         const float lambda3 = lambda2 * lambda;
00050         const float h1 = 2 * lambda3 - 3 * lambda2 + 1; 
00051         const float h2 = - 2 * lambda3 + 3 * lambda2; 
00052         const float h3 = lambda3 - 2 * lambda2 + lambda; 
00053         const float h4 = lambda3 - lambda2;
00055         dest.set (h1 * P0.x + h2 * P1.x + h3 * T0.x + h4 * T1.x,
00056                           h1 * P0.y + h2 * P1.y + h3 * T0.y + h4 * T1.y,
00057                           h1 * P0.z + h2 * P1.z + h3 * T0.z + h4 * T1.z);
00058 
00059 }
00060 
00062 static inline void BuildLinearVector(const NLMISC::CVector &P0,
00063                                                                          const NLMISC::CVector &P1,                                                        
00064                                                                          NLMISC::CVector &dest,                                                                  
00065                                                                          float lambda,
00066                                                                          float oneMinusLambda
00067                                                                 )
00068 {               
00069         dest.set (lambda * P1.x + oneMinusLambda * P0.x,
00070                           lambda * P1.y + oneMinusLambda * P0.y,
00071                           lambda * P1.z + oneMinusLambda * P0.z);                                       
00072 }
00073 
00074 
00075 const uint EndRibbonStorage = 1;
00076 
00077 
00078 //=======================================================
00079 CPSRibbonBase::CPSRibbonBase() : _NbSegs(8),
00080                                                                  _SegDuration(0.02f),
00081                                                                  _Parametric(false),
00082                                                                  _RibbonIndex(0),
00083                                                                  _LastUpdateDate(0),
00084                                                                  _RibbonMode(VariableSize),
00085                                                                  _InterpolationMode(Hermitte),
00086                                                                  _RibbonLength(1),
00087                                                                  _SegLength(_RibbonLength / _NbSegs),
00088                                                                  _LODDegradation(1)
00089 
00090 {
00091         initDateVect();
00092 }
00093 
00094 //=======================================================
00095 void    CPSRibbonBase::setRibbonLength(float length)
00096 { 
00097         nlassert(length > 0.f);
00098         _RibbonLength = length;
00099         _SegLength = length / _NbSegs;
00100 }
00101 
00102 //=======================================================
00103 void    CPSRibbonBase::setRibbonMode(TRibbonMode mode)
00104 {
00105         nlassert(mode < RibbonModeLast);
00106         _RibbonMode = mode;
00107 }
00108 
00109 
00110 //=======================================================
00111 void    CPSRibbonBase::setInterpolationMode(TInterpolationMode mode)
00112 {
00113         nlassert(mode < InterpModeLast);
00114         _InterpolationMode = mode;
00115 }
00116 
00117 //=======================================================
00118 void    CPSRibbonBase::setTailNbSeg(uint32 nbSegs)
00119 {
00120         nlassert(nbSegs >= 1);  
00121         _NbSegs = nbSegs;       
00122         _RibbonIndex = 0;
00123         if (_Owner)
00124         {       
00125                 resize(_Owner->getMaxSize());
00126         }
00127         initDateVect();
00128 }
00129 
00130 
00131 //=======================================================       
00132 void    CPSRibbonBase::setSegDuration(TAnimationTime ellapsedTime)
00133 {
00134         _SegDuration = ellapsedTime;
00135 
00136 }
00137 
00138 //=======================================================       
00139 void    CPSRibbonBase::updateGlobals(float realET)
00140 {
00141         nlassert(!_Parametric);
00142         nlassert(_Owner);
00143         const uint size = _Owner->getSize();
00144         if (!size) return;
00145         const TAnimationTime currDate = _Owner->getOwner()->getSystemDate() + realET;
00146         if (currDate  - _LastUpdateDate >= _SegDuration)
00147         {
00148                 if (_RibbonIndex == 0) _RibbonIndex = _NbSegs + EndRibbonStorage;
00149                 else --_RibbonIndex;
00150                 
00152                 ::memmove(&_SamplingDate[1], &_SamplingDate[0], sizeof(float) * (_NbSegs + EndRibbonStorage));
00153                 _LastUpdateDate = currDate;
00154         }
00155         
00157         _SamplingDate[0] = currDate;
00158 
00160         TPSAttribVector::iterator posIt = _Owner->getPos().begin();
00161         NLMISC::CVector *currIt = &_Ribbons[_RibbonIndex];
00162         uint k = size;
00163         for (;;)
00164         {
00165                 *currIt = *posIt;
00166                 --k;
00167                 if (!k) break;
00168                 ++posIt;
00169                 currIt += (_NbSegs + 1 + EndRibbonStorage);
00170         }
00171 }
00172 
00173 
00174 //=======================================================       
00175 void    CPSRibbonBase::computeHermitteRibbon(uint index, NLMISC::CVector *dest, uint stride /* = sizeof(NLMISC::CVector)*/)
00176 {       
00177         nlassert(!_Parametric); 
00178         NLMISC::CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
00179         NLMISC::CVector *endIt   = startIt + (_NbSegs + 1 + EndRibbonStorage);
00180         NLMISC::CVector *currIt  = startIt + _RibbonIndex;      
00181         const NLMISC::CVector *firstIt = currIt;
00182         NLMISC::CVector *nextIt  = currIt + 1;
00183         if (nextIt == endIt) nextIt = startIt;
00184         NLMISC::CVector *nextNextIt = nextIt + 1;       
00185         if (nextNextIt == endIt) nextNextIt = startIt;  
00186         float *date = &_SamplingDate[0];                        
00187 
00188         NLMISC::CVector t0 = (*nextIt - *currIt);
00189         NLMISC::CVector t1 = 0.5f * (*nextNextIt - *currIt);
00190 
00191         uint leftToDo = _UsedNbSegs + 1;
00192 
00193         float lambda = 0.f;
00194         float lambdaStep = 1.f;
00195         
00196 
00197         for (;;)
00198         {               
00199                 float dt = date[0] - date[1];
00200 
00201                 if (dt < 10E-6f) // we reached the start of ribbon
00202                 {
00203 
00204                         do
00205                         {
00206                                 *dest = *currIt;
00207                                 dest  = (NLMISC::CVector *) ((uint8 *) dest + stride);
00208                         }
00209                         while (--leftToDo);                     
00210                         return;
00211                 }
00212 
00213                 float newLambdaStep = _UsedSegDuration / dt;
00214                 // readapt lambda
00215                 lambda *= newLambdaStep / lambdaStep;
00216                 lambdaStep = newLambdaStep;
00217                 for(;;)
00218                 {
00219                         if (lambda >= 1.f) break;
00221                         BuildHermiteVector(*currIt, *nextIt, t0, t1, *dest, lambda);
00222                         dest  = (NLMISC::CVector *) ((uint8 *) dest + stride);
00223                         -- leftToDo;
00224                         if (!leftToDo) return;                                                                                          
00225                         lambda += lambdaStep;                   
00226                 }
00227 
00228                 ++date;
00229                 lambda -= 1.f;
00230 
00231                 // Start new segment and compute new tangents
00232                 t0 = t1;
00233                 currIt = nextIt;
00234                 nextIt = nextNextIt;
00235                 ++nextNextIt;
00236                 if (nextNextIt == endIt) nextNextIt = startIt;
00237                 if (nextNextIt == firstIt)
00238                 {
00239                         t1 = *nextIt - *currIt;
00240                 }
00241                 else
00242                 {               
00243                         t1 = 0.5f * (*nextNextIt - *currIt);
00244                 }               
00245         }
00246 }
00247 
00248 //=======================================================       
00249 void CPSRibbonBase::computeLinearRibbon(uint index, NLMISC::CVector *dest, uint stride /* = sizeof(NLMISC::CVector)*/)
00250 {
00252         nlassert(!_Parametric); 
00253         NLMISC::CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
00254         NLMISC::CVector *endIt   = startIt + (_NbSegs + 1 + EndRibbonStorage);
00255         NLMISC::CVector *currIt  = startIt + _RibbonIndex;      
00256         NLMISC::CVector *nextIt  = currIt + 1;
00257         if (nextIt == endIt) nextIt = startIt;
00258         NLMISC::CVector *nextNextIt = nextIt + 1;       
00259         if (nextNextIt == endIt) nextNextIt = startIt;  
00260         float *date = &_SamplingDate[0];                                
00261 
00262         uint leftToDo = _UsedNbSegs + 1;
00263 
00264         float lambda = 0.f;
00265         float lambdaStep = 1.f;
00266         
00267         for (;;)
00268         {               
00269                 float dt = date[0] - date[1];
00270 
00271                 if (dt < 10E-6f) // we reached the start of ribbon
00272                 {
00273                         do
00274                         {
00275                                 *dest = *currIt;
00276                                 dest  = (NLMISC::CVector *) ((uint8 *) dest + stride);
00277                         }
00278                         while (--leftToDo);                     
00279                         return;
00280                 }
00281                 
00282                 
00283                 float newLambdaStep = _UsedSegDuration / dt;
00284                 // readapt lambda
00285                 lambda *= newLambdaStep / lambdaStep;
00286                 lambdaStep = newLambdaStep;
00287 
00288                 float oneMinusLambda = 1.f - lambda;
00289                 for(;;)
00290                 {
00291                         if (lambda >= 1.f) break;
00293                         BuildLinearVector(*currIt, *nextIt, *dest, lambda, oneMinusLambda);
00294                         dest  = (NLMISC::CVector *) ((uint8 *) dest + stride);
00295                         -- leftToDo;
00296                         if (!leftToDo) return;                                                                                          
00297                         lambda += lambdaStep;
00298                         oneMinusLambda -= lambdaStep;
00299                 }
00300                 
00301                 ++date;
00302                 lambda -= 1.f;
00303                 
00304                 currIt = nextIt;
00305                 nextIt = nextNextIt;
00306                 ++nextNextIt;
00307                 if (nextNextIt == endIt) nextNextIt = startIt;          
00308                 
00309         }
00310 }
00311 
00312 
00313 
00314 //=======================================================       
00315 void CPSRibbonBase::computeLinearCstSizeRibbon(uint index, NLMISC::CVector *dest, uint stride /* = sizeof(NLMISC::CVector)*/)
00316 {       
00317         nlassert(!_Parametric); 
00318         CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
00319         NLMISC::CVector *endIt   = startIt + (_NbSegs + 1 + EndRibbonStorage);
00320         NLMISC::CVector *currIt  = startIt + _RibbonIndex;      
00321         NLMISC::CVector *firstIt = currIt;      
00322         NLMISC::CVector *nextIt  = currIt + 1;
00323         if (nextIt == endIt) nextIt = startIt;
00324         NLMISC::CVector *nextNextIt = nextIt + 1;       
00325         if (nextNextIt == endIt) nextNextIt = startIt;          
00326 
00327         uint leftToDo = _UsedNbSegs + 1;
00328 
00329         float lambda = 0.f;
00330         float lambdaStep = 1.f; 
00331 
00332         
00334         for (;;)
00335         {       
00337                 const float sampleLength = (*nextIt - *currIt).norm();          
00338                 if (sampleLength > 10E-6f)
00339                 {                                       
00341                         float newLambdaStep = _UsedSegLength / sampleLength;
00342                         // readapt lambda
00343                         lambda *= newLambdaStep / lambdaStep;
00344                         lambdaStep = newLambdaStep;
00345 
00346                         float oneMinusLambda = 1.f - lambda;
00347                         for(;;)
00348                         {
00349                                 if (lambda >= 1.f) break;
00351                                 BuildLinearVector(*currIt, *nextIt, *dest, lambda, oneMinusLambda);
00352                                 dest  = (NLMISC::CVector *) ((uint8 *) dest + stride);
00353                                 -- leftToDo;
00354                                 if (!leftToDo) return;                                                                                          
00355                                 lambda += lambdaStep;
00356                                 oneMinusLambda -= lambdaStep;
00357                         }
00358                         lambda -= 1.f;
00359                 }
00360                 
00362                 currIt = nextIt;
00363                 nextIt = nextNextIt;
00364                 ++nextNextIt;
00365                 if (nextNextIt == endIt) nextNextIt = startIt;
00366                 if (nextNextIt == firstIt)
00367                 {
00368                         // The length of the sampling curve is too short
00369                         // must truncate the ribbon.
00370                         NLMISC::CVector &toDup = *nextIt;
00371                         while (leftToDo --)
00372                         {
00373                                 *dest = toDup;
00374                                 dest  = (NLMISC::CVector *) ((uint8 *) dest + stride);
00375                         }
00376                         return;
00377                 }
00378         }
00379 }
00380 
00381 //=======================================================       
00382 void CPSRibbonBase::computeHermitteCstSizeRibbon(uint index, NLMISC::CVector *dest, uint stride /* = sizeof(NLMISC::CVector)*/)
00383 {       
00384         nlassert(!_Parametric); 
00385         NLMISC::CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
00386         NLMISC::CVector *endIt   = startIt + (_NbSegs + 1 + EndRibbonStorage);
00387         NLMISC::CVector *currIt  = startIt + _RibbonIndex;      
00388         NLMISC::CVector *firstIt = currIt;      
00389         NLMISC::CVector *nextIt  = currIt + 1;
00390         if (nextIt == endIt) nextIt = startIt;
00391         NLMISC::CVector *nextNextIt = nextIt + 1;       
00392         if (nextNextIt == endIt) nextNextIt = startIt;
00393 
00394         NLMISC::CVector t0 = (*nextIt - *currIt);
00395         NLMISC::CVector t1 = 0.5f * (*nextNextIt - *currIt);
00396 
00397         uint leftToDo = _UsedNbSegs + 1;
00398 
00399         float lambda = 0.f;
00400         float lambdaStep = 1.f; 
00401 
00402         
00405         for (;;)
00406         {       
00408                 const float sampleLength = (*nextIt - *currIt).norm();          
00409                 if (sampleLength > 10E-6f)
00410                 {                                       
00412                         float newLambdaStep = _UsedSegLength / sampleLength;
00413                         // readapt lambda
00414                         lambda *= newLambdaStep / lambdaStep;
00415                         lambdaStep = newLambdaStep;
00416                         
00417                         for(;;)
00418                         {
00419                                 if (lambda >= 1.f) break;
00421                                 BuildHermiteVector(*currIt, *nextIt, t0, t1, *dest, lambda);
00422                                 dest  = (NLMISC::CVector *) ((uint8 *) dest + stride);
00423                                 -- leftToDo;
00424                                 if (!leftToDo) return;                                                                                          
00425                                 lambda += lambdaStep;                           
00426                         }
00427                         lambda -= 1.f;
00428                 }
00429                 
00431                 currIt = nextIt;
00432                 nextIt = nextNextIt;
00433                 ++nextNextIt;
00434                 if (nextNextIt == endIt) nextNextIt = startIt;
00435                 if (nextNextIt == firstIt)
00436                 {
00437                         // The length of the sampling curve is too short
00438                         // must truncate the ribbon.
00439                         NLMISC::CVector &toDup = *nextIt;
00440                         while (leftToDo --)
00441                         {
00442                                 *dest = toDup;
00443                                 dest  = (NLMISC::CVector *) ((uint8 *) dest + stride);
00444                         }
00445                         return;
00446                 }
00448                 t0 = t1;
00449                 t1 = 0.5f * (*nextNextIt - *currIt);
00450         }
00451 }
00452 
00453 
00454 //=======================================================       
00455 void CPSRibbonBase::computeRibbon(uint index, NLMISC::CVector *dest, uint stride /* = sizeof(NLMISC::CVector)*/)
00456 {
00457         switch (_InterpolationMode)
00458         {
00459                 case Linear:
00460                         if (_RibbonMode == VariableSize)
00461                         {
00462                                 computeLinearRibbon(index, dest, stride);                               
00463                         }
00464                         else
00465                         {
00466                                 computeLinearCstSizeRibbon(index, dest, stride);                                
00467                         }
00468                 break;
00469                 case Hermitte:
00470                         if (_RibbonMode == VariableSize)
00471                         {
00472                                 computeHermitteRibbon(index, dest, stride);                                     
00473                                 
00474                         }
00475                         else
00476                         {
00477                                 computeHermitteCstSizeRibbon(index, dest, stride);                                      
00478                         }
00479                 break;
00480                 default:
00481                         nlassert(0);
00482                 break;
00483         }
00484         
00485 }
00486 
00487 
00488 //=======================================================       
00489 void    CPSRibbonBase::dupRibbon(uint dest, uint src)
00490 {
00491         nlassert(!_Parametric);
00492         nlassert(_Owner);
00493         const uint size = _Owner->getSize();
00494         nlassert(dest < size && src < size);
00495         ::memcpy(&_Ribbons[dest * (_NbSegs + EndRibbonStorage + 1)], &_Ribbons[src * (_NbSegs + EndRibbonStorage + 1)], sizeof(NLMISC::CVector) * (_NbSegs + 1 + EndRibbonStorage));
00496 }
00497 
00498 //=======================================================       
00499 void    CPSRibbonBase::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00500 {
00501         if (_Parametric) return;
00503         const uint index = _Owner->getNewElementIndex();
00504         const NLMISC::CVector &pos = _Owner->getPos()[index]; // get the pos of the new element;
00505         resetSingleRibbon(index, pos);
00506 }
00507 
00508 //=======================================================       
00509 void    CPSRibbonBase::deleteElement(uint32 index)
00510 {
00511         if (_Parametric) return;
00512         const uint32 size = _Owner->getSize();
00513         if(index == (size - 1)) return; // was the last element, no permutation needed.
00514         dupRibbon(index, size - 1);
00515 }
00516 
00517 //=======================================================       
00518 void    CPSRibbonBase::resize(uint32 size)
00519 {
00520         nlassert(size < (1 << 16));
00521         if (_Parametric) return;
00522         _Ribbons.resize(size * (_NbSegs + 1 + EndRibbonStorage));
00523         resetFromOwner();
00524 }
00525 
00526 
00527 //=======================================================       
00528 void CPSRibbonBase::resetSingleRibbon(uint index, const NLMISC::CVector &pos)
00529 {
00530         nlassert(!_Parametric);
00531         NLMISC::CVector *it = &_Ribbons[(index * (_NbSegs + 1 + EndRibbonStorage))];
00532         std::fill(it, it + (_NbSegs + 1 + EndRibbonStorage), pos);
00533 }
00534 
00535 
00536 
00537 //=======================================================       
00538 void CPSRibbonBase::resetFromOwner()
00539 {
00540         nlassert(!_Parametric);
00541         TPSAttribVector::iterator posIt = _Owner->getPos().begin();
00542         TPSAttribVector::iterator endPosIt = _Owner->getPos().end();
00543         for (uint k = 0; posIt != endPosIt; ++posIt, ++k)
00544         {
00545                 resetSingleRibbon(k, *posIt);
00546         }
00547 }
00548 
00549 //=======================================================       
00550 void CPSRibbonBase::motionTypeChanged(bool parametric)
00551 {
00552         _Parametric = parametric;
00553         if (parametric)
00554         {
00555                 NLMISC::contReset(_Ribbons); // kill the vector         
00556         }
00557         else
00558         {
00559                 nlassert(_Owner);
00560                 resize(_Owner->getMaxSize());
00561                 initDateVect();         
00562                 resetFromOwner();               
00563         }       
00564 }
00565 
00566 
00567 //=======================================================       
00568 void CPSRibbonBase::initDateVect()
00569 {
00570         _SamplingDate.resize( _NbSegs + 1 + EndRibbonStorage);
00571         std::fill(_SamplingDate.begin(), _SamplingDate.begin() + (_NbSegs + 1 + EndRibbonStorage), 0.f);
00572 }
00573 
00574 
00575 //=======================================================       
00576 void CPSRibbonBase::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00577 {
00578         CPSParticle::serial(f);
00579         sint ver = f.serialVersion(1);
00580         f.serialEnum(_RibbonMode);
00581         f.serialEnum(_InterpolationMode);
00582         f.serial(_NbSegs, _SegDuration);        
00583         if (_RibbonMode == FixedSize)
00584         {
00585                 f.serial(_RibbonLength);
00586                 if (f.isReading())
00587                 {
00588                         _SegLength = _RibbonLength / _NbSegs;
00589                 }
00590         }
00591 
00592         if (f.isReading())
00593         {
00594                 if (_Owner)
00595                 {                               
00596                         resize(_Owner->getMaxSize());
00597                         initDateVect();         
00598                         resetFromOwner();
00599                 }
00600         }
00601 
00602         if (ver >= 1)
00603         {
00604                 f.serial(_LODDegradation);
00605         }
00606 }
00607 
00608 
00609 //=======================================================       
00610 void CPSRibbonBase::updateLOD()
00611 {
00612         nlassert(_Owner);
00613         float ratio = _Owner->getOwner()->getOneMinusCurrentLODRatio(); 
00614         float squaredRatio = ratio * ratio;
00615         float lodRatio = _LODDegradation + (1.f - _LODDegradation ) * squaredRatio * squaredRatio * squaredRatio;
00616         
00617         _UsedNbSegs = (uint) (_NbSegs * lodRatio);
00618         NLMISC::clamp(_UsedNbSegs, 0u, _NbSegs);
00619         const float epsilon = 10E-4f;   
00620         _UsedSegDuration =  _SegDuration / std::max(epsilon, lodRatio);
00621         _UsedSegLength   =  _SegLength / std::max(epsilon, lodRatio);
00622 
00623 }
00624 
00625 //=======================================================       
00626 void CPSRibbonBase::systemDateChanged()
00627 {
00628         nlassert(_Owner->getOwner());
00629         _Owner->getOwner()->getSystemDate();
00630         float date = _Owner->getOwner()->getSystemDate();
00631         std::fill(_SamplingDate.begin(), _SamplingDate.end(), date);    
00632         _LastUpdateDate = date;
00633 }
00634 
00635 
00636 
00637 } // NL3D
00638 

Generated on Tue Mar 16 06:34:40 2004 for NeL by doxygen 1.3.6