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

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000, 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_mesh.h"
00029 #include "3d/ps_macro.h"
00030 #include "3d/shape.h"
00031 #include "3d/mesh.h"
00032 #include "3d/transform_shape.h"
00033 #include "3d/shape_bank.h"
00034 #include "3d/texture_mem.h"
00035 #include "3d/scene.h"
00036 #include "3d/ps_located.h"
00037 #include "3d/particle_system.h"
00038 #include "3d/particle_system_shape.h"
00039 #include "3d/ps_iterator.h"
00040 #include "nel/misc/stream.h"
00041 #include "nel/misc/path.h"
00042 
00043 #include <memory>
00044 
00045 
00046 
00047 
00048 
00049 namespace NL3D 
00050 {
00051 
00053 // static members //
00055 
00056 
00057 
00058 
00059 CPSConstraintMesh::CMeshDisplayShare            CPSConstraintMesh::_MeshDisplayShare(16);       
00060 CVertexBuffer                                                           CPSConstraintMesh::_PreRotatedMeshVB;                     // mesh has no normals
00061 CVertexBuffer                                                           CPSConstraintMesh::_PreRotatedMeshVBWithNormal;  // mesh has normals
00062 
00063 
00064 
00065 // this produce a random unit vector
00066 static CVector MakeRandomUnitVect(void) 
00067 {
00068         CVector v((float) ((rand() % 20000) - 10000)
00069                           ,(float) ((rand() % 20000) - 10000)
00070                           ,(float) ((rand() % 20000) - 10000)
00071                           );
00072         v.normalize();
00073         return v;
00074 }
00075 
00076 
00078 // CPSMesh implementation //
00080 
00081 
00082 //====================================================================================
00083 
00084 
00085 
00086 
00087 const std::string DummyShapeName("dummy mesh shape");
00088 
00092 static CMesh *CreateDummyShape(void)
00093 {
00094         CMesh::CMeshBuild mb;
00095         CMeshBase::CMeshBaseBuild mbb;
00096 
00097         mb.VertexFlags = CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag;
00098         mb.Vertices.push_back(CVector(-.5f, -.5f, -.5f));
00099         mb.Vertices.push_back(CVector(.5f, -.5f, -.5f));
00100         mb.Vertices.push_back(CVector(.5f, -.5f, .5f));
00101         mb.Vertices.push_back(CVector(-.5f, -.5f, .5f));
00102 
00103         mb.Vertices.push_back(CVector(-.5f, .5f, -.5f));
00104         mb.Vertices.push_back(CVector(.5f, .5f, -.5f));
00105         mb.Vertices.push_back(CVector(.5f, .5f, .5f));
00106         mb.Vertices.push_back(CVector(-.5f, .5f, .5f));
00107 
00108         // index for each face
00109         uint32 tab[] = { 4, 1, 0,
00110                                          4, 5, 1,
00111                                          5, 2, 1,
00112                                          5, 6, 2,
00113                                          6, 3, 2,
00114                                          6, 7, 3,
00115                                          7, 0, 3,
00116                                          7, 4, 0,
00117                                          7, 5, 4,
00118                                          7, 6, 5,
00119                                          2, 0, 1,
00120                                          2, 3, 0
00121                                         };
00122 
00123         for (uint k = 0; k < 6; ++k)
00124         {
00125                 CMesh::CFace f;
00126                 f.Corner[0].Vertex = tab[6 * k];
00127                 f.Corner[0].Uvws[0] = NLMISC::CUVW(0, 0, 0);
00128 
00129                 f.Corner[1].Vertex = tab[6 * k + 1];
00130                 f.Corner[1].Uvws[0] = NLMISC::CUVW(1, 1, 0);
00131 
00132                 f.Corner[2].Vertex = tab[6 * k + 2];
00133                 f.Corner[2].Uvws[0] = NLMISC::CUVW(0, 1, 0);
00134 
00135                 f.MaterialId = 0;
00136 
00137                 mb.Faces.push_back(f);
00138 
00139                 f.Corner[0].Vertex = tab[6 * k + 3];
00140                 f.Corner[0].Uvws[0] = NLMISC::CUVW(0, 0, 0);
00141 
00142                 f.Corner[1].Vertex = tab[6 * k + 4];
00143                 f.Corner[1].Uvws[0] = NLMISC::CUVW(1, 0, 0);
00144 
00145                 f.Corner[2].Vertex = tab[6 * k + 5];
00146                 f.Corner[2].Uvws[0] = NLMISC::CUVW(1, 1, 0);
00147 
00148                 f.MaterialId = 0;
00149                 mb.Faces.push_back(f);          
00150         }
00151 
00152         CMaterial mat;
00153         CTextureMem *tex = new CTextureMem;
00154         tex->makeDummy();
00155         mat.setTexture(0, tex);
00156         mat.setLighting(false);
00157         mat.setColor(CRGBA::White);
00158         mbb.Materials.push_back(mat);
00159         CMesh *m = new CMesh;
00160         m->build(mbb, mb);
00161         return m;
00162 } 
00163 
00164 
00165 //====================================================================================
00166 void CPSMesh::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00167 {       
00168         (void)f.serialVersion(3);       
00169         CPSParticle::serial(f);
00170         CPSSizedParticle::serialSizeScheme(f);
00171         CPSRotated3DPlaneParticle::serialPlaneBasisScheme(f);
00172         CPSRotated2DParticle::serialAngle2DScheme(f);
00173         f.serial(_Shape);
00174         if (f.isReading())
00175         {
00176                 invalidate();
00177         }
00178 }
00179 
00180 
00181 //====================================================================================
00182 uint32 CPSMesh::getMaxNumFaces(void) const
00183 {
00185         return 0;
00186 }
00187 
00188 //====================================================================================
00189 bool CPSMesh::hasTransparentFaces(void)
00190 {
00192         return false;
00193 }
00194 
00195 //====================================================================================
00196 bool CPSMesh::hasOpaqueFaces(void)
00197 {
00199         return false;
00200 }
00201 
00202 //====================================================================================
00203 void CPSMesh::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00204 {
00205         newPlaneBasisElement(emitterLocated, emitterIndex);
00206         newAngle2DElement(emitterLocated, emitterIndex);
00207         newSizeElement(emitterLocated, emitterIndex);
00208 
00209         nlassert(_Owner);
00210         nlassert(_Owner->getOwner());
00211 
00212         CScene *scene = _Owner->getScene();
00213         nlassert(scene); // the setScene method of the particle system should have been called
00214         //CTransformShape *instance = _Shape->createInstance(*scene);
00215 
00216         CTransformShape *instance = scene->createInstance(_Shape);
00217 
00218         if (!instance)
00219         {
00220                 
00221                 // mesh not found ...
00222                 IShape *is = CreateDummyShape();
00223                 scene->getShapeBank()->add(DummyShapeName, is);
00224                 instance = scene->createInstance(DummyShapeName);
00225                 nlassert(instance);
00226         }
00227 
00228 
00229         instance->setTransformMode(CTransform::DirectMatrix);
00230 
00231         instance->hide(); // the object hasn't the right matrix yet so we hide it. It'll be shown once it is computed
00232         nlassert(instance);
00233 
00234         _Instances.insert(instance);
00235 }
00236 
00237 //====================================================================================  
00238 void CPSMesh::deleteElement(uint32 index)
00239 {       
00240         deleteSizeElement(index);
00241         deleteAngle2DElement(index);
00242         deletePlaneBasisElement(index);
00243 
00244         // check wether CTransformShape have been instanciated
00245         if (_Invalidated) return;
00246 
00247         nlassert(_Owner);
00248         nlassert(_Owner->getOwner());
00249 
00250         CScene *scene = _Owner->getScene();
00251         nlassert(scene); // the setScene method of the particle system should have been called
00252 
00253         scene->deleteInstance(_Instances[index]);
00254         _Instances.remove(index);
00255 }
00256 
00257 //====================================================================================
00258 void CPSMesh::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEt)
00259 {
00260                 if (pass == PSSolidRender)                      
00261                 {
00262                         updatePos();
00263                 }
00264                 else 
00265                 if (pass == PSToolRender) // edition mode only
00266                 {                       
00267                         showTool();
00268                 }
00269 
00270 }
00271 
00272 //====================================================================================
00273 void CPSMesh::updatePos()
00274 {
00275         const uint MeshBufSize = 512;
00276         PARTICLES_CHECK_MEM;
00277         nlassert(_Owner);
00278         const uint32 size = _Owner->getSize();
00279         if (!size) return;
00280 
00281 
00282         _Owner->incrementNbDrawnParticles(size); // for benchmark purpose       
00283 
00284 
00285         if (_Invalidated)
00286         {
00287                 // need to rebuild all the transform shapes
00288                 nlassert(_Owner);
00289                 nlassert(_Owner->getOwner());
00290 
00291                 CScene *scene = _Owner->getScene();
00292                 nlassert(scene); // the setScene method of the particle system should have been called
00293         
00294 
00295                 resize(_Owner->getMaxSize());
00296 
00297                 for (uint k = 0; k < size; ++k)
00298                 {
00299                         CTransformShape *instance = scene->createInstance(_Shape);
00300                         instance->setTransformMode(CTransform::DirectMatrix);
00301                         instance->hide();
00302                         _Instances.insert(instance);
00303                 }
00304 
00305                 _Invalidated = false;
00306         }
00307         
00308         float sizes[MeshBufSize];
00309         float angles[MeshBufSize];
00310         static CPlaneBasis planeBasis[MeshBufSize];
00311 
00312         uint32 leftToDo = size, toProcess;
00313 
00314 
00315         float *ptCurrSize;
00316         const uint  ptCurrSizeIncrement = _SizeScheme ? 1 : 0;
00317 
00318         float *ptCurrAngle;
00319         const uint  ptCurrAngleIncrement = _Angle2DScheme ? 1 : 0;
00320 
00321         CPlaneBasis *ptBasis;
00322         const uint  ptCurrPlaneBasisIncrement = _PlaneBasisScheme ? 1 : 0;
00323 
00324         TPSAttribVector::const_iterator posIt = _Owner->getPos().begin(), endPosIt;
00325 
00326 
00327         TInstanceCont::iterator instanceIt = _Instances.begin();
00328 
00329         do
00330         {
00331                 toProcess = leftToDo < MeshBufSize ? leftToDo : MeshBufSize;
00332 
00333                 if (_SizeScheme)
00334                 {
00335                         ptCurrSize  = (float *) (_SizeScheme->make(_Owner, size - leftToDo, &sizes[0], sizeof(float), toProcess, true));                        
00336                 }
00337                 else
00338                 {
00339                         ptCurrSize =& _ParticleSize;
00340                 }
00341 
00342                 if (_Angle2DScheme)
00343                 {
00344                         ptCurrAngle  = (float *) (_Angle2DScheme->make(_Owner, size - leftToDo, &angles[0], sizeof(float), toProcess, true));                   
00345                 }
00346                 else
00347                 {
00348                         ptCurrAngle =& _Angle2D;
00349                 }
00350 
00351 
00352                 if (_PlaneBasisScheme)
00353                 {
00354                         ptBasis  = (CPlaneBasis *) (_PlaneBasisScheme->make(_Owner, size - leftToDo, &planeBasis[0], sizeof(CPlaneBasis), toProcess, true));                    
00355                 }
00356                 else
00357                 {
00358                         ptBasis = &_PlaneBasis;
00359                 }
00360 
00361                 endPosIt = posIt + toProcess;           
00362                 CMatrix mat, tmat;              
00363 
00364                 // the matrix used to get in the right basis
00365                 const CMatrix &transfo = _Owner->isInSystemBasis() ? /*_Owner->getOwner()->*/getSysMat() : CMatrix::Identity;
00366                 do
00367                 {
00368                         (*instanceIt)->show();
00369 
00370                         tmat.identity();
00371                         mat.identity();
00372 
00373                         tmat.translate(*posIt);
00374 
00375                         
00376 
00377                         mat.setRot( ptBasis->X * CPSUtil::getCos((sint32) *ptCurrAngle) + ptBasis->Y * CPSUtil::getSin((sint32) *ptCurrAngle)
00378                                                 , ptBasis->X * CPSUtil::getCos((sint32) *ptCurrAngle + 64) + ptBasis->Y * CPSUtil::getSin((sint32) *ptCurrAngle + 64)
00379                                                 , ptBasis->X ^ ptBasis->Y
00380                                           );
00381 
00382                         mat.scale(*ptCurrSize);                 
00383                         
00384                         (*instanceIt)->setMatrix(transfo * tmat * mat);                 
00385 
00386                         ++instanceIt;
00387                         ++posIt;
00388                         ptCurrSize += ptCurrSizeIncrement;
00389                         ptCurrAngle += ptCurrAngleIncrement;
00390                         ptBasis += ptCurrPlaneBasisIncrement;
00391                 }
00392                 while (posIt != endPosIt);
00393                 leftToDo -= toProcess;
00394         }
00395         while (leftToDo);
00396 
00397         PARTICLES_CHECK_MEM;
00398 }
00399 
00400 //====================================================================================
00401 void CPSMesh::resize(uint32 size)
00402 {
00403         nlassert(size < (1 << 16));
00404         resizeSize(size);
00405         resizeAngle2D(size);
00406         resizePlaneBasis(size);
00407         _Instances.resize(size);
00408 }
00409 
00410 
00411 //====================================================================================
00412 CPSMesh::~CPSMesh()
00413 {       
00414         if (_Owner && _Owner->getOwner())
00415         {       
00416                 CScene *scene = _Owner->getScene();
00417                 nlassert(scene); // the setScene method of the particle system should have been called
00418 
00419                 for (TInstanceCont::iterator it = _Instances.begin(); it != _Instances.end(); ++it)
00420                 {
00421                         scene->deleteInstance(*it);
00422                 }
00423         }
00424 }
00425 
00427 // CPSConstraintMesh implementation //
00429 
00431 static uint getMeshNumTri(const CMesh &m)
00432 {       
00433         uint numFaces = 0;
00434         for (uint k = 0; k < m.getNbMatrixBlock(); ++k)
00435         {
00436                 for (uint l = 0; l  < m.getNbRdrPass(k); ++l)
00437                 {
00438                         const CPrimitiveBlock pb = m.getRdrPassPrimitiveBlock(k, l);
00439                         numFaces += (pb.getNumLine() << 1) + pb.getNumTri() + (pb.getNumQuad() << 1);
00440 
00441                 }
00442         }
00443         return numFaces;
00444 }
00445 
00446 
00447 //====================================================================================
00449 static void CheckForOpaqueAndTransparentFacesInMesh(const CMesh &m, bool &hasTransparentFaces, bool &hasOpaqueFaces)
00450 {
00451         hasTransparentFaces = false;
00452         hasOpaqueFaces = false;
00453         
00454         for (uint k = 0; k < m.getNbRdrPass(0); ++k)
00455         {
00456                 const CMaterial &currMat = m.getMaterial(m.getRdrPassMaterial(0, k));
00457                 if (!currMat.getZWrite())
00458                 {
00459                         hasTransparentFaces = true;
00460                 }
00461                 else // z-buffer write or no blending -> the face is opaque
00462                 {
00463                         hasOpaqueFaces = true;
00464                 }
00465         }        
00466 }
00467 
00468 
00469 
00475 class CPSConstraintMeshHelper
00476 {
00477 public:
00478         template <class T>      
00479         static void drawMeshs(T posIt, CPSConstraintMesh &m, uint size, uint32 srcStep, bool opaque)
00480         {
00481                 CMesh                             &mesh = * NLMISC::safe_cast<CMesh *>((IShape *) m._Shapes[0]);        
00482                 const CVertexBuffer   &modelVb = mesh.getVertexBuffer();
00483 
00484                 // size for model vertices
00485                 const uint inVSize        = modelVb.getVertexSize(); // vertex size                             
00486 
00487                 // driver setup
00488                 IDriver *driver = m.getDriver();
00489                 m.setupDriverModelMatrix();     
00490 
00491                 // buffer to compute sizes
00492                 float                   sizes[ConstraintMeshBufSize];
00493                 
00494                 float *ptCurrSize;
00495                 uint ptCurrSizeIncrement = m._SizeScheme ? 1 : 0;
00496 
00497                 T endPosIt;
00498                 uint leftToDo = size, toProcess;                        
00499                 
00501                 CPSConstraintMesh::CMeshDisplay  &md= m._MeshDisplayShare.getMeshDisplay(m._Shapes[0], modelVb.getVertexFormat() 
00502                                                                                                                                 | (m._ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
00503 
00504                 m.setupRenderPasses((float) m._Owner->getOwner()->getSystemDate() - m._GlobalAnimDate, md.RdrPasses, opaque);
00505 
00506                 CVertexBuffer &outVb = md.VB;
00507                 const uint outVSize = outVb.getVertexSize();
00508                 
00509                 driver->activeVertexBuffer(outVb);      
00510 
00511                 // we don't have precomputed mesh there ... so each mesh must be transformed, which is the worst case   
00512                 CPlaneBasis planeBasis[ConstraintMeshBufSize];
00513                 CPlaneBasis *ptBasis;
00514                 uint ptBasisIncrement = m._PlaneBasisScheme ? 1 : 0;
00515 
00516                 const uint nbVerticesInSource   = modelVb.getNumVertices();
00517 
00518                 sint inNormalOff=0;
00519                 sint outNormalOff=0;
00520                 if (modelVb.getVertexFormat() & CVertexBuffer::NormalFlag)
00521                 {       
00522                         inNormalOff  =  modelVb.getNormalOff();
00523                         outNormalOff =  outVb.getNormalOff();   
00524                 }
00525                 
00526                 do
00527                 {
00528                         uint8 *outVertex = (uint8 *) outVb.getVertexCoordPointer();             
00529 
00530                         toProcess = std::min(leftToDo, ConstraintMeshBufSize);
00531 
00532                         if (m._SizeScheme)
00533                         {
00534                                 ptCurrSize  = (float *) (m._SizeScheme->make(m._Owner, size -leftToDo, &sizes[0], sizeof(float), toProcess, true, srcStep));                            
00535                         }
00536                         else
00537                         {
00538                                 ptCurrSize = &m._ParticleSize;
00539                         }
00540 
00541                         if (m._PlaneBasisScheme)
00542                         {
00543                                 ptBasis = (CPlaneBasis *) (m._PlaneBasisScheme->make(m._Owner, size -leftToDo, &planeBasis[0], sizeof(CPlaneBasis), toProcess, true, srcStep));
00544                         }
00545                         else
00546                         {
00547                                 ptBasis = &m._PlaneBasis;
00548                         }
00549                         
00550 
00551                         endPosIt = posIt + toProcess;
00552                         // transfo matrix & scaled transfo matrix;
00553                         CMatrix  M, sM;
00554 
00555                 
00556                         if (m._Shapes.size() == 1)
00557                         {
00559                                 do
00560                                 {
00561 
00562                                         uint8 *inVertex = (uint8 *) modelVb.getVertexCoordPointer();
00563                                         uint k = nbVerticesInSource;
00564 
00565                                         // do we need a normal ?
00566                                         if (modelVb.getVertexFormat() & CVertexBuffer::NormalFlag)
00567                                         {
00568                                                 M.identity();
00569                                                 M.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
00570                                                 sM = M;
00571                                                 sM.scale(*ptCurrSize);
00572 
00573                                                 // offset of normals in the prerotated mesh                             
00574                                                 do
00575                                                 {
00576                                                         CHECK_VERTEX_BUFFER(modelVb, inVertex); 
00577                                                         CHECK_VERTEX_BUFFER(outVb,        outVertex);   
00578                                                         CHECK_VERTEX_BUFFER(modelVb, inVertex + inNormalOff);   
00579                                                         CHECK_VERTEX_BUFFER(outVb,        outVertex + outNormalOff);    
00580 
00581                                                         // translate and resize the vertex (relatively to the mesh origin)
00582                                                         *(CVector *) outVertex = *posIt + sM * *(CVector *) inVertex;                                                                           
00583                                                         // copy the normal
00584                                                         *(CVector *) (outVertex + outNormalOff) = M * *(CVector *) (inVertex + inNormalOff);
00585                                                         
00586 
00587                                                         inVertex  += inVSize;
00588                                                         outVertex += outVSize;
00589                                                 }
00590                                                 while (--k);
00591                                         }
00592                                         else
00593                                         {
00594                                                 // no normal to transform
00595                                                 sM.identity();
00596                                                 sM.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
00597                                                 sM.scale(*ptCurrSize);
00598 
00599                                                 do
00600                                                 {
00601                                                         CHECK_VERTEX_BUFFER(modelVb, inVertex);
00602                                                         CHECK_VERTEX_BUFFER(outVb, outVertex);
00603 
00604                                                         // translate and resize the vertex (relatively to the mesh origin)
00605                                                         *(CVector *) outVertex = *posIt + sM * *(CVector *) inVertex;                           
00606 
00607                                                         inVertex  += inVSize;
00608                                                         outVertex += outVSize;
00609                                                 }
00610                                                 while (--k);
00611                                         }
00612 
00613                                         
00614                                         ++posIt;
00615                                         ptCurrSize += ptCurrSizeIncrement;
00616                                         ptBasis += ptBasisIncrement;
00617                                 }
00618                                 while (posIt != endPosIt);
00619                         }
00620                         else
00621                         {
00622                                 // morphed case
00623                                 
00624                                 // first, compute the morph value for each mesh
00625                                 float   morphValues[ConstraintMeshBufSize];
00626                                 float   *currMorphValue;
00627                                 uint    morphValueIncr;
00628 
00629                                 if (m._MorphScheme) // variable case
00630                                 {
00631                                         currMorphValue = (float *) m._MorphScheme->make(m._Owner, size - leftToDo, &morphValues[0], sizeof(float), toProcess, true, srcStep);
00632                                         morphValueIncr  = 1;
00633                                 }
00634                                 else 
00635                                 {
00636                                         currMorphValue = &m._MorphValue;
00637                                         morphValueIncr  = 0;
00638                                 }
00639 
00640                                 do
00641                                 {
00642                                         const uint numShapes = m._Shapes.size();
00643                                         const uint8 *m0, *m1;
00644                                         float lambda;
00645                                         float opLambda;
00646                                         const CVertexBuffer *inVB0, *inVB1;
00647                                         if (*currMorphValue >= numShapes - 1)
00648                                         {
00649                                                 lambda = 0.f;
00650                                                 opLambda = 1.f;
00651                                                 inVB0 = inVB1 = &NLMISC::safe_cast<CMesh *>((IShape *) m._Shapes[numShapes - 1])->getVertexBuffer();
00652                                         }
00653                                         else if (*currMorphValue <= 0)
00654                                         {
00655                                                 lambda = 0.f;
00656                                                 opLambda = 1.f;
00657                                                 inVB0 = inVB1 = &NLMISC::safe_cast<CMesh *>((IShape *) m._Shapes[0])->getVertexBuffer();
00658                                         }
00659                                         else
00660                                         {
00661                                                 uint iMeshIndex = (uint) *currMorphValue;
00662                                                 lambda = *currMorphValue - iMeshIndex;
00663                                                 opLambda = 1.f - lambda;
00664                                                 inVB0 = &NLMISC::safe_cast<CMesh *>((IShape *) m._Shapes[iMeshIndex])->getVertexBuffer();
00665                                                 inVB1 = &NLMISC::safe_cast<CMesh *>((IShape *) m._Shapes[iMeshIndex + 1])->getVertexBuffer();
00666                                         }
00667 
00668                                         m0 = (uint8 *) inVB0->getVertexCoordPointer();
00669                                         m1 = (uint8 *) inVB1->getVertexCoordPointer();
00670 
00671                                                         
00672                                         uint k = nbVerticesInSource;
00673                                         // do we need a normal ?
00674                                         if (modelVb.getVertexFormat() & CVertexBuffer::NormalFlag)
00675                                         {
00676                                                 M.identity();
00677                                                 M.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
00678                                                 sM = M;
00679                                                 sM.scale(*ptCurrSize);
00680 
00681                                                 // offset of normals in the prerotated mesh                             
00682                                                 do
00683                                                 {
00684                                                         CHECK_VERTEX_BUFFER((*inVB0),     m0);                                                  
00685                                                         CHECK_VERTEX_BUFFER((*inVB1),     m1);  
00686                                                         CHECK_VERTEX_BUFFER((*inVB0),     m0 + inNormalOff);                    
00687                                                         CHECK_VERTEX_BUFFER((*inVB1),     m1 + inNormalOff);
00688                                                         CHECK_VERTEX_BUFFER(outVb,        outVertex);                                                   
00689                                                         CHECK_VERTEX_BUFFER(outVb,        outVertex + outNormalOff);    
00690 
00691                                                         // morph, and transform the vertex
00692                                                         *(CVector *) outVertex = *posIt + sM * (opLambda * *(CVector *) m0 + lambda * *(CVector *) m1);
00693                                                         // morph, and transform the normal
00694                                                         *(CVector *) (outVertex + outNormalOff) = M * (opLambda * *(CVector *) (m0 + inNormalOff)
00695                                                                                                                                                   + lambda * *(CVector *) (m1 + inNormalOff)).normed();
00696                                                         
00697 
00698                                                         m0  += inVSize;
00699                                                         m1  += inVSize;
00700                                                         outVertex += outVSize;
00701                                                 }
00702                                                 while (--k);
00703                                         }
00704                                         else
00705                                         {
00706                                                 // no normal to transform
00707                                                 sM.identity();
00708                                                 sM.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
00709                                                 sM.scale(*ptCurrSize);
00710 
00711                                                 do
00712                                                 {                       
00713                                                         CHECK_VERTEX_BUFFER((*inVB0),     m0);                                                  
00714                                                         CHECK_VERTEX_BUFFER((*inVB1),     m1);          
00715                                                         CHECK_VERTEX_BUFFER(outVb, outVertex);
00716                                                         // morph, and transform the vertex
00717                                                         *(CVector *) outVertex = *posIt + sM * (opLambda * *(CVector *) m0 + opLambda * *(CVector *) m1);
00718 
00719                                                         m0  += inVSize;
00720                                                         m1  += inVSize;
00721                                                         outVertex += outVSize;
00722                                                 }
00723                                                 while (--k);
00724                                         }
00725 
00726                                         
00727                                         ++posIt;
00728                                         ptCurrSize += ptCurrSizeIncrement;
00729                                         ptBasis += ptBasisIncrement;
00730                                         currMorphValue += morphValueIncr;
00731                                 }
00732                                 while (posIt != endPosIt);
00733                         }               
00734 
00735                         // compute colors if needed
00736                         if (m._ColorScheme)
00737                         {
00738                                 m.computeColors(outVb, modelVb, size - leftToDo, toProcess, srcStep);
00739                         }
00740                         
00741                         // render meshs
00742                         m.doRenderPasses(driver, toProcess, md.RdrPasses, opaque);
00743                         leftToDo -= toProcess;
00744 
00745                 }
00746                 while (leftToDo);
00747         }
00748 
00749 
00750         template <class T, class U>     
00751         static void drawPrerotatedMeshs(T posIt,
00752                                                                     U indexIt,
00753                                                                         CPSConstraintMesh &m,
00754                                                                         uint size,
00755                                                                         uint32 srcStep,
00756                                                                         bool opaque,
00757                                                                         TAnimationTime ellapsedTime)
00758         {
00759                 // get the vb from the original mesh
00760                 CMesh                             &mesh = * NLMISC::safe_cast<CMesh *>((IShape *) m._Shapes[0]);        
00761                 const CVertexBuffer   &modelVb = mesh.getVertexBuffer();
00762 
00764                 CVertexBuffer &prerotVb  = m.makePrerotatedVb(modelVb, ellapsedTime);   
00765 
00766                 // driver setup
00767                 IDriver *driver = m.getDriver();
00768                 m.setupDriverModelMatrix();     
00769 
00770                 // renderPasses setup
00771                 nlassert(m._Owner)      
00772 
00773                 // storage for sizes of meshs
00774                 float sizes[ConstraintMeshBufSize];
00775                 
00776                 // point the size for the current mesh
00777                 float *ptCurrSize;
00778                 uint ptCurrSizeIncrement = m._SizeScheme ? 1 : 0;
00779 
00780                 T endPosIt;
00781                 uint leftToDo = size, toProcess;
00782                 const uint nbVerticesInSource = modelVb.getNumVertices();
00783                 
00784 
00785 
00786                 // size of a complete prerotated model
00787                 const uint prerotatedModelSize = prerotVb.getVertexSize() * modelVb.getNumVertices();
00788 
00790                 CPSConstraintMesh::CMeshDisplay  &md    = m._MeshDisplayShare.getMeshDisplay(m._Shapes[0], modelVb.getVertexFormat() 
00791                                                                                                                                 | (m._ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
00792 
00793 
00794                 m.setupRenderPasses((float) m._Owner->getOwner()->getSystemDate() - m._GlobalAnimDate, md.RdrPasses, opaque);
00795 
00796                 CVertexBuffer &outVb = md.VB;
00797 
00798                 driver->activeVertexBuffer(outVb);
00799 
00800 
00801                 // size of vertices in prerotated model
00802                 const uint inVSize = prerotVb.getVertexSize();
00803 
00804                 // size ofr vertices in dest vb
00805                 const uint outVSize = outVb.getVertexSize();
00806 
00807                 // offset of normals in vertices of the prerotated model, and source model              
00808                 uint normalOff=0;
00809                 uint pNormalOff=0;
00810                 if (prerotVb.getVertexFormat() & CVertexBuffer::NormalFlag) 
00811                 {
00812                         normalOff  =  outVb.getNormalOff();
00813                         pNormalOff =  prerotVb.getNormalOff();                  
00814                 }
00815                                         
00816                 do
00817                 {                       
00818                         toProcess = std::min(leftToDo, ConstraintMeshBufSize);
00819 
00820                         if (m._SizeScheme)
00821                         {
00822                                 // compute size
00823                                 ptCurrSize = (float *) (m._SizeScheme->make(m._Owner, size - leftToDo, &sizes[0], sizeof(float), toProcess, true, srcStep));                            
00824                         }
00825                         else
00826                         {
00827                                 // pointer on constant size
00828                                 ptCurrSize = &m._ParticleSize;
00829                         }
00830 
00831                         endPosIt = posIt + toProcess;
00832                         uint8 *outVertex  = (uint8 *) outVb.getVertexCoordPointer();
00834                         do
00835                         {
00836                                 uint8 *inVertex = (uint8 *) prerotVb.getVertexCoordPointer() + prerotatedModelSize * *indexIt; // prerotated vertex                     
00837                                 uint k = nbVerticesInSource;
00838                                 
00839                                 if (prerotVb.getVertexFormat() & CVertexBuffer::NormalFlag) // has it a normal ?
00840                                 {
00841                                         do
00842                                         {
00843                                                 CHECK_VERTEX_BUFFER(outVb, outVertex);
00844                                                 CHECK_VERTEX_BUFFER(prerotVb, inVertex);
00845                                                 CHECK_VERTEX_BUFFER(outVb, outVertex + normalOff);
00846                                                 CHECK_VERTEX_BUFFER(prerotVb, inVertex + pNormalOff);
00847 
00848 
00849                                                 // translate and resize the vertex (relatively to the mesh origin)
00850                                                 *(CVector *)  outVertex                                          = *posIt + *ptCurrSize * *(CVector *) inVertex;
00851                                                 // copy the normal
00852                                                 *(CVector *)  (outVertex + normalOff ) = *(CVector *) (inVertex + pNormalOff);
00853                                                 inVertex  += inVSize;
00854                                                 outVertex += outVSize;
00855                                         }
00856                                         while (--k);
00857                                 }
00858                                 else
00859                                 {
00860                                         do
00861                                         {                                       
00862                                                 // translate and resize the vertex (relatively to the mesh origin)
00863                                                 CHECK_VERTEX_BUFFER(outVb, outVertex);
00864                                                 CHECK_VERTEX_BUFFER(prerotVb, inVertex);
00865                                                 *(CVector *)  outVertex = *posIt + *ptCurrSize * *(CVector *) inVertex;                                                                                                 
00866                                                 inVertex  += inVSize;
00867                                                 outVertex += outVSize;
00868                                         }
00869                                         while (--k);
00870                                 }
00871                                 
00872                                 ++indexIt;
00873                                 ++posIt;
00874                                 ptCurrSize += ptCurrSizeIncrement;
00875                         }
00876                         while (posIt != endPosIt);
00877 
00878                         // compute colors if needed
00879                         if (m._ColorScheme)
00880                         {
00881                                 m.computeColors(outVb, modelVb, size - leftToDo, toProcess, srcStep);
00882                         }
00883                                         
00884 
00886                         m.doRenderPasses(driver, toProcess, md.RdrPasses, opaque);
00887                         leftToDo -= toProcess;
00888 
00889                 }
00890                 while (leftToDo);
00891                 PARTICLES_CHECK_MEM
00892         }
00893 };
00894 
00895 CPSConstraintMesh::CPSConstraintMesh() : _NumFaces(0),
00896                                                                                  _ModelBank(NULL),
00897                                                                                  _ModulatedStages(0),
00898                                                                                  _Touched(1),
00899                                                                                  _VertexColorLightingForced(false),
00900                                                                                  _GlobalAnimationEnabled(0),
00901                                                                                  _ReinitGlobalAnimTimeOnNewElement(0),
00902                                                                                  _MorphValue(0),
00903                                                                                  _MorphScheme(NULL)
00904 {               
00905         _Name = std::string("ConstraintMesh");
00906 }
00907 
00908 //====================================================================================
00909 uint32 CPSConstraintMesh::getMaxNumFaces(void) const
00910 {
00911 //      nlassert(_ModelVb);
00912         return _NumFaces * _Owner->getMaxSize();
00913         
00914 }
00915 
00916 
00917 //====================================================================================
00918 bool CPSConstraintMesh::hasTransparentFaces(void)
00919 {
00920         if (!_Touched) return _HasTransparentFaces != 0;
00922         update();
00923         return _HasTransparentFaces != 0;
00924 }
00925 
00926 //====================================================================================
00927 bool CPSConstraintMesh::hasOpaqueFaces(void)
00928 {
00929         if (!_Touched) return _HasOpaqueFaces != 0;     
00930         update();
00931         return _HasOpaqueFaces != 0;
00932 }
00933 
00934 //====================================================================================
00935 void CPSConstraintMesh::setShape(const std::string &meshFileName)
00936 {       
00937         _MeshShapeFileName.resize(1);   
00938         _MeshShapeFileName[0] = meshFileName;
00939         _Touched = 1;
00940 }
00941 
00942 
00943 //===========================================================================
00944 std::string                     CPSConstraintMesh::getShape(void) const
00945 {
00946         nlassert(_MeshShapeFileName.size() == 1);
00947         return _MeshShapeFileName[0];
00948 }
00949 
00950 //====================================================================================
00951 void            CPSConstraintMesh::setShapes(const std::string *shapesNames, uint numShapes)
00952 {
00953         _MeshShapeFileName.resize(numShapes);
00954         std::copy(shapesNames, shapesNames + numShapes, _MeshShapeFileName.begin());
00955         _Touched = 1;
00956 }
00957 
00958 //====================================================================================
00959 uint        CPSConstraintMesh::getNumShapes() const
00960 {
00961         return _MeshShapeFileName.size();
00962 }
00963 
00964 //====================================================================================
00965 void    CPSConstraintMesh::getShapesNames(std::string *shapesNames) const
00966 {
00967         std::copy(_MeshShapeFileName.begin(), _MeshShapeFileName.end(), shapesNames);
00968 }
00969 
00970 
00971 
00972 //====================================================================================
00973 void            CPSConstraintMesh::setShape(uint index, const std::string &shapeName)
00974 {
00975         nlassert(index < _MeshShapeFileName.size());
00976         _MeshShapeFileName[index] = shapeName;
00977         _Touched = 1;
00978 }
00979 
00980         
00981 //====================================================================================
00982 const std::string          &CPSConstraintMesh::getShape(uint index) const
00983 {
00984         nlassert(index < _MeshShapeFileName.size());
00985         return _MeshShapeFileName[index];
00986 }
00987 
00988 
00989 
00990 //====================================================================================
00991 void    CPSConstraintMesh::setMorphValue(float value)
00992 {
00993         delete _MorphScheme;
00994         _MorphScheme = NULL;
00995         _MorphValue = value;
00996 }
00997 
00998 
00999 //====================================================================================
01000 float   CPSConstraintMesh::getMorphValue() const
01001 {
01002         return _MorphValue;
01003 }
01004 
01005 //====================================================================================
01006 void    CPSConstraintMesh::setMorphScheme(CPSAttribMaker<float> *scheme)
01007 {
01008         delete _MorphScheme;
01009         _MorphScheme = scheme;
01010         if (_MorphScheme->hasMemory()) _MorphScheme->resize(_Owner->getMaxSize(), _Owner->getSize());
01011 }
01012 
01013 //====================================================================================
01014 CPSAttribMaker<float>           *CPSConstraintMesh::getMorphScheme()
01015 {
01016         return _MorphScheme;
01017 }
01018 
01019 //====================================================================================
01020 const CPSAttribMaker<float>     *CPSConstraintMesh::getMorphScheme() const
01021 {
01022         return _MorphScheme;
01023 }
01024 
01025 
01026 //====================================================================================
01027 static IShape *GetDummyShapeFromBank(CShapeBank &sb)
01028 {       
01029         static const std::string dummyMeshName("dummy constraint mesh shape");
01030         if (sb.isPresent(dummyMeshName) == CShapeBank::Present)
01031         {                               
01032                 return sb.addRef(dummyMeshName);
01033         }
01034         else
01035         {
01036                 // no dummy shape created -> add one to the bank
01037                 IShape *is = CreateDummyShape();
01038                 sb.add(std::string("dummy constraint mesh shape"), is);
01039                 return is;
01040         }
01041 }
01042 
01043 //====================================================================================
01044 bool CPSConstraintMesh::update(void)
01045 {               
01046         bool ok = true;
01047         if (!_Touched) return ok;
01048 
01049         clean();
01050         
01051         nlassert(_Owner->getScene());
01052 
01053         CScene *scene = _Owner->getScene();
01054         CShapeBank *sb = scene->getShapeBank();
01055         IShape *is;
01056 
01057 
01058         uint32 vFormat=0;
01059         uint   numVerts=0;      
01060 
01061         if (_MeshShapeFileName.size() == 0)
01062         {
01063                 _MeshShapeFileName.resize(1);
01064                 _MeshShapeFileName[0] = DummyShapeName;         
01065         }
01066         
01067 
01068         _Shapes.resize(_MeshShapeFileName.size());      
01069         for (uint k = 0; k < _MeshShapeFileName.size(); ++k)
01070         {
01071                 if (sb->isPresent(_MeshShapeFileName[k]) == CShapeBank::Present)
01072                 {
01073                         _Shapes[k] = sb->addRef(_MeshShapeFileName[k]);
01074 
01076                         const CMesh &m  = * NLMISC::safe_cast<CMesh *>((IShape *) _Shapes[k]); // only mesh shape's can be used with this class!
01077                         if (k == 0)
01078                         {                       
01079                                 vFormat = m.getVertexBuffer().getVertexFormat();
01080                                 numVerts =  m.getVertexBuffer().getNumVertices();
01081                         }
01082                         else
01083                         {
01084                                 if (vFormat != m.getVertexBuffer().getVertexFormat()
01085                                         || numVerts != m.getVertexBuffer().getNumVertices())
01086                                 {
01087                                         ok = false;
01088                                 }
01089                         }
01090                 }
01091                 else
01092                 {
01093                         try
01094                         {
01095                                 sb->load(_MeshShapeFileName[k]);
01096                         }       
01097                         catch (NLMISC::EPathNotFound &)
01098                         {
01099                                 nlwarning("mesh not found : %s; used as a constraint mesh particle", _MeshShapeFileName[k].c_str());
01100                                 // shape not found, so not present in the shape bank -> we create a dummy shape
01101                         }
01102 
01103                         if (sb->isPresent(_MeshShapeFileName[k]) != CShapeBank::Present)
01104                         {                                       
01105                                 ok = false;
01106                         }
01107                         else
01108                         {
01109                                 is = sb->addRef(_MeshShapeFileName[k]);
01110                                 if (!dynamic_cast<CMesh *>(is)) // is it a mesh
01111                                 {
01112                                         nlwarning("Tried to bind a shape that is not a mesh to a mesh particle : %s", _MeshShapeFileName[k].c_str());
01113                                         sb->release(is);                                        
01114                                         ok = false;
01115                                 }
01116                                 else
01117                                 {
01118                                         const CMesh &m  = * NLMISC::safe_cast<CMesh *>(is);
01120                                         if (m.getVertexBuffer().getNumVertices() > ConstraintMeshMaxNumVerts)
01121                                         {
01122                                                 nlwarning("Tried to bind a mesh that has more than %d vertices to a particle mesh: %s", (int) ConstraintMeshMaxNumVerts, _MeshShapeFileName[k].c_str());
01123                                                 sb->release(is);                                                
01124                                                 ok = false;
01125                                         }
01126                                         else
01127                                         {
01128                                                 _Shapes[k] = is;
01130                                                 const CMesh &m  = * NLMISC::safe_cast<CMesh *>((IShape *) _Shapes[k]); // only mesh shape's can be used with this class!
01131                                                 if (k == 0)
01132                                                 {                       
01133                                                         vFormat = m.getVertexBuffer().getVertexFormat();
01134                                                         numVerts =  m.getVertexBuffer().getNumVertices();
01135                                                 }
01136                                                 else
01137                                                 {
01138                                                         if (vFormat != m.getVertexBuffer().getVertexFormat()
01139                                                                 || numVerts != m.getVertexBuffer().getNumVertices())
01140                                                         {
01141                                                                 ok = false;
01142                                                         }
01143                                                 }
01144                                         }
01145                                 }
01146                         }
01147                 }
01148                 
01149                 if (!ok)
01150                 {
01151                         releaseShapes();
01152                         _Shapes.resize(1);
01153                         _Shapes[0] = GetDummyShapeFromBank(*sb);
01154                         break;
01155                 }
01156         }
01157 
01158 
01159         const CMesh &m  = * NLMISC::safe_cast<CMesh *>((IShape *) _Shapes[0]); // only mesh shape's can be used with this class!
01160 
01162         _NumFaces = getMeshNumTri(m);
01163         notifyOwnerMaxNumFacesChanged();
01164         
01166         bool hasTransparentFaces, hasOpaqueFaces;
01167         CheckForOpaqueAndTransparentFacesInMesh(m, hasTransparentFaces, hasOpaqueFaces);
01168         _HasTransparentFaces = hasTransparentFaces;     
01169         _HasOpaqueFaces = hasOpaqueFaces;
01170         _ModelBank = sb;        
01171         _GlobalAnimDate = _Owner->getOwner()->getSystemDate();
01172         _Touched = 0;
01173         nlassert(_Shapes.size() > 0);
01174 
01175         #ifdef NL_DEBUG
01176                 for (uint j = 0; j < _Shapes.size(); ++j)
01177                 {
01178                         nlassert(dynamic_cast<CMesh *>((IShape *) _Shapes[j]));
01179                 }
01180         #endif
01181 
01182         return ok;
01183         
01184 }
01185 
01186 
01187 
01188 //====================================================================================
01189 void CPSConstraintMesh::hintRotateTheSame(uint32 nbConfiguration,
01190                                                                                   float minAngularVelocity,
01191                                                                                   float maxAngularVelocity
01192                                                                                 )
01193 {
01194         nlassert(nbConfiguration <= ConstraintMeshMaxNumPrerotatedModels);
01195 
01196         // TODO : avoid code duplication with CPSFace ...
01197         _MinAngularVelocity = minAngularVelocity;
01198         _MaxAngularVelocity = maxAngularVelocity;
01199 
01200 
01201 
01202         _PrecompBasis.resize(nbConfiguration);
01203 
01204         if (nbConfiguration)
01205         {
01206                 // each precomp basis is created randomly;
01207                 for (uint k = 0; k < nbConfiguration; ++k)
01208                 {
01209                          CVector v = MakeRandomUnitVect();
01210                         _PrecompBasis[k].Basis = CPlaneBasis(v);
01211                         _PrecompBasis[k].Axis = MakeRandomUnitVect();
01212                         _PrecompBasis[k].AngularVelocity = minAngularVelocity 
01213                                                                                            + (rand() % 20000) / 20000.f * (maxAngularVelocity - minAngularVelocity);
01214 
01215                 }       
01216 
01217                 // we need to do this because nbConfs may have changed
01218                 fillIndexesInPrecompBasis();
01219         }       
01220 }
01221 
01222 
01223 //====================================================================================
01224 void CPSConstraintMesh::fillIndexesInPrecompBasis(void)
01225 {
01226         // TODO : avoid code duplication with CPSFace ...
01227         const uint32 nbConf = _PrecompBasis.size();
01228         if (_Owner)
01229         {
01230                 _IndexInPrecompBasis.resize( _Owner->getMaxSize() );
01231         }       
01232         for (std::vector<uint32>::iterator it = _IndexInPrecompBasis.begin(); it != _IndexInPrecompBasis.end(); ++it)
01233         {
01234                 *it = rand() % nbConf;
01235         }
01236 }
01237 
01238 //====================================================================================  
01240 void CPSConstraintMesh::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01241 {
01242 
01243         sint ver = f.serialVersion(4);
01244         if (f.isReading())
01245         {
01246                 clean();
01247         }
01248 
01249         CPSParticle::serial(f);
01250         CPSSizedParticle::serialSizeScheme(f);
01251         CPSRotated3DPlaneParticle::serialPlaneBasisScheme(f);
01252 
01253         // prerotations ...
01254 
01255         if (f.isReading())
01256         {
01257                 uint32 nbConfigurations;
01258                 f.serial(nbConfigurations);
01259                 if (nbConfigurations)
01260                 {
01261                         f.serial(_MinAngularVelocity, _MaxAngularVelocity);             
01262                 }
01263                 hintRotateTheSame(nbConfigurations, _MinAngularVelocity, _MaxAngularVelocity);  
01264         }
01265         else    
01266         {                               
01267                 uint32 nbConfigurations = _PrecompBasis.size();
01268                 f.serial(nbConfigurations);
01269                 if (nbConfigurations)
01270                 {
01271                         f.serial(_MinAngularVelocity, _MaxAngularVelocity);             
01272                 }
01273         }
01274 
01275         // saves the model file name, or an empty string if nothing has been set        
01276         static std::string emptyStr;
01277 
01278         if (ver < 4) // early version : no morphing support
01279         {
01280                 if (!f.isReading())
01281                 {
01282                         if (_MeshShapeFileName.size() > 0)
01283                         {
01284                                 f.serial(_MeshShapeFileName[0]);                        
01285                         }
01286                         else
01287                         {
01288                                 f.serial(emptyStr); 
01289                         }
01290                 }
01291                 else
01292                 {       
01293                         _MeshShapeFileName.resize(1);                           
01294                         f.serial(_MeshShapeFileName[0]);
01295                         _Touched = true;                        
01296                 }
01297         }
01298 
01299         if (ver > 1)
01300         {
01301                 CPSColoredParticle::serialColorScheme(f);
01302                 f.serial(_ModulatedStages);
01303                 if (f.isReading())
01304                 {
01305                         bool vcEnabled;
01306                         f.serial(vcEnabled);
01307                         _VertexColorLightingForced = vcEnabled;
01308                 }
01309                 else
01310                 {
01311                         bool vcEnabled = (_VertexColorLightingForced != 0);
01312                         f.serial(vcEnabled);
01313                 }                                               
01314         }
01315 
01316         if (ver > 2) // texture animation
01317         {
01318                 if (f.isReading())
01319                 {
01320                         bool gaEnabled;
01321                         f.serial(gaEnabled);
01322                         _GlobalAnimationEnabled = gaEnabled;
01323                         if (gaEnabled)
01324                         {
01325                                 PGlobalTexAnims newPtr(new CGlobalTexAnims); // create new
01326                                 std::swap(_GlobalTexAnims, newPtr);                      // replace old
01327                                 f.serial(*_GlobalTexAnims);
01328                         }
01329 
01330                         bool rgt;
01331                         f.serial(rgt);
01332                         _ReinitGlobalAnimTimeOnNewElement = rgt;
01333                 }
01334                 else
01335                 {
01336                         bool gaEnabled = (_GlobalAnimationEnabled != 0);
01337                         f.serial(gaEnabled);
01338                         if (gaEnabled)
01339                         {
01340                                 f.serial(*_GlobalTexAnims);
01341                         }
01342 
01343                         bool rgt = _ReinitGlobalAnimTimeOnNewElement != 0;
01344                         f.serial(rgt);                  
01345                 }
01346         }
01347 
01348         if (ver > 3) // mesh morphing
01349         {
01350                 f.serialCont(_MeshShapeFileName);
01351                 bool useScheme;
01352                 if (f.isReading())
01353                 {               
01354                         delete _MorphScheme;
01355                 }
01356                 else
01357                 {
01358                         useScheme = _MorphScheme != NULL;
01359                 }
01360                 f.serial(useScheme);
01361                 if (useScheme)
01362                 {                               
01363                         f.serialPolyPtr(_MorphScheme);
01364                 }
01365                 else
01366                 {
01367                         f.serial(_MorphValue);
01368                 }               
01369         }
01370 }
01371 
01372 //====================================================================================
01373 CPSConstraintMesh::~CPSConstraintMesh() 
01374 {
01375         clean();
01376         delete _MorphScheme;
01377 }
01378 
01379 
01380 
01381 //====================================================================================
01382 void CPSConstraintMesh::releaseShapes()
01383 {
01384         for (TShapeVect::iterator it = _Shapes.begin(); it != _Shapes.end(); ++it)
01385         {
01386                 if (*it)
01387                 {
01388                         _ModelBank->release(*it);
01389                 }
01390         }
01391         _Shapes.clear();
01392 }
01393 
01394 //====================================================================================
01395 void CPSConstraintMesh::clean(void)
01396 {       
01397         if (_ModelBank)
01398         {       
01399                 releaseShapes();                
01400         }
01401 }
01402 
01403 
01404 //====================================================================================
01405 CVertexBuffer &CPSConstraintMesh::makePrerotatedVb(const CVertexBuffer &inVb, TAnimationTime ellapsedTime)
01406 {
01407         // get a VB that has positions and eventually normals
01408         CVertexBuffer &prerotatedVb = inVb.getVertexFormat() & CVertexBuffer::NormalFlag ? _PreRotatedMeshVBWithNormal : _PreRotatedMeshVB;
01409 
01410         // size of vertices for source VB
01411         const uint vSize = inVb.getVertexSize();
01412 
01413         // size for vertices in prerotated model
01414         const uint vpSize = prerotatedVb.getVertexSize();
01415         
01416 
01417         // offset of normals in vertices of the prerotated model, and source model              
01418         uint normalOff=0;
01419         uint pNormalOff=0;
01420         if (prerotatedVb.getVertexFormat() & CVertexBuffer::NormalFlag) 
01421         {
01422                 normalOff  =  inVb.getNormalOff();
01423                 pNormalOff =  prerotatedVb.getNormalOff();                      
01424         }
01425 
01426         const uint nbVerticesInSource   = inVb.getNumVertices();
01427                 
01428 
01429         // rotate basis
01430         // and compute the set of prerotated meshs that will then duplicated (with scale and translation) to create the Vb of what must be drawn
01431         uint8 *outVertex = (uint8 *) prerotatedVb.getVertexCoordPointer();
01432         for (std::vector< CPlaneBasisPair >::iterator it = _PrecompBasis.begin(); it != _PrecompBasis.end(); ++it)
01433         {
01434                 // not optimized at all, but this will apply to very few elements anyway...
01435                 CMatrix mat;
01436                 mat.rotate(CQuat(it->Axis, ellapsedTime * it->AngularVelocity));
01437                 CVector n = mat * it->Basis.getNormal();
01438                 it->Basis = CPlaneBasis(n);
01439         
01440                 mat.identity();
01441                 mat.setRot(it->Basis.X, it->Basis.Y, it->Basis.X ^ it->Basis.Y);
01442 
01443                 uint8 *inVertex = (uint8 *) inVb.getVertexCoordPointer();
01444 
01445                 uint k = nbVerticesInSource;
01446 
01447                 // check wether we need to rotate normals as well...
01448                 if (inVb.getVertexFormat() & CVertexBuffer::NormalFlag)
01449                 {
01450                 
01451                         do
01452                         {
01453                                 CHECK_VERTEX_BUFFER(inVb, inVertex);
01454                                 CHECK_VERTEX_BUFFER(inVb, inVertex + normalOff);
01455                                 CHECK_VERTEX_BUFFER(prerotatedVb, outVertex);
01456                                 CHECK_VERTEX_BUFFER(prerotatedVb, outVertex + pNormalOff);
01457 
01458                                 * (CVector *) outVertex =  mat.mulVector(* (CVector *) inVertex);
01459                                 * (CVector *) (outVertex + normalOff) =  mat.mulVector(* (CVector *) (inVertex + pNormalOff) );
01460                                 outVertex += vpSize;
01461                                 inVertex  += vSize;
01462                                 
01463                         }
01464                         while (--k);            
01465                 }
01466                 else
01467                 {
01468                         // no normal included
01469                         do
01470                         {       
01471                                 
01472                                 CHECK_VERTEX_BUFFER(prerotatedVb, outVertex);   
01473                                 CHECK_VERTEX_BUFFER(inVb, inVertex);                                    
01474 
01475                                 * (CVector *) outVertex =  mat.mulVector(* (CVector *) inVertex);
01476                                 outVertex += vpSize;
01477                                 inVertex += vSize;
01478                         }
01479                         while (--k);    
01480 
01481                 }
01482         }
01483         return prerotatedVb;
01484 }
01485 
01486 
01487 //====================================================================================
01488 void CPSConstraintMesh::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEt)
01489 {
01490                 if (
01491                         (pass == PSBlendRender && hasTransparentFaces())
01492                         || (pass == PSSolidRender && hasOpaqueFaces())
01493                         )
01494                 {
01495                         draw(pass == PSSolidRender, ellapsedTime);
01496                 }
01497                 else 
01498                 if (pass == PSToolRender) // edition mode only
01499                 {                       
01500                         showTool();
01501                 }
01502 }
01503 
01504 //====================================================================================
01505 void CPSConstraintMesh::draw(bool opaque, TAnimationTime ellapsedTime)
01506 {
01507         PARTICLES_CHECK_MEM;
01508         nlassert(_Owner);       
01509         
01510         update(); // update mesh datas if needed
01511         uint32 step;
01512         uint   numToProcess;
01513         computeSrcStep(step, numToProcess);     
01514         if (!numToProcess) return;
01515         _Owner->incrementNbDrawnParticles(numToProcess); // for benchmark purpose       
01516 
01517         
01518         if (_PrecompBasis.size() == 0) 
01519         {
01520                 if (step == (1 << 16))
01521                 {
01522                         CPSConstraintMeshHelper::drawMeshs(_Owner->getPos().begin(),                                       
01523                                                                                           *this,
01524                                                                       numToProcess,
01525                                                                                           step,
01526                                                                                           opaque
01527                                                                                          );
01528                 }
01529                 else
01530                 {       
01531                         CPSConstraintMeshHelper::drawMeshs(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
01532                                                                                           *this,
01533                                                                       numToProcess,
01534                                                                                           step,
01535                                                                                           opaque
01536                                                                                          );             
01537                 }
01538         }
01539         else
01540         {
01541                 if (step == (1 << 16))
01542                 {
01543                         CPSConstraintMeshHelper::drawPrerotatedMeshs(_Owner->getPos().begin(),
01544                                                                                                              _IndexInPrecompBasis.begin(),
01545                                                                                                                  *this,
01546                                                                                                                  numToProcess,
01547                                                                                                                  step,
01548                                                                                                                  opaque,
01549                                                                                                                  ellapsedTime
01550                                                                                                             );
01551                 }
01552                 else
01553                 {       
01554                         typedef CAdvance1616Iterator<std::vector<uint32>::const_iterator, uint32> TIndexIterator;
01555                         CPSConstraintMeshHelper::drawPrerotatedMeshs(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
01556                                                                                                                  TIndexIterator(_IndexInPrecompBasis.begin(), 0, step),
01557                                                                                                                  *this,
01558                                                                                                                  numToProcess,
01559                                                                                                                  step,
01560                                                                                                                  opaque,
01561                                                                                                                  ellapsedTime
01562                                                                                                             );          
01563                 }
01564         }
01565         
01566                 
01567 }
01568 
01569 //====================================================================================
01570 // Private func used to force modulation on a material and to store the preious state
01571 static inline void ForceMaterialModulation(CMaterial &destMat, CMaterial &srcMat, uint8 modulatedStages)
01572 {
01573         for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
01574         {               
01575                 if (modulatedStages & (1 << k))
01576                 {
01577                         destMat.texEnvArg0RGB(k, CMaterial::Previous, CMaterial::SrcColor);
01578                         destMat.texEnvArg0Alpha(k, CMaterial::Previous, CMaterial::SrcAlpha);
01579                         destMat.texEnvArg1RGB(k, CMaterial::Constant, CMaterial::SrcColor);
01580                         destMat.texEnvArg1Alpha(k, CMaterial::Constant, CMaterial::SrcAlpha);
01581                         destMat.texEnvOpRGB(k, CMaterial::Modulate);
01582                         destMat.texEnvOpAlpha(k, CMaterial::Modulate);                  
01583                 }
01584                 else // restore from source material
01585                 {
01586                         destMat.setTexEnvMode(k, srcMat.getTexEnvMode(k));
01587                 }
01588         }       
01589 }
01590 
01591 
01592 //====================================================================================
01593 void    CPSConstraintMesh::setupRenderPasses(float date, TRdrPassSet &rdrPasses, bool opaque)
01594 {
01595         // render meshs : we process each rendering pass
01596         for (TRdrPassSet::iterator rdrPassIt = rdrPasses.begin() 
01597                 ; rdrPassIt != rdrPasses.end(); ++rdrPassIt)
01598         {
01599 
01600                 CMaterial &Mat = rdrPassIt->Mat;
01601                 CMaterial &SourceMat = rdrPassIt->SourceMat;
01602 
01603 
01605                 if ((opaque && Mat.getZWrite()) || (!opaque && ! Mat.getZWrite()))
01606                 {               
01607 
01608         
01609                         // has to setup material constant color ?
01610                         // global color not supported for mesh
01611                 /*      CParticleSystem &ps = *(_Owner->getOwner());
01612                         if (!_ColorScheme) 
01613                         {                                                               
01614                                 NLMISC::CRGBA col;
01615                                 col.modulateFromColor(SourceMat.getColor(), _Color);
01616                                 if (ps.getColorAttenuationScheme() == NULL)
01617                                 {
01618                                         col.modulateFromColor(col, ps.getGlobalColor());
01619                                 }
01620                                 Mat.setColor(col);                              
01621                         }
01622                         else
01623                         {                               
01624                                 Mat.setColor(ps.getGlobalColor());
01625                         }*/
01626 
01628                         ForceMaterialModulation(Mat, SourceMat, _ModulatedStages);
01629 
01631                         bool forceVertexcolorLighting = _VertexColorLightingForced != 0 ? true : SourceMat.getLightedVertexColor();
01632                         if (forceVertexcolorLighting != Mat.getLightedVertexColor()) // avoid to touch mat if not needed
01633                         {
01634                                 Mat.setLightedVertexColor(forceVertexcolorLighting);
01635                         }
01636 
01638                         if (_GlobalAnimationEnabled != 0)
01639                         {
01640                                 for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
01641                                 {
01642                                         if (Mat.getTexture(k) != NULL)
01643                                         {
01644                                                 Mat.enableUserTexMat(k, true);
01645                                                 CMatrix mat;
01646                                                 _GlobalTexAnims->Anims[k].buildMatrix(date, mat);
01647                                                 Mat.setUserTexMat(k ,mat);
01648                                         }
01649                                 }
01650                         }               
01651                 }                       
01652         }
01653 
01654 }
01655 
01656 //====================================================================================
01657 void    CPSConstraintMesh::doRenderPasses(IDriver *driver, uint numObj, TRdrPassSet &rdrPasses, bool opaque)
01658 {               
01659         // render meshs : we process each rendering pass
01660         for (TRdrPassSet::iterator rdrPassIt = rdrPasses.begin() 
01661                 ; rdrPassIt != rdrPasses.end(); ++rdrPassIt)
01662         {       
01663                 CMaterial &Mat = rdrPassIt->Mat;
01664                 if ((opaque && Mat.getZWrite()) || (!opaque && ! Mat.getZWrite()))
01665                 {
01667                         rdrPassIt->Pb.setNumTri(rdrPassIt->Pb.capacityTri()   * numObj / ConstraintMeshBufSize);
01668                         rdrPassIt->Pb.setNumQuad(rdrPassIt->Pb.capacityQuad() * numObj / ConstraintMeshBufSize);
01669                         rdrPassIt->Pb.setNumLine(rdrPassIt->Pb.capacityLine() * numObj / ConstraintMeshBufSize);
01670 
01672                         driver->render(rdrPassIt->Pb, rdrPassIt->Mat);
01673                 }
01674         }
01675 
01676 }
01677 
01678 
01679 //====================================================================================
01680 void    CPSConstraintMesh::computeColors(CVertexBuffer &outVB, const CVertexBuffer &inVB, uint startIndex, uint toProcess, uint32 srcStep)
01681 {       
01682         nlassert(_ColorScheme);
01683         // there are 2 case : 1 - the source mesh has colors, which are modulated with the current color
01684         //                                        2 - the source mesh has no colors : colors are directly copied into the dest vb
01685 
01686         if (inVB.getVertexFormat() & CVertexBuffer::PrimaryColorFlag) // case 1
01687         {
01688                 // TODO: optimisation : avoid to duplicate colors...
01689                 _ColorScheme->makeN(_Owner, startIndex, outVB.getColorPointer(), outVB.getVertexSize(), toProcess, inVB.getNumVertices(), srcStep);
01690                 // modulate from the source mesh
01691                 uint8 *vDest  = (uint8 *) outVB.getColorPointer();
01692                 uint8 *vSrc   = (uint8 *) inVB.getColorPointer();
01693                 const uint vSize = outVB.getVertexSize();
01694                 const uint numVerts = inVB.getNumVertices();
01695                 uint  meshSize = vSize * numVerts;              
01696                 for (uint k = 0; k < toProcess; ++k)
01697                 {
01698                         NLMISC::CRGBA::modulateColors((CRGBA *) vDest, (CRGBA *) vSrc, (CRGBA *) vDest, numVerts, vSize, vSize);
01699                         vDest += meshSize;
01700                 }
01701         }
01702         else // case 2
01703         {
01704                 _ColorScheme->makeN(_Owner, startIndex, outVB.getColorPointer(), outVB.getVertexSize(), toProcess, inVB.getNumVertices(), srcStep);
01705         }
01706 }
01707 
01708 
01709 //====================================================================================
01710 void CPSConstraintMesh::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
01711 {
01712         newSizeElement(emitterLocated, emitterIndex);
01713         newPlaneBasisElement(emitterLocated, emitterIndex);
01714         // TODO : avoid code cuplication with CPSFace ...
01715         const uint32 nbConf = _PrecompBasis.size();
01716         if (nbConf) // do we use precomputed basis ?
01717         {
01718                 _IndexInPrecompBasis[_Owner->getNewElementIndex()] = rand() % nbConf;
01719         }
01720         newColorElement(emitterLocated, emitterIndex);
01721         if (_GlobalAnimationEnabled && _ReinitGlobalAnimTimeOnNewElement)
01722         {               
01723                 _GlobalAnimDate = _Owner->getOwner()->getSystemDate();
01724         }
01725         if (_MorphScheme && _MorphScheme->hasMemory()) _MorphScheme->newElement(emitterLocated, emitterIndex);
01726 }
01727         
01728 //====================================================================================  
01729 void CPSConstraintMesh::deleteElement(uint32 index)
01730 {
01731         deleteSizeElement(index);
01732         deletePlaneBasisElement(index);
01733         // TODO : avoid code cuplication with CPSFace ...
01734         if (_PrecompBasis.size()) // do we use precomputed basis ?
01735         {
01736                 // replace ourself by the last element...
01737                 _IndexInPrecompBasis[index] = _IndexInPrecompBasis[_Owner->getSize() - 1];
01738         }
01739         deleteColorElement(index);
01740         if (_MorphScheme && _MorphScheme->hasMemory()) _MorphScheme->deleteElement(index);
01741 }
01742         
01743 //====================================================================================
01744 void CPSConstraintMesh::resize(uint32 size)
01745 {
01746         nlassert(size < (1 << 16));
01747         resizeSize(size);
01748         resizePlaneBasis(size);
01749         // TODO : avoid code cuplication with CPSFace ...
01750         if (_PrecompBasis.size()) // do we use precomputed basis ?
01751         {
01752                 _IndexInPrecompBasis.resize(size);
01753         }
01754         resizeColor(size);
01755         if (_MorphScheme && _MorphScheme->hasMemory()) _MorphScheme->resize(size, _Owner->getSize());
01756 }       
01757 
01758 //====================================================================================
01759 void CPSConstraintMesh::updateMatAndVbForColor(void)
01760 {
01761         // nothing to do for us...
01762 }
01763 
01764 //====================================================================================
01765 void    CPSConstraintMesh::forceStageModulationByColor(uint stage, bool force)
01766 {
01767         nlassert(stage < IDRV_MAT_MAXTEXTURES);
01768         if (force)
01769         {
01770                 _ModulatedStages |= 1 << stage;
01771         }
01772         else
01773         {
01774                 _ModulatedStages &= ~(1 << stage);
01775         }
01776 }
01777 
01778 //====================================================================================
01779 bool    CPSConstraintMesh::isStageModulationForced(uint stage) const
01780 {
01781         nlassert(stage < IDRV_MAT_MAXTEXTURES);
01782         return (_ModulatedStages & (1 << stage)) != 0;
01783 }
01784 
01785 //====================================================================================
01786 
01792 static void DuplicatePrimitiveBlock(const CPrimitiveBlock &srcBlock, CPrimitiveBlock &destBlock, uint nbReplicate, uint vertOffset)
01793 {
01794         PARTICLES_CHECK_MEM;
01795 
01796         // this must be update each time a new primitive is added
01797         
01798         // loop counters, and index of the current primitive in the dest pb
01799         uint k, l, index;
01800 
01801         // the current vertex offset.
01802         uint currVertOffset;
01803 
01804 
01805         // duplicate triangles
01806         uint numTri = srcBlock.getNumTri();
01807         destBlock.reserveTri(numTri * nbReplicate);
01808         
01809         index = 0;
01810         currVertOffset = 0;
01811 
01812         const uint32 *triPtr = srcBlock.getTriPointer();
01813         const uint32 *currTriPtr; // current Tri
01814         for (k = 0; k < nbReplicate; ++k)
01815         {
01816                 currTriPtr = triPtr;
01817                 for (l = 0; l < numTri; ++l)
01818                 {
01819                         destBlock.setTri(index, currTriPtr[0] + currVertOffset, currTriPtr[1] + currVertOffset, currTriPtr[2] + currVertOffset);
01820                         currTriPtr += 3;
01821                         ++ index;
01822                 }
01823                 currVertOffset += vertOffset;
01824         }
01825 
01826 
01827         // duplicate quads
01828         uint numQuad = srcBlock.getNumQuad();
01829         destBlock.reserveQuad(numQuad * nbReplicate);
01830         
01831         index = 0;
01832         currVertOffset = 0;
01833 
01834         const uint32 *QuadPtr = srcBlock.getQuadPointer();
01835         const uint32 *currQuadPtr; // current Quad
01836         for (k = 0; k < nbReplicate; ++k)
01837         {
01838                 currQuadPtr = QuadPtr;
01839                 for (l = 0; l < numQuad; ++l)
01840                 {
01841                         destBlock.setQuad(index, currQuadPtr[0] + currVertOffset, currQuadPtr[1] + currVertOffset, currQuadPtr[2] + currVertOffset, currQuadPtr[3] + currVertOffset);
01842                         currQuadPtr += 4;
01843                         ++ index;
01844                 }
01845                 currVertOffset += vertOffset;
01846         }
01847 
01848         // duplicate lines
01849         uint numLine = srcBlock.getNumLine();
01850         destBlock.reserveLine(numLine * nbReplicate);
01851         
01852         index = 0;
01853         currVertOffset = 0;
01854 
01855         const uint32 *LinePtr = srcBlock.getLinePointer();
01856         const uint32 *currLinePtr; // current Line
01857         for (k = 0; k < nbReplicate; ++k)
01858         {
01859                 currLinePtr = LinePtr;
01860                 for (l = 0; l < numLine; ++l)
01861                 {
01862                         destBlock.setLine(index, currLinePtr[0] + currVertOffset, currLinePtr[1] + currVertOffset);
01863                         currLinePtr += 4;
01864                         ++ index;
01865                 }
01866                 currVertOffset += vertOffset;
01867         }       
01868 
01869 
01870         // TODO quad / strips duplication : (unimplemented in primitive blocks for now)
01871 
01872         PARTICLES_CHECK_MEM;
01873 }
01874 
01875 //====================================================================================
01876 void CPSConstraintMesh::initPrerotVB()
01877 {
01878         // position, no normals
01879         _PreRotatedMeshVB.setVertexFormat(CVertexBuffer::PositionFlag);
01880         _PreRotatedMeshVB.setNumVertices(ConstraintMeshMaxNumPrerotatedModels * ConstraintMeshMaxNumVerts);
01881 
01882         // position & normals
01883         _PreRotatedMeshVBWithNormal.setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::NormalFlag);
01884         _PreRotatedMeshVBWithNormal.setNumVertices(ConstraintMeshMaxNumPrerotatedModels * ConstraintMeshMaxNumVerts);
01885 }
01886 
01887 //====================================================================================
01888 CPSConstraintMesh::CMeshDisplay &CPSConstraintMesh::CMeshDisplayShare::getMeshDisplay(IShape *shape, uint32 format)
01889 {
01890         CKey key;
01891         key.Shape = shape;
01892         key.Format = format;
01893         if (MDMap.count(key)) // already exists ?
01894         {
01895                 nlassert(MDMap[key]);
01896                 return *MDMap[key];
01897         }
01898         else
01899         {
01900                 if (MDQueue.size() == _MaxNumMD) // is there room left?
01901                 {
01902                         // no, destroy the least recent entry
01903                         nlassert(MDMap.count(MDQueue.front())); // make sure it is also in the map
01904                         MDMap.erase(MDQueue.front());
01905                         MDQueue.pop();
01906                 }
01907                 std::auto_ptr<CMeshDisplay> MD(new CMeshDisplay);
01908         
01909                 // setup rdr passes & primitive blocks
01910                 buildRdrPassSet(MD->RdrPasses, shape);
01911                 
01912                 // setup vb
01913                 buildVB(format, MD->VB, shape);
01914                 
01915                 MDQueue.push(key);
01916                 MDMap[key] = MD.get();
01917                 return *(MD.release());
01918         }
01919 }
01920 
01921 
01922 //====================================================================================
01923 CPSConstraintMesh::CMeshDisplayShare::~CMeshDisplayShare()
01924 {
01925         for (TMDMap::iterator it = MDMap.begin(); it != MDMap.end(); ++it)
01926         {
01927                 delete it->second;
01928         }
01929 }
01930 
01931 //====================================================================================
01932 void CPSConstraintMesh::CMeshDisplayShare::buildRdrPassSet(TRdrPassSet &dest, const IShape *shape)
01933 {       
01934         const CMesh &m = *NLMISC::safe_cast<const CMesh *>(shape);
01935         // we don't support skinning for mesh particles, so there must be only one matrix block 
01936         nlassert(m.getNbMatrixBlock() == 1);  // SKINNING UNSUPPORTED
01937         
01938         dest.resize(m.getNbRdrPass(0));
01939         const CVertexBuffer &srcVb = m.getVertexBuffer();
01940         
01941         for (uint k = 0; k < m.getNbRdrPass(0); ++k)
01942         {
01943                 dest[k].Mat = m.getMaterial(m.getRdrPassMaterial(0, k));
01944                 dest[k].SourceMat = dest[k].Mat;
01945                 DuplicatePrimitiveBlock(m.getRdrPassPrimitiveBlock(0, k), dest[k].Pb, ConstraintMeshBufSize, srcVb.getNumVertices() );          
01946         }       
01947 }
01948 
01949 //====================================================================================
01950 void CPSConstraintMesh::CMeshDisplayShare::buildVB(uint32 destFormat, CVertexBuffer &dest, const IShape *shape)
01951 {
01953         nlassert(shape);
01954         const CMesh &m = *NLMISC::safe_cast<const CMesh *>(shape);
01955         const CVertexBuffer &meshVb = m.getVertexBuffer();
01956         nlassert(destFormat == meshVb.getVertexFormat() || destFormat == (meshVb.getVertexFormat() | (uint32) CVertexBuffer::PrimaryColorFlag) );
01957         dest.setVertexFormat(destFormat);
01958         dest.setNumVertices(ConstraintMeshBufSize * meshVb.getNumVertices());
01959 
01960         uint8 *outPtr = (uint8 *) dest.getVertexCoordPointer();
01961         uint8 *inPtr = (uint8 *)  meshVb.getVertexCoordPointer();
01962         uint  meshSize  = dest.getVertexSize() * meshVb.getNumVertices();
01963 
01964         if (destFormat == meshVb.getVertexFormat()) // no color added
01965         {               
01966                 for (uint k = 0; k < ConstraintMeshBufSize; ++k)
01967                 {
01968                         ::memcpy((void *) (outPtr + k * meshSize), (void *) inPtr, meshSize);                   
01969                 }
01970         }
01971         else // color added, but not available in src 
01972         {
01973                 sint colorOff = dest.getColorOff();
01974                 uint inVSize    = meshVb.getVertexSize();
01975                 uint outVSize   = dest.getVertexSize();         
01976                 for (uint k = 0; k < ConstraintMeshBufSize; ++k)
01977                 {
01978                         for (uint v = 0; v < meshVb.getNumVertices(); ++v)
01979                         {
01980                                 // copy until color
01981                                 ::memcpy((void *) (outPtr + k * meshSize + v * outVSize), (void *) (inPtr + v * inVSize), colorOff);
01982                                 // copy datas after color
01983                                 ::memcpy((void *) (outPtr + k * meshSize + v * outVSize + colorOff + sizeof(uint8[4])), (void *) (inPtr + v * inVSize + colorOff), inVSize - colorOff);
01984                         }
01985                 }
01986         }
01987 }
01988 
01989 //=====================================================================================
01990 CPSConstraintMesh::CMeshDisplayShare::CKey::~CKey()
01991 {
01992 }
01993 
01994 //===================================================================================== 
01995 CPSConstraintMesh::CGlobalTexAnim::CGlobalTexAnim() : TransSpeed(NLMISC::CVector2f::Null),
01996                                                          TransAccel(NLMISC::CVector2f::Null),
01997                                                          ScaleStart(1 ,1),
01998                                                          ScaleSpeed(NLMISC::CVector2f::Null),
01999                                                          ScaleAccel(NLMISC::CVector2f::Null),
02000                                                          WRotSpeed(0),
02001                                                          WRotAccel(0)
02002 {
02003 }
02004 
02005 //=====================================================================================
02006 void    CPSConstraintMesh::CGlobalTexAnim::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02007 {
02008         f.serialVersion(0);
02009         f.serial(TransSpeed, TransAccel, ScaleStart, ScaleSpeed, ScaleAccel);
02010         f.serial(WRotSpeed, WRotAccel);
02011 }
02012 
02013 //=====================================================================================
02014 void CPSConstraintMesh::CGlobalTexAnim::buildMatrix(float &date, NLMISC::CMatrix &dest)
02015 {
02016         float fDate = (float) date;
02017         float halfDateSquared   = 0.5f * fDate * fDate;
02018         NLMISC::CVector2f pos   = fDate * TransSpeed + halfDateSquared * fDate * TransAccel;
02019         NLMISC::CVector2f scale = ScaleStart + fDate * ScaleSpeed + halfDateSquared * fDate * ScaleAccel;
02020         float rot = fDate * WRotSpeed + halfDateSquared * WRotAccel;
02021         
02022                         
02023         float fCos, fSin;
02024         if (rot != 0.f)
02025         {
02026                 fCos = ::cosf(- rot);
02027                 fSin = ::sinf(- rot);
02028         }
02029         else
02030         {
02031                 fCos = 1.f;
02032                 fSin = 0.f;
02033         }
02034 
02035         NLMISC::CVector I(fCos, fSin, 0);
02036         NLMISC::CVector J(-fSin, fCos, 0);                              
02037         dest.setRot(scale.x * I, scale.y * J, NLMISC::CVector::K);      
02038         NLMISC::CVector center(-0.5f, -0.5f, 0.f);
02039         NLMISC::CVector t(pos.x, pos.y, 0);
02040         dest.setPos(t + dest.mulVector(center) - center);       
02041 }
02042 
02043 //=====================================================================================
02044 void    CPSConstraintMesh::setGlobalTexAnim(uint stage, const CGlobalTexAnim &properties)
02045 {
02046         nlassert(_GlobalAnimationEnabled != 0);
02047         nlassert(stage < IDRV_MAT_MAXTEXTURES);
02048         nlassert(_GlobalTexAnims.get());
02049         _GlobalTexAnims->Anims[stage] = properties;
02050 }
02051 
02052 //=====================================================================================
02053 const CPSConstraintMesh::CGlobalTexAnim &CPSConstraintMesh::getGlobalTexAnim(uint stage) const
02054 {
02055         nlassert(_GlobalAnimationEnabled != 0);
02056         nlassert(stage < IDRV_MAT_MAXTEXTURES);
02057         nlassert(_GlobalTexAnims.get());
02058         return _GlobalTexAnims->Anims[stage];
02059 }
02060 
02061 
02062 //=====================================================================================
02063 CPSConstraintMesh::TTexAnimType CPSConstraintMesh::getTexAnimType() const
02064 {
02065         return (TTexAnimType) (_GlobalAnimationEnabled != 0 ? GlobalAnim : NoAnim);     
02066 }
02067 
02068 //=====================================================================================
02069 void  CPSConstraintMesh::setTexAnimType(TTexAnimType type)
02070 {
02071         nlassert(type < Last);
02072         if (type == getTexAnimType()) return; // does the type of animation change ?
02073         switch (type)
02074         {
02075                 case NoAnim:
02076                         _GlobalTexAnims.reset();
02077                         restoreMaterials();
02078                         _GlobalAnimationEnabled = 0;
02079                 break;
02080                 case GlobalAnim:
02081                 {
02082                         PGlobalTexAnims newPtr(new CGlobalTexAnims);
02083                         std::swap(_GlobalTexAnims, newPtr);                     
02084                         _GlobalAnimationEnabled = 1;
02085                 }
02086                 break;
02087                 default: break;
02088         }
02089 }
02090 
02091 //=====================================================================================
02092 void    CPSConstraintMesh::CGlobalTexAnims::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02093 {
02094         f.serialVersion(0);
02095         for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
02096         {
02097                 f.serial(Anims[k]);
02098         }
02099 }
02100 
02101 //=====================================================================================
02102 void CPSConstraintMesh::restoreMaterials()
02103 {
02104         update();
02105         CMesh                             &mesh = * NLMISC::safe_cast<CMesh *>((IShape *) _Shapes[0]);
02106         const CVertexBuffer   &modelVb = mesh.getVertexBuffer();
02107         CMeshDisplay  &md= _MeshDisplayShare.getMeshDisplay(_Shapes[0], modelVb.getVertexFormat() 
02108                                                                                                                         | (_ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
02109 
02110         TRdrPassSet rdrPasses = md.RdrPasses;
02111                 // render meshs : we process each rendering pass
02112         for (TRdrPassSet::iterator rdrPassIt = rdrPasses.begin() 
02113                 ; rdrPassIt != rdrPasses.end(); ++rdrPassIt)
02114         {       
02115                 rdrPassIt->Mat = rdrPassIt->SourceMat;          
02116         }
02117 }
02118 
02119 } // NL3D