ps_mesh.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2000, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #include "std3d.h"
00025 
00026 #include "nel/3d/ps_mesh.h"
00027 #include "nel/3d/ps_macro.h"
00028 #include "nel/3d/shape.h"
00029 #include "nel/3d/mesh.h"
00030 #include "nel/3d/transform_shape.h"
00031 #include "nel/3d/shape_bank.h"
00032 #include "nel/3d/texture_mem.h"
00033 #include "nel/3d/scene.h"
00034 #include "nel/3d/ps_located.h"
00035 #include "nel/3d/particle_system.h"
00036 #include "nel/3d/particle_system_shape.h"
00037 #include "nel/3d/particle_system_model.h"
00038 #include "nel/3d/ps_iterator.h"
00039 #include "nel/misc/stream.h"
00040 #include "nel/misc/path.h"
00041 
00042 #include <memory>
00043 #include <functional>
00044 
00045 
00046 
00047 
00048 namespace NL3D
00049 {
00050 
00052 // static members //
00054 
00055 
00056 
00057 
00058 CPSConstraintMesh::CMeshDisplayShare        CPSConstraintMesh::_MeshDisplayShare(16);
00059 CVertexBuffer                               CPSConstraintMesh::_PreRotatedMeshVB;             // mesh has no normals
00060 CVertexBuffer                               CPSConstraintMesh::_PreRotatedMeshVBWithNormal;  // mesh has normals
00061 CPSConstraintMesh::TMeshName2RamVB          CPSConstraintMesh::_MeshRamVBs;
00062 
00063 
00064 
00065 // this produce a random unit vector
00066 static CVector MakeRandomUnitVect(void)
00067 {
00068     NL_PS_FUNC(MakeRandomUnitVect)
00069     CVector v((float) ((rand() % 20000) - 10000)
00070               ,(float) ((rand() % 20000) - 10000)
00071               ,(float) ((rand() % 20000) - 10000)
00072               );
00073     v.normalize();
00074     return v;
00075 }
00076 
00077 
00079 // CPSMesh implementation //
00081 
00082 
00083 //====================================================================================
00084 
00085 
00086 
00087 
00088 const std::string DummyShapeName("dummy mesh shape");
00089 
00093 static CMesh *CreateDummyMesh(void)
00094 {
00095     NL_PS_FUNC(CreateDummyMesh)
00096     CMesh::CMeshBuild mb;
00097     CMeshBase::CMeshBaseBuild mbb;
00098 
00099     mb.VertexFlags = CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag;
00100     mb.Vertices.push_back(CVector(-.5f, -.5f, -.5f));
00101     mb.Vertices.push_back(CVector(.5f, -.5f, -.5f));
00102     mb.Vertices.push_back(CVector(.5f, -.5f, .5f));
00103     mb.Vertices.push_back(CVector(-.5f, -.5f, .5f));
00104 
00105     mb.Vertices.push_back(CVector(-.5f, .5f, -.5f));
00106     mb.Vertices.push_back(CVector(.5f, .5f, -.5f));
00107     mb.Vertices.push_back(CVector(.5f, .5f, .5f));
00108     mb.Vertices.push_back(CVector(-.5f, .5f, .5f));
00109 
00110     // index for each face
00111     uint32 tab[] = { 4, 1, 0,
00112                      4, 5, 1,
00113                      5, 2, 1,
00114                      5, 6, 2,
00115                      6, 3, 2,
00116                      6, 7, 3,
00117                      7, 0, 3,
00118                      7, 4, 0,
00119                      7, 5, 4,
00120                      7, 6, 5,
00121                      2, 0, 1,
00122                      2, 3, 0
00123                     };
00124 
00125     for (uint k = 0; k < 6; ++k)
00126     {
00127         CMesh::CFace f;
00128         f.Corner[0].Vertex = tab[6 * k];
00129         f.Corner[0].Uvws[0] = NLMISC::CUVW(0, 0, 0);
00130 
00131         f.Corner[1].Vertex = tab[6 * k + 1];
00132         f.Corner[1].Uvws[0] = NLMISC::CUVW(1, 1, 0);
00133 
00134         f.Corner[2].Vertex = tab[6 * k + 2];
00135         f.Corner[2].Uvws[0] = NLMISC::CUVW(0, 1, 0);
00136 
00137         f.MaterialId = 0;
00138 
00139         mb.Faces.push_back(f);
00140 
00141         f.Corner[0].Vertex = tab[6 * k + 3];
00142         f.Corner[0].Uvws[0] = NLMISC::CUVW(0, 0, 0);
00143 
00144         f.Corner[1].Vertex = tab[6 * k + 4];
00145         f.Corner[1].Uvws[0] = NLMISC::CUVW(1, 0, 0);
00146 
00147         f.Corner[2].Vertex = tab[6 * k + 5];
00148         f.Corner[2].Uvws[0] = NLMISC::CUVW(1, 1, 0);
00149 
00150         f.MaterialId = 0;
00151         mb.Faces.push_back(f);
00152     }
00153 
00154     CMaterial mat;
00155     CTextureMem *tex = new CTextureMem;
00156     tex->makeDummy();
00157     mat.setTexture(0, tex);
00158     mat.setLighting(false);
00159     mat.setColor(CRGBA::White);
00160     mbb.Materials.push_back(mat);
00161     CMesh *m = new CMesh;
00162     m->build(mbb, mb);
00163     return m;
00164 }
00165 
00166 
00167 //====================================================================================
00168 void CPSMesh::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00169 {
00170     NL_PS_FUNC(CPSMesh_IStream )
00171     (void)f.serialVersion(3);
00172     CPSParticle::serial(f);
00173     CPSSizedParticle::serialSizeScheme(f);
00174     CPSRotated3DPlaneParticle::serialPlaneBasisScheme(f);
00175     CPSRotated2DParticle::serialAngle2DScheme(f);
00176     f.serial(_Shape);
00177     if (f.isReading())
00178     {
00179 
00180         uint maxSize = 0;
00181         if (_Owner)
00182         {
00183             maxSize = _Owner->getMaxSize();
00184             _Instances.resize(maxSize);
00185         }
00186         for(uint k = 0; k < maxSize; ++k)
00187         {
00188             _Instances.insert(NULL);
00189         }
00190     }
00191 }
00192 
00193 //====================================================================================
00194 void CPSMesh::setShape(const std::string &shape)
00195 {
00196     NL_PS_FUNC(CPSMesh_setShape)
00197     if (shape == _Shape) return;
00198     _Shape = shape;
00199     removeAllInstancesFromScene();
00200 }
00201 
00202 //====================================================================================
00203 uint32 CPSMesh::getNumWantedTris() const
00204 {
00205     NL_PS_FUNC(CPSMesh_getNumWantedTris)
00207     return 0;
00208 }
00209 
00210 //====================================================================================
00211 bool CPSMesh::hasTransparentFaces(void)
00212 {
00213     NL_PS_FUNC(CPSMesh_hasTransparentFaces)
00215     return false;
00216 }
00217 
00218 //====================================================================================
00219 bool CPSMesh::hasOpaqueFaces(void)
00220 {
00221     NL_PS_FUNC(CPSMesh_hasOpaqueFaces)
00223     return false;
00224 }
00225 
00226 //====================================================================================
00227 bool CPSMesh::hasLightableFaces()
00228 {
00229     NL_PS_FUNC(CPSMesh_hasLightableFaces)
00231     return false;
00232 }
00233 
00234 //====================================================================================
00235 void CPSMesh::releaseAllRef()
00236 {
00237     NL_PS_FUNC(CPSMesh_releaseAllRef)
00238     CPSParticle::releaseAllRef();
00239     nlassert(_Owner && _Owner->getScene());
00240     removeAllInstancesFromScene();
00241 }
00242 
00243 //====================================================================================
00244 void CPSMesh::removeAllInstancesFromScene()
00245 {
00246     NL_PS_FUNC(CPSMesh_removeAllInstancesFromScene)
00247     for(uint k = 0; k < _Instances.getSize(); ++k)
00248     {
00249         if (_Instances[k])
00250         {
00251             if (_Owner) _Owner->getScene()->deleteInstance(_Instances[k]);
00252             _Instances[k] = NULL;
00253         }
00254     }
00255 }
00256 
00257 //====================================================================================
00258 CTransformShape *CPSMesh::createInstance()
00259 {
00260     NL_PS_FUNC(CPSMesh_createInstance)
00261     CScene *scene = _Owner->getScene();
00262     nlassert(scene); // the setScene method of the particle system should have been called
00263     CTransformShape *instance = scene->createInstance(_Shape);
00264     if (!instance)
00265     {
00266         // mesh not found ...
00267         IShape *is = CreateDummyMesh();
00268         scene->getShapeBank()->add(DummyShapeName, is);
00269         instance = scene->createInstance(DummyShapeName);
00270         nlassert(instance);
00271     }
00272     instance->setTransformMode(CTransform::DirectMatrix);
00273     instance->hide(); // the object hasn't the right matrix yet so we hide it. It'll be shown once it is computed
00274     return instance;
00275 }
00276 
00277 //====================================================================================
00278 void CPSMesh::newElement(const CPSEmitterInfo &info)
00279 {
00280     NL_PS_FUNC(CPSMesh_newElement)
00281     newPlaneBasisElement(info);
00282     newAngle2DElement(info);
00283     newSizeElement(info);
00284     nlassert(_Owner);
00285     nlassert(_Owner->getOwner());
00286     CTransformShape *instance = createInstance();
00287     nlassert(instance);
00288     _Instances.insert(instance);
00289 }
00290 
00291 //====================================================================================
00292 void CPSMesh::deleteElement(uint32 index)
00293 {
00294     NL_PS_FUNC(CPSMesh_deleteElement)
00295     deleteSizeElement(index);
00296     deleteAngle2DElement(index);
00297     deletePlaneBasisElement(index);
00298 
00299     // check whether CTransformShape have been instanciated
00300     nlassert(_Owner);
00301     nlassert(_Owner->getOwner());
00302     CScene *scene = _Owner->getScene();
00303     nlassert(scene); // the setScene method of the particle system should have been called
00304     if (_Instances[index])
00305     {
00306         scene->deleteInstance(_Instances[index]);
00307     }
00308     _Instances.remove(index);
00309 }
00310 
00311 //====================================================================================
00312 void CPSMesh::step(TPSProcessPass pass)
00313 {
00314     NL_PS_FUNC(CPSMesh_step)
00315     if (pass == PSMotion)
00316     {
00317         updatePos();
00318     }
00319     else
00320     if (pass == PSToolRender) // edition mode only
00321     {
00322         showTool();
00323     }
00324 }
00325 
00326 //====================================================================================
00327 void CPSMesh::updatePos()
00328 {
00329     NL_PS_FUNC(CPSMesh_updatePos)
00330     const uint MeshBufSize = 512;
00331     PARTICLES_CHECK_MEM;
00332     nlassert(_Owner);
00333     const uint32 size = _Owner->getSize();
00334     if (!size) return;
00335 
00336 
00337     _Owner->incrementNbDrawnParticles(size); // for benchmark purpose
00338 
00339 
00340     if (!_Instances[0])
00341     {
00342         for (uint k = 0; k < size; ++k)
00343         {
00344             nlassert(!_Instances[k]);
00345             _Instances[k] = createInstance();
00346         }
00347     }
00348 
00349     float sizes[MeshBufSize];
00350     float angles[MeshBufSize];
00351     static CPlaneBasis planeBasis[MeshBufSize];
00352 
00353     uint32 leftToDo = size, toProcess;
00354 
00355 
00356     float *ptCurrSize;
00357     const uint  ptCurrSizeIncrement = _SizeScheme ? 1 : 0;
00358 
00359     float *ptCurrAngle;
00360     const uint  ptCurrAngleIncrement = _Angle2DScheme ? 1 : 0;
00361 
00362     CPlaneBasis *ptBasis;
00363     const uint  ptCurrPlaneBasisIncrement = _PlaneBasisScheme ? 1 : 0;
00364 
00365     TPSAttribVector::const_iterator posIt = _Owner->getPos().begin(), endPosIt;
00366 
00367 
00368     TInstanceCont::iterator instanceIt = _Instances.begin();
00369 
00370     do
00371     {
00372         toProcess = leftToDo < MeshBufSize ? leftToDo : MeshBufSize;
00373 
00374         if (_SizeScheme)
00375         {
00376             ptCurrSize  = (float *) (_SizeScheme->make(_Owner, size - leftToDo, &sizes[0], sizeof(float), toProcess, true));
00377         }
00378         else
00379         {
00380             ptCurrSize =& _ParticleSize;
00381         }
00382 
00383         if (_Angle2DScheme)
00384         {
00385             ptCurrAngle  = (float *) (_Angle2DScheme->make(_Owner, size - leftToDo, &angles[0], sizeof(float), toProcess, true));
00386         }
00387         else
00388         {
00389             ptCurrAngle =& _Angle2D;
00390         }
00391 
00392 
00393         if (_PlaneBasisScheme)
00394         {
00395             ptBasis  = (CPlaneBasis *) (_PlaneBasisScheme->make(_Owner, size - leftToDo, &planeBasis[0], sizeof(CPlaneBasis), toProcess, true));
00396         }
00397         else
00398         {
00399             ptBasis = &_PlaneBasis;
00400         }
00401 
00402         endPosIt = posIt + toProcess;
00403         CMatrix mat, tmat;
00404 
00405         // the matrix used to get in the right basis
00406         const CMatrix &transfo = getLocalToWorldMatrix();
00407         do
00408         {
00409 
00410             tmat.identity();
00411             mat.identity();
00412 
00413             tmat.translate(*posIt);
00414 
00415 
00416 
00417             mat.setRot( ptBasis->X * CPSUtil::getCos((sint32) *ptCurrAngle) + ptBasis->Y * CPSUtil::getSin((sint32) *ptCurrAngle)
00418                         , ptBasis->X * CPSUtil::getCos((sint32) *ptCurrAngle + 64) + ptBasis->Y * CPSUtil::getSin((sint32) *ptCurrAngle + 64)
00419                         , ptBasis->X ^ ptBasis->Y
00420                       );
00421 
00422             mat.scale(*ptCurrSize);
00423 
00424             (*instanceIt)->setMatrix(transfo * tmat * mat);
00425             if (CParticleSystem::OwnerModel)
00426             {
00427                 // make sure the visibility is the same
00428                 if (CParticleSystem::OwnerModel->isHrcVisible())
00429                 {
00430                     (*instanceIt)->show();
00431                 }
00432                 else
00433                 {
00434                     (*instanceIt)->hide();
00435                 }
00436                 (*instanceIt)->setClusterSystem(CParticleSystem::OwnerModel->getClusterSystem());
00437             }
00438 
00439             ++instanceIt;
00440             ++posIt;
00441             ptCurrSize += ptCurrSizeIncrement;
00442             ptCurrAngle += ptCurrAngleIncrement;
00443             ptBasis += ptCurrPlaneBasisIncrement;
00444         }
00445         while (posIt != endPosIt);
00446         leftToDo -= toProcess;
00447     }
00448     while (leftToDo);
00449 
00450     PARTICLES_CHECK_MEM;
00451 }
00452 
00453 //====================================================================================
00454 void CPSMesh::resize(uint32 size)
00455 {
00456     NL_PS_FUNC(CPSMesh_resize)
00457     nlassert(size < (1 << 16));
00458     resizeSize(size);
00459     resizeAngle2D(size);
00460     resizePlaneBasis(size);
00461     if (size < _Instances.getSize())
00462     {
00463         for(uint k = size; k < _Instances.getSize(); ++k)
00464         {
00465             if (_Owner) _Owner->getScene()->deleteInstance(_Instances[k]);
00466         }
00467     }
00468     _Instances.resize(size);
00469 }
00470 
00471 
00472 //====================================================================================
00473 CPSMesh::~CPSMesh()
00474 {
00475     NL_PS_FUNC(CPSMesh_CPSMeshDtor)
00476     if (_Owner && _Owner->getOwner())
00477     {
00478         removeAllInstancesFromScene();
00479     }
00480     else
00481     {
00482         #ifdef NL_DEBUG
00483             for (TInstanceCont::iterator it = _Instances.begin(); it != _Instances.end(); ++it)
00484             {
00485                 nlassert(*it == NULL); // there's a leak..:(
00486             }
00487         #endif
00488     }
00489 }
00490 
00492 // CPSConstraintMesh implementation //
00494 
00496 static uint getMeshNumTri(const CMesh &m)
00497 {
00498     NL_PS_FUNC(getMeshNumTri)
00499     uint numFaces = 0;
00500     for (uint k = 0; k < m.getNbMatrixBlock(); ++k)
00501     {
00502         for (uint l = 0; l  < m.getNbRdrPass(k); ++l)
00503         {
00504             const CIndexBuffer pb = m.getRdrPassPrimitiveBlock(k, l);
00505             numFaces += pb.getNumIndexes()/3;
00506 
00507         }
00508     }
00509     return numFaces;
00510 }
00511 
00512 
00513 //====================================================================================
00515 static void CheckForOpaqueAndTransparentFacesInMesh(const CMesh &m, bool &hasTransparentFaces, bool &hasOpaqueFaces)
00516 {
00517     NL_PS_FUNC(CheckForOpaqueAndTransparentFacesInMesh)
00518     hasTransparentFaces = false;
00519     hasOpaqueFaces = false;
00520 
00521     for (uint k = 0; k < m.getNbRdrPass(0); ++k)
00522     {
00523         const CMaterial &currMat = m.getMaterial(m.getRdrPassMaterial(0, k));
00524         if (!currMat.getZWrite())
00525         {
00526             hasTransparentFaces = true;
00527         }
00528         else // z-buffer write or no blending -> the face is opaque
00529         {
00530             hasOpaqueFaces = true;
00531         }
00532     }
00533 }
00534 
00535 //====================================================================================
00537 static bool CheckForLightableFacesInMesh(const CMesh &m)
00538 {
00539     NL_PS_FUNC(CheckForLightableFacesInMesh)
00540     for (uint k = 0; k < m.getNbRdrPass(0); ++k)
00541     {
00542         const CMaterial &currMat = m.getMaterial(m.getRdrPassMaterial(0, k));
00543         if (currMat.isLighted()) return true;
00544     }
00545     return false;
00546 }
00547 
00548 
00554 class CPSConstraintMeshHelper
00555 {
00556 public:
00557     template <class T>
00558     static void drawMeshs(T posIt, CPSConstraintMesh &m, uint size, uint32 srcStep, bool opaque)
00559     {
00560         NL_PS_FUNC(CPSConstraintMeshHelper_drawMeshs)
00561         const CVertexBuffer   &modelVb = m.getMeshVB(0);
00562 
00563 
00564         // size for model vertices
00565         const uint inVSize    = modelVb.getVertexSize(); // vertex size
00566 
00567         // driver setup
00568         IDriver *driver = m.getDriver();
00569         m.setupDriverModelMatrix();
00570 
00571         // buffer to compute sizes
00572         float           sizes[ConstraintMeshBufSize];
00573 
00574         float *ptCurrSize;
00575         uint ptCurrSizeIncrement = m._SizeScheme ? 1 : 0;
00576 
00577         T endPosIt;
00578         uint leftToDo = size, toProcess;
00579 
00581         CPSConstraintMesh::CMeshDisplay  &md= m._MeshDisplayShare.getMeshDisplay(m._Meshes[0], modelVb, modelVb.getVertexFormat()
00582                                                                 | (m._ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
00583 
00584         m.setupRenderPasses((float) m._Owner->getOwner()->getSystemDate() - m._GlobalAnimDate, md.RdrPasses, opaque);
00585 
00586         CVertexBuffer &outVb = md.VB;
00587         const uint outVSize = outVb.getVertexSize();
00588 
00589 
00590 
00591         // we don't have precomputed mesh there ... so each mesh must be transformed, which is the worst case
00592         CPlaneBasis planeBasis[ConstraintMeshBufSize];
00593         CPlaneBasis *ptBasis;
00594         uint ptBasisIncrement = m._PlaneBasisScheme ? 1 : 0;
00595 
00596         const uint nbVerticesInSource   = modelVb.getNumVertices();
00597 
00598         sint inNormalOff=0;
00599         sint outNormalOff=0;
00600         if (modelVb.getVertexFormat() & CVertexBuffer::NormalFlag)
00601         {
00602             inNormalOff  =  modelVb.getNormalOff();
00603             outNormalOff =  outVb.getNormalOff();
00604         }
00605         if (m._ColorScheme)
00606         {
00607             CVertexBuffer::TVertexColorType vtc = driver->getVertexColorFormat();
00608             m._ColorScheme->setColorType(vtc);
00609             if (modelVb.getVertexFormat() & CVertexBuffer::PrimaryColorFlag)
00610             {
00611                 const_cast<CVertexBuffer &>(modelVb).setVertexColorFormat(vtc);
00612             }
00613         }
00614         CVertexBufferRead vbaRead;
00615         modelVb.lock (vbaRead);
00616         do
00617         {
00618             toProcess = std::min(leftToDo, ConstraintMeshBufSize);
00619             outVb.setNumVertices(toProcess * nbVerticesInSource);
00620             {
00621                 CVertexBufferReadWrite vba;
00622                 outVb.lock(vba);
00623                 uint8 *outVertex = (uint8 *) vba.getVertexCoordPointer();
00624                 if (m._SizeScheme)
00625                 {
00626                     ptCurrSize  = (float *) (m._SizeScheme->make(m._Owner, size -leftToDo, &sizes[0], sizeof(float), toProcess, true, srcStep));
00627                 }
00628                 else
00629                 {
00630                     ptCurrSize = &m._ParticleSize;
00631                 }
00632 
00633                 if (m._PlaneBasisScheme)
00634                 {
00635                     ptBasis = (CPlaneBasis *) (m._PlaneBasisScheme->make(m._Owner, size -leftToDo, &planeBasis[0], sizeof(CPlaneBasis), toProcess, true, srcStep));
00636                 }
00637                 else
00638                 {
00639                     ptBasis = &m._PlaneBasis;
00640                 }
00641 
00642 
00643                 endPosIt = posIt + toProcess;
00644                 // transfo matrix & scaled transfo matrix;
00645                 CMatrix  M, sM;
00646 
00647 
00648                 if (m._Meshes.size() == 1)
00649                 {
00651                     do
00652                     {
00653                         const uint8 *inVertex = (const uint8 *) vbaRead.getVertexCoordPointer();
00654                         uint k = nbVerticesInSource;
00655 
00656                         // do we need a normal ?
00657                         if (modelVb.getVertexFormat() & CVertexBuffer::NormalFlag)
00658                         {
00659                             M.identity();
00660                             M.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
00661                             sM = M;
00662                             sM.scale(*ptCurrSize);
00663 
00664                             // offset of normals in the prerotated mesh
00665                             do
00666                             {
00667                                 CHECK_VERTEX_BUFFER(modelVb, inVertex);
00668                                 CHECK_VERTEX_BUFFER(outVb,    outVertex);
00669                                 CHECK_VERTEX_BUFFER(modelVb, inVertex + inNormalOff);
00670                                 CHECK_VERTEX_BUFFER(outVb,    outVertex + outNormalOff);
00671 
00672                                 // translate and resize the vertex (relatively to the mesh origin)
00673                                 *(CVector *) outVertex = *posIt + sM * *(CVector *) inVertex;
00674                                 // copy the normal
00675                                 *(CVector *) (outVertex + outNormalOff) = M * *(CVector *) (inVertex + inNormalOff);
00676 
00677 
00678                                 inVertex  += inVSize;
00679                                 outVertex += outVSize;
00680                             }
00681                             while (--k);
00682                         }
00683                         else
00684                         {
00685                             // no normal to transform
00686                             sM.identity();
00687                             sM.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
00688                             sM.scale(*ptCurrSize);
00689 
00690                             do
00691                             {
00692                                 CHECK_VERTEX_BUFFER(modelVb, inVertex);
00693                                 CHECK_VERTEX_BUFFER(outVb, outVertex);
00694 
00695                                 // translate and resize the vertex (relatively to the mesh origin)
00696                                 *(CVector *) outVertex = *posIt + sM * *(CVector *) inVertex;
00697 
00698                                 inVertex  += inVSize;
00699                                 outVertex += outVSize;
00700                             }
00701                             while (--k);
00702                         }
00703 
00704 
00705                         ++posIt;
00706                         ptCurrSize += ptCurrSizeIncrement;
00707                         ptBasis += ptBasisIncrement;
00708                     }
00709                     while (posIt != endPosIt);
00710                 }
00711                 else
00712                 {
00713                     // morphed case
00714 
00715                     // first, compute the morph value for each mesh
00716                     float   morphValues[ConstraintMeshBufSize];
00717                     float   *currMorphValue;
00718                     uint    morphValueIncr;
00719 
00720                     if (m._MorphScheme) // variable case
00721                     {
00722                         currMorphValue = (float *) m._MorphScheme->make(m._Owner, size - leftToDo, &morphValues[0], sizeof(float), toProcess, true, srcStep);
00723                         morphValueIncr  = 1;
00724                     }
00725                     else 
00726                     {
00727                         currMorphValue = &m._MorphValue;
00728                         morphValueIncr  = 0;
00729                     }
00730 
00731                     do
00732                     {
00733                         const uint numShapes = m._Meshes.size();
00734                         const uint8 *m0, *m1;
00735                         float lambda;
00736                         float opLambda;
00737                         const CVertexBuffer *inVB0, *inVB1;
00738                         if (*currMorphValue >= numShapes - 1)
00739                         {
00740                             lambda = 0.f;
00741                             opLambda = 1.f;
00742                             inVB0 = inVB1 = &(m.getMeshVB(numShapes - 1));
00743                         }
00744                         else if (*currMorphValue <= 0)
00745                         {
00746                             lambda = 0.f;
00747                             opLambda = 1.f;
00748                             inVB0 = inVB1 = &(m.getMeshVB(0));
00749                         }
00750                         else
00751                         {
00752                             uint iMeshIndex = (uint) *currMorphValue;
00753                             lambda = *currMorphValue - iMeshIndex;
00754                             opLambda = 1.f - lambda;
00755                             inVB0 = &(m.getMeshVB(iMeshIndex));
00756                             inVB1 = &(m.getMeshVB(iMeshIndex + 1));
00757                         }
00758                         CVertexBufferRead vba0;
00759                         inVB0->lock (vba0);
00760                         CVertexBufferRead vba1;
00761                         inVB1->lock (vba1);
00762 
00763                         m0 = (uint8 *) vba0.getVertexCoordPointer();
00764                         m1 = (uint8 *) vba1.getVertexCoordPointer();
00765 
00766 
00767                         uint k = nbVerticesInSource;
00768                         // do we need a normal ?
00769                         if (modelVb.getVertexFormat() & CVertexBuffer::NormalFlag)
00770                         {
00771                             M.identity();
00772                             M.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
00773                             sM = M;
00774                             sM.scale(*ptCurrSize);
00775 
00776                             // offset of normals in the prerotated mesh
00777                             do
00778                             {
00779                                 CHECK_VERTEX_BUFFER((*inVB0),     m0);
00780                                 CHECK_VERTEX_BUFFER((*inVB1),     m1);
00781                                 CHECK_VERTEX_BUFFER((*inVB0),     m0 + inNormalOff);
00782                                 CHECK_VERTEX_BUFFER((*inVB1),     m1 + inNormalOff);
00783                                 CHECK_VERTEX_BUFFER(outVb,    outVertex);
00784                                 CHECK_VERTEX_BUFFER(outVb,    outVertex + outNormalOff);
00785 
00786                                 // morph, and transform the vertex
00787                                 *(CVector *) outVertex = *posIt + sM * (opLambda * *(CVector *) m0 + lambda * *(CVector *) m1);
00788                                 // morph, and transform the normal
00789                                 *(CVector *) (outVertex + outNormalOff) = M * (opLambda * *(CVector *) (m0 + inNormalOff)
00790                                                                               + lambda * *(CVector *) (m1 + inNormalOff)).normed();
00791 
00792 
00793                                 m0  += inVSize;
00794                                 m1  += inVSize;
00795                                 outVertex += outVSize;
00796                             }
00797                             while (--k);
00798                         }
00799                         else
00800                         {
00801                             // no normal to transform
00802                             sM.identity();
00803                             sM.setRot(ptBasis->X, ptBasis->Y, ptBasis->X ^ ptBasis->Y);
00804                             sM.scale(*ptCurrSize);
00805 
00806                             do
00807                             {
00808                                 CHECK_VERTEX_BUFFER((*inVB0),     m0);
00809                                 CHECK_VERTEX_BUFFER((*inVB1),     m1);
00810                                 CHECK_VERTEX_BUFFER(outVb, outVertex);
00811                                 // morph, and transform the vertex
00812                                 *(CVector *) outVertex = *posIt + sM * (opLambda * *(CVector *) m0 + opLambda * *(CVector *) m1);
00813 
00814                                 m0  += inVSize;
00815                                 m1  += inVSize;
00816                                 outVertex += outVSize;
00817                             }
00818                             while (--k);
00819                         }
00820 
00821 
00822                         ++posIt;
00823                         ptCurrSize += ptCurrSizeIncrement;
00824                         ptBasis += ptBasisIncrement;
00825                         currMorphValue += morphValueIncr;
00826                     }
00827                     while (posIt != endPosIt);
00828                 }
00829 
00830                 // compute colors if needed
00831                 if (m._ColorScheme)
00832                 {
00833                     m.computeColors(outVb, modelVb, size - leftToDo, toProcess, srcStep, *driver, vba, vbaRead);
00834                 }
00835             }
00836 
00837             // render meshs
00838             driver->activeVertexBuffer(outVb);
00839             m.doRenderPasses(driver, toProcess, md.RdrPasses, opaque);
00840             leftToDo -= toProcess;
00841 
00842         }
00843         while (leftToDo);
00844     }
00845 
00846 
00847     template <class T, class U>
00848     static void drawPrerotatedMeshs(T posIt,
00849                                     U indexIt,
00850                                     CPSConstraintMesh &m,
00851                                     uint size,
00852                                     uint32 srcStep,
00853                                     bool opaque)
00854     {
00855         // get the vb from the original mesh
00856         const CVertexBuffer   &modelVb = m.getMeshVB(0);
00857 
00859         CVertexBuffer &prerotVb  = m.makePrerotatedVb(modelVb);
00860 
00861         // driver setup
00862         IDriver *driver = m.getDriver();
00863         m.setupDriverModelMatrix();
00864 
00865         // renderPasses setup
00866         nlassert(m._Owner);
00867 
00868         // storage for sizes of meshs
00869         float sizes[ConstraintMeshBufSize];
00870 
00871         // point the size for the current mesh
00872         float *ptCurrSize;
00873         uint ptCurrSizeIncrement = m._SizeScheme ? 1 : 0;
00874 
00875         T endPosIt;
00876         uint leftToDo = size, toProcess;
00877         const uint nbVerticesInSource = modelVb.getNumVertices();
00878 
00879 
00880 
00881         // size of a complete prerotated model
00882         const uint prerotatedModelSize = prerotVb.getVertexSize() * modelVb.getNumVertices();
00883 
00885         CPSConstraintMesh::CMeshDisplay  &md    = m._MeshDisplayShare.getMeshDisplay(m._Meshes[0], modelVb, modelVb.getVertexFormat()
00886                                                                 | (m._ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
00887 
00888 
00889         m.setupRenderPasses((float) m._Owner->getOwner()->getSystemDate() - m._GlobalAnimDate, md.RdrPasses, opaque);
00890 
00891         CVertexBuffer &outVb = md.VB;
00892 
00893 
00894 
00895         // size of vertices in prerotated model
00896         const uint inVSize = prerotVb.getVertexSize();
00897 
00898         // size ofr vertices in dest vb
00899         const uint outVSize = outVb.getVertexSize();
00900 
00901         // offset of normals in vertices of the prerotated model, and source model
00902         uint normalOff=0;
00903         uint pNormalOff=0;
00904         if (prerotVb.getVertexFormat() & CVertexBuffer::NormalFlag)
00905         {
00906             normalOff  =  outVb.getNormalOff();
00907             pNormalOff =  prerotVb.getNormalOff();
00908         }
00909 
00910         if (m._ColorScheme)
00911         {
00912             CVertexBuffer::TVertexColorType vtc = driver->getVertexColorFormat();
00913             m._ColorScheme->setColorType(vtc);
00914             if (modelVb.getVertexFormat() & CVertexBuffer::PrimaryColorFlag)
00915             {
00916                 const_cast<CVertexBuffer &>(modelVb).setVertexColorFormat(vtc);
00917             }
00918         }
00919 
00920         CVertexBufferRead PrerotVba;
00921         prerotVb.lock(PrerotVba);
00922         do
00923         {
00924             toProcess = std::min(leftToDo, ConstraintMeshBufSize);
00925             outVb.setNumVertices(toProcess * nbVerticesInSource);
00926             {
00927                 CVertexBufferReadWrite vba;
00928                 outVb.lock(vba);
00929 
00930 
00931                 if (m._SizeScheme)
00932                 {
00933                     // compute size
00934                     ptCurrSize = (float *) (m._SizeScheme->make(m._Owner, size - leftToDo, &sizes[0], sizeof(float), toProcess, true, srcStep));
00935                 }
00936                 else
00937                 {
00938                     // pointer on constant size
00939                     ptCurrSize = &m._ParticleSize;
00940                 }
00941 
00942                 endPosIt = posIt + toProcess;
00943                 uint8 *outVertex  = (uint8 *) vba.getVertexCoordPointer();
00945                 do
00946                 {
00947                     uint8 *inVertex = (uint8 *) PrerotVba.getVertexCoordPointer() + prerotatedModelSize * *indexIt; // prerotated vertex
00948                     uint k = nbVerticesInSource;
00949 
00950                     if (prerotVb.getVertexFormat() & CVertexBuffer::NormalFlag) // has it a normal ?
00951                     {
00952                         do
00953                         {
00954                             CHECK_VERTEX_BUFFER(outVb, outVertex);
00955                             CHECK_VERTEX_BUFFER(prerotVb, inVertex);
00956                             CHECK_VERTEX_BUFFER(outVb, outVertex + normalOff);
00957                             CHECK_VERTEX_BUFFER(prerotVb, inVertex + pNormalOff);
00958 
00959 
00960                             // translate and resize the vertex (relatively to the mesh origin)
00961                             *(CVector *)  outVertex                      = *posIt + *ptCurrSize * *(CVector *) inVertex;
00962                             // copy the normal
00963                             *(CVector *)  (outVertex + normalOff ) = *(CVector *) (inVertex + pNormalOff);
00964                             inVertex  += inVSize;
00965                             outVertex += outVSize;
00966                         }
00967                         while (--k);
00968                     }
00969                     else
00970                     {
00971                         do
00972                         {
00973                             // translate and resize the vertex (relatively to the mesh origin)
00974                             CHECK_VERTEX_BUFFER(outVb, outVertex);
00975                             CHECK_VERTEX_BUFFER(prerotVb, inVertex);
00976                             *(CVector *)  outVertex = *posIt + *ptCurrSize * *(CVector *) inVertex;
00977                             inVertex  += inVSize;
00978                             outVertex += outVSize;
00979                         }
00980                         while (--k);
00981                     }
00982 
00983                     ++indexIt;
00984                     ++posIt;
00985                     ptCurrSize += ptCurrSizeIncrement;
00986                 }
00987                 while (posIt != endPosIt);
00988 
00989                 // compute colors if needed
00990                 if (m._ColorScheme)
00991                 {
00992                     m.computeColors(outVb, modelVb, size - leftToDo, toProcess, srcStep, *driver, vba, PrerotVba);
00993                 }
00994             }
00995 
00997             driver->activeVertexBuffer(outVb);
00998             m.doRenderPasses(driver, toProcess, md.RdrPasses, opaque);
00999             leftToDo -= toProcess;
01000 
01001         }
01002         while (leftToDo);
01003         PARTICLES_CHECK_MEM
01004     }
01005 };
01006 
01007 CPSConstraintMesh::CPSConstraintMesh() : _NumFaces(0),
01008                                          _ModelBank(NULL),
01009                                          _ModulatedStages(0),
01010                                          _Touched(1),
01011                                          _HasOpaqueFaces(0),
01012                                          _VertexColorLightingForced(false),
01013                                          _GlobalAnimationEnabled(0),
01014                                          _ReinitGlobalAnimTimeOnNewElement(0),
01015                                          _HasLightableFaces(0),
01016                                          _ValidBuild(0),
01017                                          _MorphValue(0),
01018                                          _MorphScheme(NULL)
01019 {
01020     NL_PS_FUNC(CPSConstraintMesh_CPSConstraintMesh)
01021     if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("ConstraintMesh");
01022 }
01023 
01024 //====================================================================================
01025 uint32 CPSConstraintMesh::getNumWantedTris() const
01026 {
01027     NL_PS_FUNC(CPSConstraintMesh_getNumWantedTris)
01028 //  nlassert(_ModelVb);
01029     //return _NumFaces * _Owner->getMaxSize();
01030     return _NumFaces * _Owner->getSize();
01031 }
01032 
01033 
01034 //====================================================================================
01035 bool CPSConstraintMesh::hasTransparentFaces(void)
01036 {
01037     NL_PS_FUNC(CPSConstraintMesh_hasTransparentFaces)
01038     if (!_Touched) return _HasTransparentFaces != 0;
01040     update();
01041     return _HasTransparentFaces != 0;
01042 }
01043 
01044 //====================================================================================
01045 bool CPSConstraintMesh::hasOpaqueFaces(void)
01046 {
01047     NL_PS_FUNC(CPSConstraintMesh_hasOpaqueFaces)
01048     if (!_Touched) return _HasOpaqueFaces != 0;
01049     update();
01050     return _HasOpaqueFaces != 0;
01051 }
01052 
01053 //====================================================================================
01054 bool CPSConstraintMesh::hasLightableFaces()
01055 {
01056     NL_PS_FUNC(CPSConstraintMesh_hasLightableFaces)
01057     if (!_Touched) return _HasLightableFaces != 0;
01058     update();
01059     return _HasLightableFaces != 0;
01060 }
01061 
01062 
01063 //====================================================================================
01064 void CPSConstraintMesh::setShape(const std::string &meshFileName)
01065 {
01066     NL_PS_FUNC(CPSConstraintMesh_setShape)
01067     _MeshShapeFileName.resize(1);
01068     _MeshShapeFileName[0] = meshFileName;
01069     _Touched = 1;
01070     _ValidBuild = 0;
01071 }
01072 
01073 
01074 //===========================================================================
01075 std::string         CPSConstraintMesh::getShape(void) const
01076 {
01077     NL_PS_FUNC(CPSConstraintMesh_getShape)
01078     if (_Touched)
01079     {
01080         const_cast<CPSConstraintMesh *>(this)->update();
01081     }
01082     nlassert(_MeshShapeFileName.size() == 1);
01083     return _MeshShapeFileName[0];
01084 }
01085 
01086 //====================================================================================
01087 bool CPSConstraintMesh::isValidBuild() const
01088 {
01089     NL_PS_FUNC(CPSConstraintMesh_isValidBuild)
01090     if (_Touched)
01091     {
01092         const_cast<CPSConstraintMesh *>(this)->update();
01093     }
01094     return _ValidBuild != 0;
01095 }
01096 
01097 //====================================================================================
01098 void        CPSConstraintMesh::setShapes(const std::string *shapesNames, uint numShapes)
01099 {
01100     NL_PS_FUNC(CPSConstraintMesh_setShapes)
01101     _MeshShapeFileName.resize(numShapes);
01102     std::copy(shapesNames, shapesNames + numShapes, _MeshShapeFileName.begin());
01103     _Touched = 1;
01104     _ValidBuild = 0;
01105 }
01106 
01107 //====================================================================================
01108 uint        CPSConstraintMesh::getNumShapes() const
01109 {
01110     NL_PS_FUNC(CPSConstraintMesh_getNumShapes)
01111     if (_Touched)
01112     {
01113         const_cast<CPSConstraintMesh *>(this)->update();
01114     }
01115     return _MeshShapeFileName.size();
01116 }
01117 
01118 //====================================================================================
01119 void    CPSConstraintMesh::getShapesNames(std::string *shapesNames) const
01120 {
01121     NL_PS_FUNC(CPSConstraintMesh_getShapesNames)
01122     if (_Touched)
01123     {
01124         const_cast<CPSConstraintMesh *>(this)->update();
01125     }
01126     std::copy(_MeshShapeFileName.begin(), _MeshShapeFileName.end(), shapesNames);
01127 }
01128 
01129 
01130 
01131 //====================================================================================
01132 void        CPSConstraintMesh::setShape(uint index, const std::string &shapeName)
01133 {
01134     NL_PS_FUNC(CPSConstraintMesh_setShape)
01135     nlassert(index < _MeshShapeFileName.size());
01136     _MeshShapeFileName[index] = shapeName;
01137     _Touched = 1;
01138     _ValidBuild = 0;
01139 }
01140 
01141 
01142 //====================================================================================
01143 const std::string          &CPSConstraintMesh::getShape(uint index) const
01144 {
01145     NL_PS_FUNC(CPSConstraintMesh_getShape)
01146     if (_Touched)
01147     {
01148         const_cast<CPSConstraintMesh *>(this)->update();
01149     }
01150     nlassert(index < _MeshShapeFileName.size());
01151     return _MeshShapeFileName[index];
01152 }
01153 
01154 
01155 
01156 //====================================================================================
01157 void    CPSConstraintMesh::setMorphValue(float value)
01158 {
01159     NL_PS_FUNC(CPSConstraintMesh_setMorphValue)
01160     delete _MorphScheme;
01161     _MorphScheme = NULL;
01162     _MorphValue = value;
01163 }
01164 
01165 
01166 //====================================================================================
01167 float   CPSConstraintMesh::getMorphValue() const
01168 {
01169     NL_PS_FUNC(CPSConstraintMesh_getMorphValue)
01170     return _MorphValue;
01171 }
01172 
01173 //====================================================================================
01174 void    CPSConstraintMesh::setMorphScheme(CPSAttribMaker<float> *scheme)
01175 {
01176     NL_PS_FUNC(CPSConstraintMesh_setMorphScheme)
01177     delete _MorphScheme;
01178     _MorphScheme = scheme;
01179     if (_MorphScheme->hasMemory()) _MorphScheme->resize(_Owner->getMaxSize(), _Owner->getSize());
01180 }
01181 
01182 //====================================================================================
01183 CPSAttribMaker<float>       *CPSConstraintMesh::getMorphScheme()
01184 {
01185     NL_PS_FUNC(CPSConstraintMesh_getMorphScheme)
01186     return _MorphScheme;
01187 }
01188 
01189 //====================================================================================
01190 const CPSAttribMaker<float> *CPSConstraintMesh::getMorphScheme() const
01191 {
01192     NL_PS_FUNC(CPSConstraintMesh_getMorphScheme)
01193     return _MorphScheme;
01194 }
01195 
01196 
01197 //====================================================================================
01198 static CMesh *GetDummyMeshFromBank(CShapeBank &sb)
01199 {
01200     NL_PS_FUNC(GetDummyMeshFromBank)
01201     static const std::string dummyMeshName("dummy constraint mesh shape");
01202     if (sb.getPresentState(dummyMeshName) == CShapeBank::Present)
01203     {
01204         return NLMISC::safe_cast<CMesh *>(sb.addRef(dummyMeshName));
01205     }
01206     else
01207     {
01208         // no dummy shape created -> add one to the bank
01209         CMesh *m = CreateDummyMesh();
01210         sb.add(std::string("dummy constraint mesh shape"), m);
01211         return m;
01212     }
01213 }
01214 
01215 //====================================================================================
01216 void CPSConstraintMesh::getShapeNumVerts(std::vector<sint> &numVerts)
01217 {
01218     NL_PS_FUNC(CPSConstraintMesh_getShapeNumVerts)
01219     _Touched = 1; // force reload
01220     update(&numVerts);
01221 }
01222 
01223 //====================================================================================
01224 bool CPSConstraintMesh::update(std::vector<sint> *numVertsVect /*= NULL*/)
01225 {
01226     NL_PS_FUNC(CPSConstraintMesh_update)
01227     bool ok = true;
01228     if (!_Touched) return ok;
01229 
01230     clean();
01231 
01232     nlassert(_Owner->getScene());
01233 
01234     CScene *scene = _Owner->getScene();
01235     _ModelBank = scene->getShapeBank();
01236     IShape *is = 0;
01237 
01238 
01239     uint32 vFormat = 0;
01240     uint   numVerts = 0;
01241     uint8  uvRouting[CVertexBuffer::MaxStage];
01242 
01243     if (_MeshShapeFileName.size() == 0)
01244     {
01245         _MeshShapeFileName.resize(1);
01246         _MeshShapeFileName[0] = DummyShapeName;
01247     }
01248 
01249 
01250     _Meshes.resize(_MeshShapeFileName.size());
01251     _MeshVertexBuffers.resize(_MeshShapeFileName.size());
01252     std::fill(_MeshVertexBuffers.begin(), _MeshVertexBuffers.end(), (CVertexBuffer *) NULL);
01253     if (numVertsVect) numVertsVect->resize(_MeshShapeFileName.size());
01254     for (uint k = 0; k < _MeshShapeFileName.size(); ++k)
01255     {
01256         if (_ModelBank->getPresentState(_MeshShapeFileName[k]) == CShapeBank::Present)
01257         {
01258             CMesh *mesh = dynamic_cast<CMesh *>( _ModelBank->addRef(_MeshShapeFileName[k]));
01259             if (!mesh)
01260             {
01261                 nlwarning("Tried to bind a shape that is not a mesh to a mesh particle : %s", _MeshShapeFileName[k].c_str());
01262                 _ModelBank->release(is);
01263                 ok = false;
01264                 if (numVertsVect) (*numVertsVect)[k] = ShapeFileIsNotAMesh;
01265             }
01266             else
01267             {
01268                 _Meshes[k] = mesh;
01270                 if (k == 0)
01271                 {
01272                     vFormat = mesh->getVertexBuffer().getVertexFormat();
01273                     numVerts =  mesh->getVertexBuffer().getNumVertices();
01274                     std::copy(mesh->getVertexBuffer().getUVRouting(), mesh->getVertexBuffer().getUVRouting() + CVertexBuffer::MaxStage, uvRouting);
01275                     if (numVertsVect) (*numVertsVect)[k] = (sint) numVerts;
01276                 }
01277                 else
01278                 {
01279                     if (vFormat != mesh->getVertexBuffer().getVertexFormat())
01280                     {
01281                         nlwarning("Vertex format differs between meshs");
01282                         ok = false;
01283                     }
01284                     if (numVerts != mesh->getVertexBuffer().getNumVertices())
01285                     {
01286                         nlwarning("Num vertices differs between meshs");
01287                         ok = false;
01288                     }
01289                     if (!std::equal(mesh->getVertexBuffer().getUVRouting(), mesh->getVertexBuffer().getUVRouting() + CVertexBuffer::MaxStage, uvRouting))
01290                     {
01291                         nlwarning("UV routing differs between meshs");
01292                         ok = false;
01293                     }
01294                     if (numVertsVect) (*numVertsVect)[k] = (sint) mesh->getVertexBuffer().getNumVertices();
01295                 }
01296             }
01297         }
01298         else
01299         {
01300             try
01301             {
01302                 _ModelBank->load(_MeshShapeFileName[k]);
01303             }
01304             catch (NLMISC::EPathNotFound &)
01305             {
01306                 nlwarning("mesh not found : %s; used as a constraint mesh particle", _MeshShapeFileName[k].c_str());
01307                 // shape not found, so not present in the shape bank -> we create a dummy shape
01308             }
01309 
01310             if (_ModelBank->getPresentState(_MeshShapeFileName[k]) != CShapeBank::Present)
01311             {
01312                 ok = false;
01313                 if (numVertsVect) (*numVertsVect)[k] = ShapeFileNotLoaded;
01314             }
01315             else
01316             {
01317                 is = _ModelBank->addRef(_MeshShapeFileName[k]);
01318                 if (!dynamic_cast<CMesh *>(is)) // is it a mesh
01319                 {
01320                     nlwarning("Tried to bind a shape that is not a mesh to a mesh particle : %s", _MeshShapeFileName[k].c_str());
01321                     _ModelBank->release(is);
01322                     ok = false;
01323                     if (numVertsVect) (*numVertsVect)[k] = ShapeFileIsNotAMesh;
01324                 }
01325                 else
01326                 {
01327                     CMesh &m  = * NLMISC::safe_cast<CMesh *>(is);
01329                     if (m.getVertexBuffer().getNumVertices() > ConstraintMeshMaxNumVerts)
01330                     {
01331                         nlwarning("Tried to bind a mesh that has more than %d vertices to a particle mesh: %s", (int) ConstraintMeshMaxNumVerts, _MeshShapeFileName[k].c_str());
01332                         _ModelBank->release(is);
01333                         ok = false;
01334                         if (numVertsVect) (*numVertsVect)[k] = ShapeHasTooMuchVertices;
01335                     }
01336                     else
01337                     {
01338                         _Meshes[k] = &m;
01339                         if (k == 0)
01340                         {
01341                             vFormat = m.getVertexBuffer().getVertexFormat();
01342                             numVerts =  m.getVertexBuffer().getNumVertices();
01343                             std::copy(m.getVertexBuffer().getUVRouting(), m.getVertexBuffer().getUVRouting() + CVertexBuffer::MaxStage, uvRouting);
01344                             if (numVertsVect) (*numVertsVect)[k] = numVerts;
01345                         }
01346                         else
01347                         {
01348                             uint32 otherVFormat = m.getVertexBuffer().getVertexFormat();
01349                             uint   otherNumVerts = m.getVertexBuffer().getNumVertices();
01350                             if (otherVFormat != vFormat ||
01351                                 otherNumVerts != numVerts ||
01352                                 !(std::equal(m.getVertexBuffer().getUVRouting(), m.getVertexBuffer().getUVRouting() + CVertexBuffer::MaxStage, uvRouting)))
01353                             {
01354                                 ok = false;
01355                             }
01356                             if (numVertsVect) (*numVertsVect)[k] = otherNumVerts;
01357                         }
01358                     }
01359                 }
01360             }
01361         }
01362 
01363         if (!ok && !numVertsVect) break;
01364     }
01365 
01366     if (!ok)
01367     {
01368         releaseShapes();
01369         _Meshes.resize(1);
01370         _MeshVertexBuffers.resize(1);
01371         _Meshes[0] = GetDummyMeshFromBank(*_ModelBank);
01372         _MeshVertexBuffers[0] = &_Meshes[0]->getVertexBuffer();
01373     }
01374 
01375     const CMesh &m  = *_Meshes[0];
01376 
01378     _NumFaces = getMeshNumTri(m);
01379     /*
01380     notifyOwnerMaxNumFacesChanged();
01381     if (_Owner && _Owner->getOwner())
01382     {
01383         _Owner->getOwner()->notifyMaxNumFacesChanged();
01384     }*/
01385 
01387     bool hasTransparentFaces, hasOpaqueFaces;
01388     CheckForOpaqueAndTransparentFacesInMesh(m, hasTransparentFaces, hasOpaqueFaces);
01389     _HasTransparentFaces = hasTransparentFaces;
01390     _HasOpaqueFaces = hasOpaqueFaces;
01391     _HasLightableFaces = CheckForLightableFacesInMesh(m);
01392     _GlobalAnimDate = _Owner->getOwner()->getSystemDate();
01393     _Touched = 0;
01394     _ValidBuild = ok ? 1 : 0;
01395     nlassert(_Meshes.size() > 0);
01396 
01397     return ok;
01398 
01399 }
01400 
01401 
01402 
01403 //====================================================================================
01404 void CPSConstraintMesh::hintRotateTheSame(uint32 nbConfiguration,
01405                                           float minAngularVelocity,
01406                                           float maxAngularVelocity
01407                                         )
01408 {
01409     NL_PS_FUNC(CPSConstraintMesh_hintRotateTheSame)
01410     nlassert(nbConfiguration <= ConstraintMeshMaxNumPrerotatedModels);
01411 
01412     // TODO : avoid code duplication with CPSFace ...
01413     _MinAngularVelocity = minAngularVelocity;
01414     _MaxAngularVelocity = maxAngularVelocity;
01415 
01416 
01417 
01418     _PrecompBasis.resize(nbConfiguration);
01419 
01420     if (nbConfiguration)
01421     {
01422         // each precomp basis is created randomly;
01423         for (uint k = 0; k < nbConfiguration; ++k)
01424         {
01425              CVector v = MakeRandomUnitVect();
01426             _PrecompBasis[k].Basis = CPlaneBasis(v);
01427             _PrecompBasis[k].Axis = MakeRandomUnitVect();
01428             _PrecompBasis[k].AngularVelocity = minAngularVelocity
01429                                                + (rand() % 20000) / 20000.f * (maxAngularVelocity - minAngularVelocity);
01430 
01431         }
01432 
01433         // we need to do this because nbConfs may have changed
01434         fillIndexesInPrecompBasis();
01435     }
01436 }
01437 
01438 
01439 //====================================================================================
01440 void CPSConstraintMesh::fillIndexesInPrecompBasis(void)
01441 {
01442     NL_PS_FUNC(CPSConstraintMesh_fillIndexesInPrecompBasis)
01443     // TODO : avoid code duplication with CPSFace ...
01444     const uint32 nbConf = _PrecompBasis.size();
01445     if (_Owner)
01446     {
01447         _IndexInPrecompBasis.resize( _Owner->getMaxSize() );
01448     }
01449     for (CPSVector<uint32>::V::iterator it = _IndexInPrecompBasis.begin(); it != _IndexInPrecompBasis.end(); ++it)
01450     {
01451         *it = rand() % nbConf;
01452     }
01453 }
01454 
01455 //====================================================================================
01457 void CPSConstraintMesh::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01458 {
01459     NL_PS_FUNC(CPSConstraintMesh_IStream )
01460 
01461     sint ver = f.serialVersion(4);
01462     if (f.isReading())
01463     {
01464         clean();
01465     }
01466 
01467     CPSParticle::serial(f);
01468     CPSSizedParticle::serialSizeScheme(f);
01469     CPSRotated3DPlaneParticle::serialPlaneBasisScheme(f);
01470 
01471     // prerotations ...
01472 
01473     if (f.isReading())
01474     {
01475         uint32 nbConfigurations;
01476         f.serial(nbConfigurations);
01477         if (nbConfigurations)
01478         {
01479             f.serial(_MinAngularVelocity, _MaxAngularVelocity);
01480         }
01481         hintRotateTheSame(nbConfigurations, _MinAngularVelocity, _MaxAngularVelocity);
01482     }
01483     else
01484     {
01485         uint32 nbConfigurations = _PrecompBasis.size();
01486         f.serial(nbConfigurations);
01487         if (nbConfigurations)
01488         {
01489             f.serial(_MinAngularVelocity, _MaxAngularVelocity);
01490         }
01491     }
01492 
01493     // saves the model file name, or an empty string if nothing has been set
01494     static std::string emptyStr;
01495 
01496     if (ver < 4) // early version : no morphing support
01497     {
01498         if (!f.isReading())
01499         {
01500             if (_MeshShapeFileName.size() > 0)
01501             {
01502                 f.serial(_MeshShapeFileName[0]);
01503             }
01504             else
01505             {
01506                 f.serial(emptyStr);
01507             }
01508         }
01509         else
01510         {
01511             _MeshShapeFileName.resize(1);
01512             f.serial(_MeshShapeFileName[0]);
01513             _Touched = true;
01514             _ValidBuild = 0;
01515         }
01516     }
01517 
01518     if (ver > 1)
01519     {
01520         CPSColoredParticle::serialColorScheme(f);
01521         f.serial(_ModulatedStages);
01522         if (f.isReading())
01523         {
01524             bool vcEnabled;
01525             f.serial(vcEnabled);
01526             _VertexColorLightingForced = vcEnabled;
01527         }
01528         else
01529         {
01530             bool vcEnabled = (_VertexColorLightingForced != 0);
01531             f.serial(vcEnabled);
01532         }
01533     }
01534 
01535     if (ver > 2) // texture animation
01536     {
01537         if (f.isReading())
01538         {
01539             bool gaEnabled;
01540             f.serial(gaEnabled);
01541             _GlobalAnimationEnabled = gaEnabled;
01542             if (gaEnabled)
01543             {
01544                 PGlobalTexAnims newPtr(new CGlobalTexAnims); // create new
01545                 //std::swap(_GlobalTexAnims, newPtr);            // replace old
01546                 _GlobalTexAnims = newPtr;
01547                 f.serial(*_GlobalTexAnims);
01548             }
01549 
01550             bool rgt;
01551             f.serial(rgt);
01552             _ReinitGlobalAnimTimeOnNewElement = rgt;
01553         }
01554         else
01555         {
01556             bool gaEnabled = (_GlobalAnimationEnabled != 0);
01557             f.serial(gaEnabled);
01558             if (gaEnabled)
01559             {
01560                 f.serial(*_GlobalTexAnims);
01561             }
01562 
01563             bool rgt = _ReinitGlobalAnimTimeOnNewElement != 0;
01564             f.serial(rgt);
01565         }
01566     }
01567 
01568     if (ver > 3) // mesh morphing
01569     {
01570         if (!f.isReading())
01571         {
01572             // remove path
01573             TMeshNameVect meshNamesWithoutPath = _MeshShapeFileName;
01574             std::transform(meshNamesWithoutPath.begin(), meshNamesWithoutPath.end(), meshNamesWithoutPath.begin(), std::ptr_fun(NLMISC::CFile::getFilename));
01575             f.serialCont(meshNamesWithoutPath);
01576         }
01577         else
01578         {
01579             f.serialCont(_MeshShapeFileName);
01580         }
01581         bool useScheme;
01582         if (f.isReading())
01583         {
01584             delete _MorphScheme;
01585         }
01586         else
01587         {
01588             useScheme = _MorphScheme != NULL;
01589         }
01590         f.serial(useScheme);
01591         if (useScheme)
01592         {
01593             f.serialPolyPtr(_MorphScheme);
01594         }
01595         else
01596         {
01597             f.serial(_MorphValue);
01598         }
01599     }
01600 }
01601 
01602 //====================================================================================
01603 CPSConstraintMesh::~CPSConstraintMesh()
01604 {
01605     NL_PS_FUNC(CPSConstraintMesh_CPSConstraintMeshDtor)
01606     clean();
01607     delete _MorphScheme;
01608 }
01609 
01610 
01611 
01612 //====================================================================================
01613 void CPSConstraintMesh::releaseShapes()
01614 {
01615     NL_PS_FUNC(CPSConstraintMesh_releaseShapes)
01616     for (TMeshVect::iterator it = _Meshes.begin(); it != _Meshes.end(); ++it)
01617     {
01618         if (*it)
01619         {
01620             if (_ModelBank) _ModelBank->release(*it);
01621         }
01622     }
01623     _Meshes.clear();
01624     _MeshVertexBuffers.clear();
01625 }
01626 
01627 //====================================================================================
01628 void CPSConstraintMesh::clean(void)
01629 {
01630     NL_PS_FUNC(CPSConstraintMesh_clean)
01631     if (_ModelBank)
01632     {
01633         releaseShapes();
01634     }
01635 }
01636 
01637 
01638 //====================================================================================
01639 CVertexBuffer &CPSConstraintMesh::makePrerotatedVb(const CVertexBuffer &inVb)
01640 {
01641     NL_PS_FUNC(CPSConstraintMesh_makePrerotatedVb)
01642     // get a VB that has positions and eventually normals
01643     CVertexBuffer &prerotatedVb = inVb.getVertexFormat() & CVertexBuffer::NormalFlag ? _PreRotatedMeshVBWithNormal : _PreRotatedMeshVB;
01644     CVertexBufferReadWrite vba;
01645     prerotatedVb.lock (vba);
01646     CVertexBufferRead vbaIn;
01647     inVb.lock (vbaIn);
01648 
01649     // size of vertices for source VB
01650     const uint vSize = inVb.getVertexSize();
01651 
01652     // size for vertices in prerotated model
01653     const uint vpSize = prerotatedVb.getVertexSize();
01654 
01655 
01656     // offset of normals in vertices of the prerotated model, and source model
01657     uint normalOff=0;
01658     uint pNormalOff=0;
01659     if (prerotatedVb.getVertexFormat() & CVertexBuffer::NormalFlag)
01660     {
01661         normalOff  =  inVb.getNormalOff();
01662         pNormalOff =  prerotatedVb.getNormalOff();
01663     }
01664 
01665     const uint nbVerticesInSource   = inVb.getNumVertices();
01666 
01667 
01668     // rotate basis
01669     // and compute the set of prerotated meshs that will then duplicated (with scale and translation) to create the Vb of what must be drawn
01670     uint8 *outVertex = (uint8 *) vba.getVertexCoordPointer();
01671     for (CPSVector<CPlaneBasisPair>::V::iterator it = _PrecompBasis.begin(); it != _PrecompBasis.end(); ++it)
01672     {
01673         // not optimized at all, but this will apply to very few elements anyway...
01674         CMatrix mat;
01675         mat.rotate(CQuat(it->Axis, CParticleSystem::EllapsedTime * it->AngularVelocity));
01676         CVector n = mat * it->Basis.getNormal();
01677         it->Basis = CPlaneBasis(n);
01678 
01679         mat.identity();
01680         mat.setRot(it->Basis.X, it->Basis.Y, it->Basis.X ^ it->Basis.Y);
01681 
01682         uint8 *inVertex = (uint8 *) vbaIn.getVertexCoordPointer();
01683 
01684         uint k = nbVerticesInSource;
01685 
01686         // check whether we need to rotate normals as well...
01687         if (inVb.getVertexFormat() & CVertexBuffer::NormalFlag)
01688         {
01689 
01690             do
01691             {
01692                 CHECK_VERTEX_BUFFER(inVb, inVertex);
01693                 CHECK_VERTEX_BUFFER(inVb, inVertex + normalOff);
01694                 CHECK_VERTEX_BUFFER(prerotatedVb, outVertex);
01695                 CHECK_VERTEX_BUFFER(prerotatedVb, outVertex + pNormalOff);
01696 
01697                 * (CVector *) outVertex =  mat.mulVector(* (CVector *) inVertex);
01698                 * (CVector *) (outVertex + normalOff) =  mat.mulVector(* (CVector *) (inVertex + pNormalOff) );
01699                 outVertex += vpSize;
01700                 inVertex  += vSize;
01701 
01702             }
01703             while (--k);
01704         }
01705         else
01706         {
01707             // no normal included
01708             do
01709             {
01710 
01711                 CHECK_VERTEX_BUFFER(prerotatedVb, outVertex);
01712                 CHECK_VERTEX_BUFFER(inVb, inVertex);
01713 
01714                 * (CVector *) outVertex =  mat.mulVector(* (CVector *) inVertex);
01715                 outVertex += vpSize;
01716                 inVertex += vSize;
01717             }
01718             while (--k);
01719 
01720         }
01721     }
01722     return prerotatedVb;
01723 }
01724 
01725 
01726 //====================================================================================
01727 void CPSConstraintMesh::step(TPSProcessPass pass)
01728 {
01729     NL_PS_FUNC(CPSConstraintMesh_step)
01730         if (
01731             (pass == PSBlendRender && hasTransparentFaces())
01732             || (pass == PSSolidRender && hasOpaqueFaces())
01733             )
01734         {
01735             draw(pass == PSSolidRender);
01736         }
01737         else
01738         if (pass == PSToolRender) // edition mode only
01739         {
01740             showTool();
01741         }
01742 }
01743 
01744 //====================================================================================
01745 void CPSConstraintMesh::draw(bool opaque)
01746 {
01747 //  if (!FilterPS[4]) return;
01748     NL_PS_FUNC(CPSConstraintMesh_draw)
01749     PARTICLES_CHECK_MEM;
01750     nlassert(_Owner);
01751 
01752     update(); // update mesh datas if needed
01753     uint32 step;
01754     uint   numToProcess;
01755     computeSrcStep(step, numToProcess);
01756     if (!numToProcess) return;
01757     _Owner->incrementNbDrawnParticles(numToProcess); // for benchmark purpose
01758 
01759 
01760     if (_PrecompBasis.size() == 0) 
01761     {
01762         if (step == (1 << 16))
01763         {
01764             CPSConstraintMeshHelper::drawMeshs(_Owner->getPos().begin(),
01765                                               *this,
01766                                               numToProcess,
01767                                               step,
01768                                               opaque
01769                                              );
01770         }
01771         else
01772         {
01773             CPSConstraintMeshHelper::drawMeshs(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
01774                                               *this,
01775                                               numToProcess,
01776                                               step,
01777                                               opaque
01778                                              );
01779         }
01780     }
01781     else
01782     {
01783         if (step == (1 << 16))
01784         {
01785             CPSConstraintMeshHelper::drawPrerotatedMeshs(_Owner->getPos().begin(),
01786                                                          _IndexInPrecompBasis.begin(),
01787                                                          *this,
01788                                                          numToProcess,
01789                                                          step,
01790                                                          opaque
01791                                                         );
01792         }
01793         else
01794         {
01795             typedef CAdvance1616Iterator<CPSVector<uint32>::V::const_iterator, uint32> TIndexIterator;
01796             CPSConstraintMeshHelper::drawPrerotatedMeshs(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
01797                                                          TIndexIterator(_IndexInPrecompBasis.begin(), 0, step),
01798                                                          *this,
01799                                                          numToProcess,
01800                                                          step,
01801                                                          opaque
01802                                                         );
01803         }
01804     }
01805 
01806 
01807 }
01808 
01809 //====================================================================================
01810 void CPSConstraintMesh::setupMaterialColor(CMaterial &destMat, CMaterial &srcMat)
01811 {
01812     NL_PS_FUNC(CPSConstraintMesh_setupMaterialColor)
01813     if (destMat.getShader() != CMaterial::Normal) return;
01814     for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
01815     {
01816         if (_ModulatedStages & (1 << k))
01817         {
01818             destMat.texEnvArg0RGB(k, CMaterial::Texture, CMaterial::SrcColor);
01819             destMat.texEnvArg0Alpha(k, CMaterial::Texture, CMaterial::SrcAlpha);
01820             destMat.texEnvArg1RGB(k, CMaterial::Diffuse, CMaterial::SrcColor);
01821             destMat.texEnvArg1Alpha(k, CMaterial::Diffuse, CMaterial::SrcAlpha);
01822             destMat.texEnvOpRGB(k, CMaterial::Modulate);
01823             destMat.texEnvOpAlpha(k, CMaterial::Modulate);
01824         }
01825         else // restore from source material
01826         {
01827             destMat.setTexEnvMode(k, srcMat.getTexEnvMode(k));
01828         }
01829     }
01830     if (_ColorScheme == NULL) // per mesh color ?
01831     {
01832         destMat.setColor(_Color);
01833         if (destMat.isLighted())
01834         {
01835             destMat.setDiffuse(_Color);
01836         }
01837     }
01838 }
01839 
01840 
01841 
01842 
01843 //====================================================================================
01844 void    CPSConstraintMesh::setupRenderPasses(float date, TRdrPassSet &rdrPasses, bool opaque)
01845 {
01846     NL_PS_FUNC(CPSConstraintMesh_setupRenderPasses)
01847     // render meshs : we process each rendering pass
01848     for (TRdrPassSet::iterator rdrPassIt = rdrPasses.begin();
01849          rdrPassIt != rdrPasses.end(); ++rdrPassIt)
01850     {
01851 
01852         CMaterial &Mat = rdrPassIt->Mat;
01853         CMaterial &SourceMat = rdrPassIt->SourceMat;
01854 
01855 
01857         if ((opaque && Mat.getZWrite()) || (!opaque && ! Mat.getZWrite()))
01858         {
01859 
01860 
01861             // has to setup material constant color ?
01862             // global color not supported for mesh
01863         /*  CParticleSystem &ps = *(_Owner->getOwner());
01864             if (!_ColorScheme)
01865             {
01866                 NLMISC::CRGBA col;
01867                 col.modulateFromColor(SourceMat.getColor(), _Color);
01868                 if (ps.getColorAttenuationScheme() == NULL || ps.isUserColorUsed())
01869                 {
01870                     col.modulateFromColor(col, ps.getGlobalColor());
01871                 }
01872                 Mat.setColor(col);
01873             }
01874             else
01875             {
01876                 Mat.setColor(ps.getGlobalColor());
01877             }*/
01878 
01881             setupMaterialColor(Mat, SourceMat);
01882 
01884             bool forceVertexcolorLighting;
01885             if (_ColorScheme != NULL)
01886             {
01887                 forceVertexcolorLighting = _VertexColorLightingForced != 0 ? true : SourceMat.getLightedVertexColor();
01888             }
01889             else
01890             {
01891                 forceVertexcolorLighting = false;
01892             }
01893             if (forceVertexcolorLighting != Mat.getLightedVertexColor()) // avoid to touch mat if not needed
01894             {
01895                 Mat.setLightedVertexColor(forceVertexcolorLighting);
01896             }
01897 
01899             if (_GlobalAnimationEnabled != 0)
01900             {
01901                 for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
01902                 {
01903                     if (Mat.getTexture(k) != NULL)
01904                     {
01905                         Mat.enableUserTexMat(k, true);
01906                         CMatrix mat;
01907                         _GlobalTexAnims->Anims[k].buildMatrix(date, mat);
01908                         Mat.setUserTexMat(k ,mat);
01909                     }
01910                 }
01911             }
01912         }
01913     }
01914 
01915 }
01916 
01917 //====================================================================================
01918 void    CPSConstraintMesh::doRenderPasses(IDriver *driver, uint numObj, TRdrPassSet &rdrPasses, bool opaque)
01919 {
01920     NL_PS_FUNC(CPSConstraintMesh_doRenderPasses)
01921     // render meshs : we process each rendering pass
01922     for (TRdrPassSet::iterator rdrPassIt = rdrPasses.begin(); rdrPassIt != rdrPasses.end(); ++rdrPassIt)
01923     {
01924         CMaterial &Mat = rdrPassIt->Mat;
01925         if ((opaque && Mat.getZWrite()) || (!opaque && ! Mat.getZWrite()))
01926         {
01928             rdrPassIt->PbTri.setNumIndexes(((rdrPassIt->PbTri.capacity()/3)   * numObj / ConstraintMeshBufSize) * 3);
01929             rdrPassIt->PbLine.setNumIndexes(((rdrPassIt->PbLine.capacity()/2) * numObj / ConstraintMeshBufSize) * 2);
01930 
01932             driver->activeIndexBuffer (rdrPassIt->PbTri);
01933             driver->renderTriangles(rdrPassIt->Mat, 0, rdrPassIt->PbTri.getNumIndexes()/3);
01934             if (rdrPassIt->PbLine.getNumIndexes() != 0)
01935             {
01936                 driver->activeIndexBuffer (rdrPassIt->PbLine);
01937                 driver->renderLines(rdrPassIt->Mat, 0, rdrPassIt->PbLine.getNumIndexes()/2);
01938             }
01939         }
01940     }
01941 
01942 }
01943 
01944 
01945 //====================================================================================
01946 void    CPSConstraintMesh::computeColors(CVertexBuffer &outVB, const CVertexBuffer &inVB, uint startIndex, uint toProcess, uint32 srcStep, IDriver &drv,
01947                                          CVertexBufferReadWrite &vba,
01948                                          CVertexBufferRead &vbaIn
01949                                         )
01950 {
01951     NL_PS_FUNC(CPSConstraintMesh_computeColors)
01952     nlassert(_ColorScheme);
01953     // there are 2 case : 1 - the source mesh has colors, which are modulated with the current color
01954     //                    2 - the source mesh has no colors : colors are directly copied into the dest vb
01955 
01956     if (inVB.getVertexFormat() & CVertexBuffer::PrimaryColorFlag) // case 1
01957     {
01958         // TODO: optimisation : avoid to duplicate colors...
01959         _ColorScheme->makeN(_Owner, startIndex, vba.getColorPointer(), outVB.getVertexSize(), toProcess, inVB.getNumVertices(), srcStep);
01960         // modulate from the source mesh
01961         // todo hulud d3d vertex color RGBA / BGRA
01962         uint8 *vDest  = (uint8 *) vba.getColorPointer();
01963         uint8 *vSrc   = (uint8 *) vbaIn.getColorPointer();
01964         const uint vSize = outVB.getVertexSize();
01965         const uint numVerts = inVB.getNumVertices();
01966         uint  meshSize = vSize * numVerts;
01967         for (uint k = 0; k < toProcess; ++k)
01968         {
01969             NLMISC::CRGBA::modulateColors((CRGBA *) vDest, (CRGBA *) vSrc, (CRGBA *) vDest, numVerts, vSize, vSize);
01970             vDest += meshSize;
01971         }
01972     }
01973     else // case 2
01974     {
01975         _ColorScheme->makeN(_Owner, startIndex, vba.getColorPointer(), outVB.getVertexSize(), toProcess, inVB.getNumVertices(), srcStep);
01976     }
01977 }
01978 
01979 
01980 //====================================================================================
01981 void CPSConstraintMesh::newElement(const CPSEmitterInfo &info)
01982 {
01983     NL_PS_FUNC(CPSConstraintMesh_newElement)
01984     newSizeElement(info);
01985     newPlaneBasisElement(info);
01986     // TODO : avoid code cuplication with CPSFace ...
01987     const uint32 nbConf = _PrecompBasis.size();
01988     if (nbConf) // do we use precomputed basis ?
01989     {
01990         _IndexInPrecompBasis[_Owner->getNewElementIndex()] = rand() % nbConf;
01991     }
01992     newColorElement(info);
01993     if (_GlobalAnimationEnabled && _ReinitGlobalAnimTimeOnNewElement)
01994     {
01995         _GlobalAnimDate = _Owner->getOwner()->getSystemDate();
01996     }
01997     if (_MorphScheme && _MorphScheme->hasMemory()) _MorphScheme->newElement(info);
01998 }
01999 
02000 //====================================================================================
02001 void CPSConstraintMesh::deleteElement(uint32 index)
02002 {
02003     NL_PS_FUNC(CPSConstraintMesh_deleteElement)
02004     deleteSizeElement(index);
02005     deletePlaneBasisElement(index);
02006     // TODO : avoid code cuplication with CPSFace ...
02007     if (_PrecompBasis.size()) // do we use precomputed basis ?
02008     {
02009         // replace ourself by the last element...
02010         _IndexInPrecompBasis[index] = _IndexInPrecompBasis[_Owner->getSize() - 1];
02011     }
02012     deleteColorElement(index);
02013     if (_MorphScheme && _MorphScheme->hasMemory()) _MorphScheme->deleteElement(index);
02014 }
02015 
02016 //====================================================================================
02017 void CPSConstraintMesh::resize(uint32 size)
02018 {
02019     NL_PS_FUNC(CPSConstraintMesh_resize)
02020     nlassert(size < (1 << 16));
02021     resizeSize(size);
02022     resizePlaneBasis(size);
02023     // TODO : avoid code cuplication with CPSFace ...
02024     if (_PrecompBasis.size()) // do we use precomputed basis ?
02025     {
02026         _IndexInPrecompBasis.resize(size);
02027     }
02028     resizeColor(size);
02029     if (_MorphScheme && _MorphScheme->hasMemory()) _MorphScheme->resize(size, _Owner->getSize());
02030 }
02031 
02032 //====================================================================================
02033 void CPSConstraintMesh::updateMatAndVbForColor(void)
02034 {
02035     NL_PS_FUNC(CPSConstraintMesh_updateMatAndVbForColor)
02036     // nothing to do for us...
02037 }
02038 
02039 //====================================================================================
02040 void    CPSConstraintMesh::forceStageModulationByColor(uint stage, bool force)
02041 {
02042     NL_PS_FUNC(CPSConstraintMesh_forceStageModulationByColor)
02043     nlassert(stage < IDRV_MAT_MAXTEXTURES);
02044     if (force)
02045     {
02046         _ModulatedStages |= 1 << stage;
02047     }
02048     else
02049     {
02050         _ModulatedStages &= ~(1 << stage);
02051     }
02052 }
02053 
02054 //====================================================================================
02055 bool    CPSConstraintMesh::isStageModulationForced(uint stage) const
02056 {
02057     NL_PS_FUNC(CPSConstraintMesh_isStageModulationForced)
02058     nlassert(stage < IDRV_MAT_MAXTEXTURES);
02059     return (_ModulatedStages & (1 << stage)) != 0;
02060 }
02061 
02062 //====================================================================================
02063 
02069 static void DuplicatePrimitiveBlock(const CIndexBuffer &srcBlock, CIndexBuffer &destBlock, uint nbReplicate, uint vertOffset)
02070 {
02071     NL_PS_FUNC(DuplicatePrimitiveBlock)
02072     PARTICLES_CHECK_MEM;
02073 
02074     // this must be update each time a new primitive is added
02075 
02076     // loop counters, and index of the current primitive in the dest pb
02077     uint k, l, index;
02078 
02079     // the current vertex offset.
02080     uint currVertOffset;
02081 
02082 
02083     // duplicate triangles
02084     uint numTri = srcBlock.getNumIndexes()/3;
02085     destBlock.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
02086     destBlock.setNumIndexes(3 * numTri * nbReplicate);
02087 
02088     index = 0;
02089     currVertOffset = 0;
02090 
02091     CIndexBufferRead ibaRead;
02092     srcBlock.lock (ibaRead);
02093     CIndexBufferReadWrite ibaWrite;
02094     destBlock.lock (ibaWrite);
02095 
02096 
02097     nlassert(destBlock.getFormat() == CIndexBuffer::Indices16);
02098 
02099     // TMP TMP TMP
02100     if (ibaRead.getFormat() == CIndexBuffer::Indices16)
02101     {
02102         const TIndexType *triPtr = (TIndexType *) ibaRead.getPtr();
02103         const TIndexType *currTriPtr; // current Tri
02104         for (k = 0; k < nbReplicate; ++k)
02105         {
02106             currTriPtr = triPtr;
02107             for (l = 0; l < numTri; ++l)
02108             {
02109                 ibaWrite.setTri(3*index, currTriPtr[0] + currVertOffset, currTriPtr[1] + currVertOffset, currTriPtr[2] + currVertOffset);
02110                 currTriPtr += 3;
02111                 ++ index;
02112             }
02113             currVertOffset += vertOffset;
02114         }
02115     }
02116     else
02117     {
02118         const uint32 *triPtr = (uint32 *) ibaRead.getPtr();
02119         const uint32 *currTriPtr; // current Tri
02120         for (k = 0; k < nbReplicate; ++k)
02121         {
02122             currTriPtr = triPtr;
02123             for (l = 0; l < numTri; ++l)
02124             {
02125                 nlassert(currTriPtr[0] + currVertOffset <= 0xffff);
02126                 nlassert(currTriPtr[1] + currVertOffset <= 0xffff);
02127                 nlassert(currTriPtr[2] + currVertOffset <= 0xffff);
02128                 //
02129                 ibaWrite.setTri(3*index, (uint16) (currTriPtr[0] + currVertOffset), (uint16) (currTriPtr[1] + currVertOffset), (uint16) (currTriPtr[2] + currVertOffset));
02130                 currTriPtr += 3;
02131                 ++ index;
02132             }
02133             currVertOffset += vertOffset;
02134         }
02135     }
02136 
02137 
02138 
02139     // TODO quad / strips duplication : (unimplemented in primitive blocks for now)
02140 
02141     PARTICLES_CHECK_MEM;
02142 }
02143 
02144 //====================================================================================
02145 void CPSConstraintMesh::initPrerotVB()
02146 {
02147     NL_PS_FUNC(CPSConstraintMesh_initPrerotVB)
02148     // position, no normals
02149     _PreRotatedMeshVB.setVertexFormat(CVertexBuffer::PositionFlag);
02150     _PreRotatedMeshVB.setNumVertices(ConstraintMeshMaxNumPrerotatedModels * ConstraintMeshMaxNumVerts);
02151     _PreRotatedMeshVB.setName("CPSConstraintMesh::_PreRotatedMeshVB");
02152 
02153     // position & normals
02154     _PreRotatedMeshVBWithNormal.setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::NormalFlag);
02155     _PreRotatedMeshVBWithNormal.setNumVertices(ConstraintMeshMaxNumPrerotatedModels * ConstraintMeshMaxNumVerts);
02156     _PreRotatedMeshVB.setName("CPSConstraintMesh::_PreRotatedMeshVBWithNormal");
02157 }
02158 
02159 //====================================================================================
02160 CPSConstraintMesh::CMeshDisplay &CPSConstraintMesh::CMeshDisplayShare::getMeshDisplay(CMesh *mesh, const CVertexBuffer &meshVB, uint32 format)
02161 {
02162     NL_PS_FUNC(CMeshDisplayShare_getMeshDisplay)
02163     nlassert(mesh);
02164     // linear search is ok because of small size
02165     for(std::list<CMDEntry>::iterator it = _Cache.begin(); it != _Cache.end(); ++it)
02166     {
02167         if (it->Format == format && it->Mesh == mesh)
02168         {
02169             // relink at start (most recent use)
02170             _Cache.splice(_Cache.begin(), _Cache, it);
02171             return it->MD;
02172         }
02173     }
02174     if (_NumMD == _MaxNumMD)
02175     {
02176         _Cache.pop_back(); // remove least recently used mesh
02177         -- _NumMD;
02178     }
02179     //NLMISC::TTicks start = NLMISC::CTime::getPerformanceTime();
02180     _Cache.push_front(CMDEntry());
02181     _Cache.front().Mesh = mesh;
02182     _Cache.front().Format = format;
02183     buildRdrPassSet(_Cache.front().MD.RdrPasses, *mesh);
02184     _Cache.front().MD.VB.setName("CPSConstraintMesh::CMeshDisplay");
02185     buildVB(_Cache.front().MD.VB, meshVB, format);
02186     ++ _NumMD;
02187     /*NLMISC::TTicks end = NLMISC::CTime::getPerformanceTime();
02188     nlinfo("mesh setup time = %.2f", (float) (1000 * NLMISC::CTime::ticksToSecond(end - start)));   */
02189     return _Cache.front().MD;
02190 }
02191 
02192 //====================================================================================
02193 void CPSConstraintMesh::CMeshDisplayShare::buildRdrPassSet(TRdrPassSet &dest,  const CMesh &m)
02194 {
02195     NL_PS_FUNC(CMeshDisplayShare_buildRdrPassSet)
02196     // we don't support skinning for mesh particles, so there must be only one matrix block
02197     nlassert(m.getNbMatrixBlock() == 1);  // SKINNING UNSUPPORTED
02198 
02199     dest.resize(m.getNbRdrPass(0));
02200     const CVertexBuffer &srcVb = m.getVertexBuffer();
02201 
02202     for (uint k = 0; k < m.getNbRdrPass(0); ++k)
02203     {
02204         dest[k].Mat = m.getMaterial(m.getRdrPassMaterial(0, k));
02205         dest[k].SourceMat = dest[k].Mat;
02206         DuplicatePrimitiveBlock(m.getRdrPassPrimitiveBlock(0, k), dest[k].PbTri, ConstraintMeshBufSize, srcVb.getNumVertices() );
02207     }
02208 }
02209 
02210 
02211 
02212 //====================================================================================
02213 void CPSConstraintMesh::CMeshDisplayShare::buildVB(CVertexBuffer &dest, const CVertexBuffer &meshVb, uint32 destFormat)
02214 {
02215     NL_PS_FUNC(CMeshDisplayShare_buildVB)
02217     nlassert(destFormat == meshVb.getVertexFormat() || destFormat == (meshVb.getVertexFormat() | (uint32) CVertexBuffer::PrimaryColorFlag) );
02218     dest.setVertexFormat(destFormat);
02219     dest.setPreferredMemory(CVertexBuffer::AGPVolatile, true);
02220     dest.setNumVertices(ConstraintMeshBufSize * meshVb.getNumVertices());
02221     for(uint k = 0; k < CVertexBuffer::MaxStage; ++k)
02222     {
02223         dest.setUVRouting((uint8) k, meshVb.getUVRouting()[k]);
02224     }
02225 
02226     CVertexBufferReadWrite vba;
02227     dest.lock (vba);
02228     CVertexBufferRead vbaIn;
02229     meshVb.lock (vbaIn);
02230 
02231     uint8 *outPtr = (uint8 *) vba.getVertexCoordPointer();
02232     uint8 *inPtr = (uint8 *)  vbaIn.getVertexCoordPointer();
02233     uint  meshSize  = dest.getVertexSize() * meshVb.getNumVertices();
02234 
02235     if (destFormat == meshVb.getVertexFormat()) // no color added
02236     {
02237         for (uint k = 0; k < ConstraintMeshBufSize; ++k)
02238         {
02239             ::memcpy((void *) (outPtr + k * meshSize), (void *) inPtr, meshSize);
02240         }
02241     }
02242     else // color added, but not available in src
02243     {
02244         sint colorOff = dest.getColorOff();
02245         uint inVSize    = meshVb.getVertexSize();
02246         uint outVSize   = dest.getVertexSize();
02247         for (uint k = 0; k < ConstraintMeshBufSize; ++k)
02248         {
02249             for (uint v = 0; v < meshVb.getNumVertices(); ++v)
02250             {
02251                 // copy until color
02252                 ::memcpy((void *) (outPtr + k * meshSize + v * outVSize), (void *) (inPtr + v * inVSize), colorOff);
02253                 // copy datas after color
02254                 ::memcpy((void *) (outPtr + k * meshSize + v * outVSize + colorOff + sizeof(uint8[4])), (void *) (inPtr + v * inVSize + colorOff), inVSize - colorOff);
02255             }
02256         }
02257     }
02258 }
02259 
02260 
02261 //=====================================================================================
02262 CPSConstraintMesh::CGlobalTexAnim::CGlobalTexAnim() : TransOffset(NLMISC::CVector2f::Null),
02263                                                       TransSpeed(NLMISC::CVector2f::Null),
02264                                                       TransAccel(NLMISC::CVector2f::Null),
02265                                                       ScaleStart(1 ,1),
02266                                                       ScaleSpeed(NLMISC::CVector2f::Null),
02267                                                       ScaleAccel(NLMISC::CVector2f::Null),
02268                                                       WRotSpeed(0),
02269                                                       WRotAccel(0)
02270 {
02271     NL_PS_FUNC(CGlobalTexAnim_CGlobalTexAnim)
02272 }
02273 
02274 //=====================================================================================
02275 void    CPSConstraintMesh::CGlobalTexAnim::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02276 {
02277     NL_PS_FUNC(CGlobalTexAnim_IStream )
02278     // version 1 : added offset
02279     sint ver = f.serialVersion(1);
02280     if (ver >= 1)
02281     {
02282         f.serial(TransOffset);
02283     }
02284     f.serial(TransSpeed, TransAccel, ScaleStart, ScaleSpeed, ScaleAccel);
02285     f.serial(WRotSpeed, WRotAccel);
02286 }
02287 
02288 //=====================================================================================
02289 void CPSConstraintMesh::CGlobalTexAnim::buildMatrix(float date, NLMISC::CMatrix &dest)
02290 {
02291     NL_PS_FUNC(CGlobalTexAnim_buildMatrix)
02292     float fDate = (float) date;
02293     float halfDateSquared   = 0.5f * fDate * fDate;
02294     NLMISC::CVector2f pos   = fDate * TransSpeed + halfDateSquared * fDate * TransAccel + TransOffset;
02295     NLMISC::CVector2f scale = ScaleStart + fDate * ScaleSpeed + halfDateSquared * fDate * ScaleAccel;
02296     float rot = fDate * WRotSpeed + halfDateSquared * WRotAccel;
02297 
02298 
02299     float fCos, fSin;
02300     if (rot != 0.f)
02301     {
02302         fCos = ::cosf(- rot);
02303         fSin = ::sinf(- rot);
02304     }
02305     else
02306     {
02307         fCos = 1.f;
02308         fSin = 0.f;
02309     }
02310 
02311     NLMISC::CVector I(fCos, fSin, 0);
02312     NLMISC::CVector J(-fSin, fCos, 0);
02313     dest.setRot(scale.x * I, scale.y * J, NLMISC::CVector::K);
02314     NLMISC::CVector center(-0.5f, -0.5f, 0.f);
02315     NLMISC::CVector t(pos.x, pos.y, 0);
02316     dest.setPos(t + dest.mulVector(center) - center);
02317 }
02318 
02319 //=====================================================================================
02320 void    CPSConstraintMesh::setGlobalTexAnim(uint stage, const CGlobalTexAnim &properties)
02321 {
02322     NL_PS_FUNC(CPSConstraintMesh_setGlobalTexAnim)
02323     nlassert(_GlobalAnimationEnabled != 0);
02324     nlassert(stage < IDRV_MAT_MAXTEXTURES);
02325     nlassert(_GlobalTexAnims.get());
02326     _GlobalTexAnims->Anims[stage] = properties;
02327 }
02328 
02329 //=====================================================================================
02330 const CPSConstraintMesh::CGlobalTexAnim &CPSConstraintMesh::getGlobalTexAnim(uint stage) const
02331 {
02332     NL_PS_FUNC(CPSConstraintMesh_getGlobalTexAnim)
02333     nlassert(_GlobalAnimationEnabled != 0);
02334     nlassert(stage < IDRV_MAT_MAXTEXTURES);
02335     nlassert(_GlobalTexAnims.get());
02336     return _GlobalTexAnims->Anims[stage];
02337 }
02338 
02339 
02340 //=====================================================================================
02341 CPSConstraintMesh::TTexAnimType CPSConstraintMesh::getTexAnimType() const
02342 {
02343     NL_PS_FUNC(CPSConstraintMesh_getTexAnimType)
02344     return (TTexAnimType) (_GlobalAnimationEnabled != 0 ? GlobalAnim : NoAnim);
02345 }
02346 
02347 //=====================================================================================
02348 void  CPSConstraintMesh::setTexAnimType(TTexAnimType type)
02349 {
02350     NL_PS_FUNC(CPSConstraintMesh_setTexAnimType)
02351     nlassert(type < Last);
02352     if (type == getTexAnimType()) return; // does the type of animation change ?
02353     switch (type)
02354     {
02355         case NoAnim:
02356             _GlobalTexAnims.reset();
02357             restoreMaterials();
02358             _GlobalAnimationEnabled = 0;
02359         break;
02360         case GlobalAnim:
02361         {
02362             PGlobalTexAnims newPtr(new CGlobalTexAnims);
02363             //std::swap(_GlobalTexAnims, newPtr);
02364             _GlobalTexAnims = newPtr;
02365             _GlobalAnimationEnabled = 1;
02366         }
02367         break;
02368         default: break;
02369     }
02370 }
02371 
02372 //=====================================================================================
02373 void    CPSConstraintMesh::CGlobalTexAnims::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02374 {
02375     NL_PS_FUNC(CGlobalTexAnims_IStream )
02376     f.serialVersion(0);
02377     for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
02378     {
02379         f.serial(Anims[k]);
02380     }
02381 }
02382 
02383 //=====================================================================================
02384 void CPSConstraintMesh::restoreMaterials()
02385 {
02386     NL_PS_FUNC(CPSConstraintMesh_restoreMaterials)
02387     update();
02388     CMeshDisplay  &md= _MeshDisplayShare.getMeshDisplay(_Meshes[0], getMeshVB(0), _Meshes[0]->getVertexBuffer().getVertexFormat() | (_ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
02389     TRdrPassSet rdrPasses = md.RdrPasses;
02390     // render meshs : we process each rendering pass
02391     for (TRdrPassSet::iterator rdrPassIt = rdrPasses.begin(); rdrPassIt != rdrPasses.end(); ++rdrPassIt)
02392     {
02393         rdrPassIt->Mat = rdrPassIt->SourceMat;
02394     }
02395 }
02396 
02397 //=====================================================================================
02398 const CVertexBuffer &CPSConstraintMesh::getMeshVB(uint index)
02399 {
02400     nlassert(!_Touched);
02401     nlassert(index < _Meshes.size());
02402     nlassert(_MeshVertexBuffers.size() == _Meshes.size());
02403     const CVertexBuffer *vb = _MeshVertexBuffers[index];
02404     if (!vb )
02405     {
02406         CMesh &mesh = * NLMISC::safe_cast<CMesh *>((IShape *) _Meshes[index]);
02407         vb = _MeshVertexBuffers[index] = &mesh.getVertexBuffer();
02408     }
02409     if (vb->getLocation() != CVertexBuffer::NotResident)
02410     {
02411         TMeshName2RamVB::iterator it = _MeshRamVBs.find(_MeshShapeFileName[index]);
02412         if (it == _MeshRamVBs.end())
02413         {
02414             CVertexBuffer &destVb = _MeshRamVBs[_MeshShapeFileName[index]];
02415             CMesh &mesh = * NLMISC::safe_cast<CMesh *>((IShape *) _Meshes[index]);
02416             mesh.getVertexBuffer().copyVertices(destVb);
02417             _MeshVertexBuffers[index] = vb = &destVb;
02418         }
02419         else
02420         {
02421             _MeshVertexBuffers[index] = vb = &it->second;
02422         }
02423     }
02424     nlassert(vb->getLocation() == CVertexBuffer::NotResident);
02425     return *vb;
02426 }
02427 
02428 //=====================================================================================
02429 void CPSMesh::onShow(bool shown)
02430 {
02431     for(uint k = 0; k < _Instances.getSize(); ++k)
02432     {
02433         if (_Instances[k])
02434         {
02435             if (shown)
02436             {
02437                 _Instances[k]->show();
02438             }
02439             else
02440             {
02441                 _Instances[k]->hide();
02442             }
02443         }
02444     }
02445 }
02446 
02447 } // NL3D

Generated on Thu Jan 7 08:26:29 2010 for NeL by  doxygen 1.6.1