# 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_face.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_face.h"
00029 #include "3d/ps_macro.h"
00030 #include "3d/driver.h"
00031 #include "3d/ps_iterator.h"
00032 #include "nel/misc/quat.h"
00033 
00034 
00035 
00036 namespace NL3D 
00037 {
00038 
00039 using NLMISC::CQuat;
00040 
00042 // CPSFace implementation //
00044 
00050 class CPSFaceHelper
00051 {
00052 public:
00053         template <class T, class U>     
00054         static void drawFaces(T posIt, U indexIt, CPSFace &f, uint size, uint32 srcStep)
00055         {
00056                 PARTICLES_CHECK_MEM;
00057                 nlassert(f._Owner);             
00058                 IDriver *driver = f.getDriver();
00059 
00060                 f.updateMatBeforeRendering(driver);
00061 
00062                 CVertexBuffer &vb = f.getNeededVB();
00063                 uint8 *currVertex;      
00064 
00065                 // number of left faces to draw, number of faces to process at once
00066                 uint32 leftFaces = size, toProcess;
00067                 f._Owner->incrementNbDrawnParticles(size); // for benchmark purpose             
00068                 f.setupDriverModelMatrix();
00069                 driver->activeVertexBuffer(vb);
00070                 if (f.isMultiTextureEnabled())
00071                 {
00072                         f.setupMaterial(f._Tex, driver, f._Mat);
00073                 }
00074                 float sizeBuf[CPSQuad::quadBufSize];
00075                 float *ptSize;          
00076                 T endPosIt;
00077 
00078                 // if constant size is used, the pointer points always the same float 
00079                 uint32 ptSizeIncrement = f._SizeScheme ? 1 : 0;
00080 
00081                 if (f._PrecompBasis.size()) // do we use precomputed basis ?
00082                 {                                       
00083                         do
00084                         {               
00085                                 toProcess = leftFaces > CPSQuad::quadBufSize ? CPSQuad::quadBufSize : leftFaces;
00086                                 currVertex = (uint8 *) vb.getVertexCoordPointer() ; 
00087                                 if (f._SizeScheme)
00088                                 {                               
00089                                         ptSize = (float *) (f._SizeScheme->make(f._Owner, size - leftFaces, sizeBuf, sizeof(float), toProcess, true, srcStep));                                                         
00090                                 }
00091                                 else
00092                                 {       
00093                                         ptSize = &f._ParticleSize;                      
00094                                 }                                       
00095                                 f.updateVbColNUVForRender(vb, size - leftFaces, toProcess, srcStep);                    
00096                                 const uint32 stride = vb.getVertexSize();
00097                                 endPosIt = posIt + toProcess;                                                   
00098                                 do              
00099                                 {                       
00100                                         const CPlaneBasis &currBasis = f._PrecompBasis[*indexIt].Basis;
00101                                         CHECK_VERTEX_BUFFER(vb, currVertex);
00102                                         ((CVector *) currVertex)->x = (*posIt).x  + *ptSize * currBasis.X.x;                    
00103                                         ((CVector *) currVertex)->y = (*posIt).y  + *ptSize * currBasis.X.y;                    
00104                                         ((CVector *) currVertex)->z = (*posIt).z  + *ptSize * currBasis.X.z;                    
00105                                         currVertex += stride;
00106 
00107                                         CHECK_VERTEX_BUFFER(vb, currVertex);
00108                                         ((CVector *) currVertex)->x = (*posIt).x  + *ptSize * currBasis.Y.x;                    
00109                                         ((CVector *) currVertex)->y = (*posIt).y  + *ptSize * currBasis.Y.y;                    
00110                                         ((CVector *) currVertex)->z = (*posIt).z  + *ptSize * currBasis.Y.z;                    
00111                                         currVertex += stride;
00112 
00113                                         CHECK_VERTEX_BUFFER(vb, currVertex);
00114                                         ((CVector *) currVertex)->x = (*posIt).x  - *ptSize * currBasis.X.x;                    
00115                                         ((CVector *) currVertex)->y = (*posIt).y  - *ptSize * currBasis.X.y;                    
00116                                         ((CVector *) currVertex)->z = (*posIt).z  - *ptSize * currBasis.X.z;                    
00117                                         currVertex += stride;
00118 
00119                                         CHECK_VERTEX_BUFFER(vb, currVertex);
00120                                         ((CVector *) currVertex)->x = (*posIt).x  - *ptSize * currBasis.Y.x;                    
00121                                         ((CVector *) currVertex)->y = (*posIt).y  - *ptSize * currBasis.Y.y;                    
00122                                         ((CVector *) currVertex)->z = (*posIt).z  - *ptSize * currBasis.Y.z;                    
00123                                         currVertex += stride;                                           
00124                                         ptSize += ptSizeIncrement;
00125                                         ++indexIt;
00126                                         ++posIt;
00127                                 }
00128                                 while (posIt != endPosIt);
00129                                 driver->renderQuads(f._Mat, 0, toProcess);
00130                                 leftFaces -= toProcess;
00131                         }
00132                         while (leftFaces);
00133                 }
00134                 else
00135                 {
00136                         // must compute each particle basis at each time
00137                         static CPlaneBasis planeBasis[CPSQuad::quadBufSize]; // buffer to compute each particle basis
00138                         CPlaneBasis *currBasis;
00139                         uint32    ptPlaneBasisIncrement = f._PlaneBasisScheme ? 1 : 0;
00140                         const uint32 vSize = vb.getVertexSize();
00141                         do
00142                         {                       
00143                                 toProcess = leftFaces > CPSQuad::quadBufSize ? CPSQuad::quadBufSize : leftFaces;
00144                                 currVertex = (uint8 *) vb.getVertexCoordPointer() ; 
00145                                 if (f._SizeScheme)
00146                                 {                               
00147                                         ptSize  = (float *) (f._SizeScheme->make(f._Owner, size - leftFaces, sizeBuf, sizeof(float), toProcess, true, srcStep));                                                                
00148                                 }
00149                                 else
00150                                 {       
00151                                         ptSize = &f._ParticleSize;                      
00152                                 }
00153 
00154                                 if (f._PlaneBasisScheme)
00155                                 {
00156                                         currBasis = (CPlaneBasis *) (f._PlaneBasisScheme->make(f._Owner, size - leftFaces, planeBasis, sizeof(CPlaneBasis), toProcess, true, srcStep));                         
00157                                 }
00158                                 else
00159                                 {
00160                                         currBasis = &f._PlaneBasis;
00161                                 }                                               
00162                                 f.updateVbColNUVForRender(vb, size - leftFaces, toProcess, srcStep);                                            
00163                                 endPosIt = posIt + toProcess;                                   
00164                                 do              
00165                                 {                       
00166                                         // we use this instead of the + operator, because we avoid 4 constructor calls this way
00167                                         CHECK_VERTEX_BUFFER(vb, currVertex);
00168                                         ((CVector *) currVertex)->x = (*posIt).x  + *ptSize * currBasis->X.x;                   
00169                                         ((CVector *) currVertex)->y = (*posIt).y  + *ptSize * currBasis->X.y;                   
00170                                         ((CVector *) currVertex)->z = (*posIt).z  + *ptSize * currBasis->X.z;                   
00171                                         currVertex += vSize;
00172 
00173                                         CHECK_VERTEX_BUFFER(vb, currVertex);
00174                                         ((CVector *) currVertex)->x = (*posIt).x  + *ptSize * currBasis->Y.x;                   
00175                                         ((CVector *) currVertex)->y = (*posIt).y  + *ptSize * currBasis->Y.y;                   
00176                                         ((CVector *) currVertex)->z = (*posIt).z  + *ptSize * currBasis->Y.z;                   
00177                                         currVertex += vSize;
00178 
00179                                         CHECK_VERTEX_BUFFER(vb, currVertex);
00180                                         ((CVector *) currVertex)->x = (*posIt).x  - *ptSize * currBasis->X.x;                   
00181                                         ((CVector *) currVertex)->y = (*posIt).y  - *ptSize * currBasis->X.y;                   
00182                                         ((CVector *) currVertex)->z = (*posIt).z  - *ptSize * currBasis->X.z;                   
00183                                         currVertex += vSize;
00184 
00185                                         CHECK_VERTEX_BUFFER(vb, currVertex);
00186                                         ((CVector *) currVertex)->x = (*posIt).x  - *ptSize * currBasis->Y.x;                   
00187                                         ((CVector *) currVertex)->y = (*posIt).y  - *ptSize * currBasis->Y.y;                   
00188                                         ((CVector *) currVertex)->z = (*posIt).z  - *ptSize * currBasis->Y.z;                   
00189                                         currVertex += vSize;
00190                                         ptSize += ptSizeIncrement;                                              
00191                                         ++posIt;
00192                                         currBasis += ptPlaneBasisIncrement;
00193                                 }
00194                                 while (posIt != endPosIt);
00195                                 driver->renderQuads(f._Mat, 0, toProcess);
00196                                 leftFaces -= toProcess;
00197                         }
00198                         while (leftFaces);
00199                 }
00200                 PARTICLES_CHECK_MEM;    
00201         }
00202 };
00203 
00205 CPSFace::CPSFace(CSmartPtr<ITexture> tex) : CPSQuad(tex)
00206 {   
00207         _Name = std::string("Face");    
00208 }
00209 
00211 void CPSFace::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime)
00212 {
00213         if (pass == PSToolRender) // edition mode only
00214         {                       
00215                 showTool();
00216                 return;
00217         }
00218         else if (pass == PSMotion)
00219         {
00220                 
00221                 if (_PrecompBasis.size()) // do we use precomputed basis ?
00222                 {                       
00223                         // rotate all precomputed basis         
00224                         for (std::vector< CPlaneBasisPair >::iterator it = _PrecompBasis.begin(); it != _PrecompBasis.end(); ++it)
00225                         {
00226                                 // not optimized at all, but this will apply to very few elements anyway...
00227                                 CMatrix mat;
00228                                 mat.rotate(CQuat(it->Axis, ellapsedTime * it->AngularVelocity));
00229                                 CVector n = mat * it->Basis.getNormal();
00230                                 it->Basis = CPlaneBasis(n);
00231                         }
00232                 }
00233                 return;
00234         }
00235         else    // check this is the right pass
00236         if (!
00237                 (       (pass == PSBlendRender && hasTransparentFaces())
00238                         || (pass == PSSolidRender && hasOpaqueFaces())
00239                 )
00240            )
00241         {
00242                 return;
00243         }
00244         
00245         
00246 
00247         if (!_Owner->getSize()) return; 
00248         uint32 step;
00249         uint   numToProcess;
00250         computeSrcStep(step, numToProcess);     
00251         if (!numToProcess) return;
00252 
00253         
00254         if (step == (1 << 16))
00255         {
00257                 std::vector<uint32>::const_iterator indexIt = _IndexInPrecompBasis.begin();
00258 
00260                 CPSFaceHelper::drawFaces(_Owner->getPos().begin(),      
00261                                                                  indexIt,
00262                                                                  *this,
00263                                                                  numToProcess,
00264                                                                  step
00265                                                                 );
00266         }
00267         else
00268         {               
00270                 CAdvance1616Iterator<std::vector<uint32>::const_iterator, const uint32>                 
00271                         indexIt(_IndexInPrecompBasis.begin(), 0, step);
00272                 CPSFaceHelper::drawFaces(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
00273                                                                  indexIt,
00274                                                                  *this,
00275                                                                  numToProcess,
00276                                                                  step                           
00277                                                                 );
00278         }
00279         
00280 }
00281 
00282 
00284 void CPSFace::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00285 {
00286         f.serialVersion(1);
00287         CPSQuad::serial(f);
00288         CPSRotated3DPlaneParticle::serialPlaneBasisScheme(f);
00289 
00290         if (f.isReading())
00291         {
00292                 uint32 nbConfigurations;
00293                 f.serial(nbConfigurations);
00294                 if (nbConfigurations)
00295                 {
00296                         f.serial(_MinAngularVelocity, _MaxAngularVelocity);             
00297                 }
00298                 hintRotateTheSame(nbConfigurations, _MinAngularVelocity, _MaxAngularVelocity);
00299 
00300                 init();         
00301         }
00302         else    
00303         {                               
00304                 uint32 nbConfigurations = _PrecompBasis.size();
00305                 f.serial(nbConfigurations);
00306                 if (nbConfigurations)
00307                 {
00308                         f.serial(_MinAngularVelocity, _MaxAngularVelocity);             
00309                 }
00310         }
00311 }
00312         
00313         
00316 static CVector MakeRandomUnitVect(void) 
00317 {
00318         CVector v((float) ((rand() % 20000) - 10000)
00319                           ,(float) ((rand() % 20000) - 10000)
00320                           ,(float) ((rand() % 20000) - 10000)
00321                           );
00322         v.normalize();
00323         return v;
00324 }
00325 
00327 void CPSFace::hintRotateTheSame(uint32 nbConfiguration
00328                                                 , float minAngularVelocity
00329                                                 , float maxAngularVelocity
00330                                           )
00331 {
00332         _MinAngularVelocity = minAngularVelocity;
00333         _MaxAngularVelocity = maxAngularVelocity;
00334         _PrecompBasis.resize(nbConfiguration);
00335         if (nbConfiguration)
00336         {
00337                 // each precomp basis is created randomly;
00338                 for (uint k = 0; k < nbConfiguration; ++k)
00339                 {
00340                          CVector v = MakeRandomUnitVect();
00341                         _PrecompBasis[k].Basis = CPlaneBasis(v);
00342                         _PrecompBasis[k].Axis = MakeRandomUnitVect();
00343                         _PrecompBasis[k].AngularVelocity = minAngularVelocity 
00344                                                                                            + (rand() % 20000) / 20000.f * (maxAngularVelocity - minAngularVelocity);
00345 
00346                 }       
00347                 // we need to do this because nbConfs may have changed
00348                 fillIndexesInPrecompBasis();
00349         }
00350 }
00351 
00353 void CPSFace::fillIndexesInPrecompBasis(void)
00354 {
00355         const uint32 nbConf = _PrecompBasis.size();
00356         if (_Owner)
00357         {
00358                 _IndexInPrecompBasis.resize( _Owner->getMaxSize() );
00359         }       
00360         for (std::vector<uint32>::iterator it = _IndexInPrecompBasis.begin(); it != _IndexInPrecompBasis.end(); ++it)
00361         {
00362                 *it = rand() % nbConf;
00363         }
00364 }
00365 
00367 void CPSFace::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00368 {
00369         CPSQuad::newElement(emitterLocated, emitterIndex);
00370         newPlaneBasisElement(emitterLocated, emitterIndex);
00371         const uint32 nbConf = _PrecompBasis.size();
00372         if (nbConf) // do we use precomputed basis ?
00373         {
00374                 _IndexInPrecompBasis[_Owner->getNewElementIndex()] = rand() % nbConf;
00375         }       
00376 }
00377         
00379         void CPSFace::deleteElement(uint32 index)
00380 {
00381         CPSQuad::deleteElement(index);
00382         deletePlaneBasisElement(index);
00383         if (_PrecompBasis.size()) // do we use precomputed basis ?
00384         {
00385                 // replace ourself by the last element...
00386                 _IndexInPrecompBasis[index] = _IndexInPrecompBasis[_Owner->getSize() - 1];
00387         }       
00388 }
00389 
00391 void CPSFace::resize(uint32 size)
00392 {
00393         nlassert(size < (1 << 16));
00394         resizePlaneBasis(size);
00395         if (_PrecompBasis.size()) // do we use precomputed basis ?
00396         {
00397                 _IndexInPrecompBasis.resize(size);
00398         }
00399         CPSQuad::resize(size);
00400 }
00401 
00402 } // NL3D