mesh.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2000 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/mesh.h"
00027 #include "nel/3d/mesh_instance.h"
00028 #include "nel/3d/scene.h"
00029 #include "nel/3d/skeleton_model.h"
00030 #include "nel/3d/mesh_morpher.h"
00031 #include "nel/misc/bsphere.h"
00032 #include "nel/3d/stripifier.h"
00033 #include "nel/misc/fast_floor.h"
00034 #include "nel/misc/hierarchical_timer.h"
00035 #include "nel/3d/mesh_blender.h"
00036 #include "nel/3d/matrix_3x4.h"
00037 #include "nel/3d/render_trav.h"
00038 #include "nel/3d/visual_collision_mesh.h"
00039 #include "nel/3d/meshvp_wind_tree.h"
00040 
00041 using namespace std;
00042 using namespace NLMISC;
00043 
00044 
00045 
00046 
00047 namespace NL3D
00048 {
00049 
00050 
00051 // ***************************************************************************
00052 // ***************************************************************************
00053 // MeshGeom Tools.
00054 // ***************************************************************************
00055 // ***************************************************************************
00056 
00057 
00058 // ***************************************************************************
00059 static  NLMISC::CAABBoxExt  makeBBox(const std::vector<CVector> &Vertices)
00060 {
00061     NLMISC::CAABBox     ret;
00062     nlassert(Vertices.size());
00063     ret.setCenter(Vertices[0]);
00064     for(sint i=0;i<(sint)Vertices.size();i++)
00065     {
00066         ret.extend(Vertices[i]);
00067     }
00068 
00069     return ret;
00070 }
00071 
00072 
00073 // ***************************************************************************
00074 sint    CMeshGeom::CCornerTmp::Flags=0;
00075 
00076 
00077 // ***************************************************************************
00078 bool    CMeshGeom::CCornerTmp::operator<(const CCornerTmp &c) const
00079 {
00080     sint    i;
00081 
00082     // Vert first.
00083     if(Vertex!=c.Vertex)
00084         return Vertex<c.Vertex;
00085 
00086     // Order: normal, uvs, color0, color1, skinning.
00087     if((CCornerTmp::Flags & CVertexBuffer::NormalFlag) && Normal!=c.Normal)
00088         return Normal<c.Normal;
00089     for(i=0; i<CVertexBuffer::MaxStage; i++)
00090     {
00091         if((CCornerTmp::Flags & (CVertexBuffer::TexCoord0Flag<<i)) && Uvws[i]!=c.Uvws[i])
00092             return Uvws[i]<c.Uvws[i];
00093     }
00094     if((CCornerTmp::Flags & CVertexBuffer::PrimaryColorFlag) && Color!=c.Color)
00095         return Color<c.Color;
00096     if((CCornerTmp::Flags & CVertexBuffer::SecondaryColorFlag) && Specular!=c.Specular)
00097         return Specular<c.Specular;
00098 
00099     if ((CCornerTmp::Flags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag)
00100     {
00101         for(i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
00102         {
00103             if(Palette.MatrixId[i] != c.Palette.MatrixId[i])
00104                 return Palette.MatrixId[i] < c.Palette.MatrixId[i];
00105             if(Weights[i] != c.Weights[i])
00106                 return Weights[i] < c.Weights[i];
00107         }
00108     }
00109 
00110 
00111     // All are equal!!
00112     return false;
00113 }
00114 
00115 
00116 // ***************************************************************************
00117 // ***************************************************************************
00118 // CMeshGeom.
00119 // ***************************************************************************
00120 // ***************************************************************************
00121 
00122 
00123 // ***************************************************************************
00124 CMeshGeom::CMeshGeom()
00125 {
00126     /* ***********************************************
00127      *  WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
00128      *  It can be loaded/called through CAsyncFileManager for instance
00129      * ***********************************************/
00130 
00131     _Skinned= false;
00132     _OriginalSkinRestored= true;
00133     _MeshMorpher = new CMeshMorpher;
00134     _BoneIdComputed = false;
00135     _BoneIdExtended= false;
00136     _PreciseClipping= false;
00137 }
00138 
00139 
00140 // ***************************************************************************
00141 CMeshGeom::~CMeshGeom()
00142 {
00143     /* ***********************************************
00144      *  WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
00145      *  It can be loaded/called through CAsyncFileManager for instance
00146      * ***********************************************/
00147 
00148     delete _MeshMorpher;
00149 }
00150 
00151 
00152 // ***************************************************************************
00153 void    CMeshGeom::optimizeTriangleOrder()
00154 {
00155     CStripifier     stripifier;
00156 
00157     // for all rdrpass of all matrix blocks.
00158     for(uint mb= 0;mb<_MatrixBlocks.size();mb++)
00159     {
00160         for(uint  rp=0; rp<_MatrixBlocks[mb].RdrPass.size(); rp++ )
00161         {
00162             // stripify list of triangles of this pass.
00163             CRdrPass    &pass= _MatrixBlocks[mb].RdrPass[rp];
00164             stripifier.optimizeTriangles(pass.PBlock, pass.PBlock);
00165         }
00166     }
00167 
00168 }
00169 
00170 
00171 // ***************************************************************************
00172 void    CMeshGeom::build (CMesh::CMeshBuild &m, uint numMaxMaterial)
00173 {
00174     sint    i;
00175 
00176     // Empty geometry?
00177     if(m.Vertices.size()==0 || m.Faces.size()==0)
00178     {
00179         _VBuffer.setNumVertices(0);
00180         _VBuffer.setName("CMeshGeom");
00181         _VBuffer.reserve(0);
00182         _MatrixBlocks.clear();
00183         _BBox.setCenter(CVector::Null);
00184         _BBox.setSize(CVector::Null);
00185         return;
00186     }
00187     nlassert(numMaxMaterial>0);
00188 
00189     // Copy the UV routing table
00190     for (i=0; i<CVertexBuffer::MaxStage; i++)
00191         _VBuffer.setUVRouting (i, m.UVRouting[i]);
00192 
00194     //======================
00195     _BBox= makeBBox(m.Vertices);
00196 
00197 
00199     //================================================
00200 
00201     // First, copy Face array.
00202     vector<CFaceTmp>    tmpFaces;
00203     tmpFaces.resize(m.Faces.size());
00204     for(i=0;i<(sint)tmpFaces.size();i++)
00205         tmpFaces[i]= m.Faces[i];
00206 
00207     _Skinned= ((m.VertexFlags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag);
00208     // Skinning is OK only if SkinWeights are of same size as vertices.
00209     _Skinned= _Skinned && (m.Vertices.size()==m.SkinWeights.size());
00210 
00211     // If skinning is KO, remove the Skin option.
00212     uint    vbFlags= m.VertexFlags;
00213     if(!_Skinned)
00214         vbFlags&= ~CVertexBuffer::PaletteSkinFlag;
00215     // Force presence of vertex.
00216     vbFlags|= CVertexBuffer::PositionFlag;
00217 
00218 
00219     // If the mesh is not skinned, we have just 1 _MatrixBlocks.
00220     if(!_Skinned)
00221     {
00222         _MatrixBlocks.resize(1);
00223         // For each faces, assign it to the matrix block 0.
00224         for(i=0;i<(sint)tmpFaces.size();i++)
00225             tmpFaces[i].MatrixBlockId= 0;
00226     }
00227     // Else We must group/compute the matrixs blocks.
00228     else
00229     {
00230         // reset matrix blocks.
00231         _MatrixBlocks.clear();
00232         // build matrix blocks, and link faces to good matrix blocks.
00233         buildSkin(m, tmpFaces);
00234     }
00235 
00237     //================================================
00238     // Setup VB.
00239     _VBuffer.setNumVertices(0);
00240     _VBuffer.reserve(0);
00241 
00242     bool useFormatExt = false;
00246     for (uint k = 0; k < CVertexBuffer::MaxStage; ++k)
00247     {
00248         if (
00249             (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
00250             && m.NumCoords[k] != 2)
00251         {
00252             useFormatExt = true;
00253             break;
00254         }
00255     }
00256 
00257     if (!useFormatExt)
00258     {
00259         // setup standard format
00260         _VBuffer.setVertexFormat(vbFlags);
00261     }
00262     else // setup extended format
00263     {
00264         _VBuffer.clearValueEx();
00265         if (vbFlags & CVertexBuffer::PositionFlag) _VBuffer.addValueEx(CVertexBuffer::Position, CVertexBuffer::Float3);
00266         if (vbFlags & CVertexBuffer::NormalFlag) _VBuffer.addValueEx(CVertexBuffer::Normal, CVertexBuffer::Float3);
00267         if (vbFlags & CVertexBuffer::PrimaryColorFlag) _VBuffer.addValueEx(CVertexBuffer::PrimaryColor, CVertexBuffer::UChar4);
00268         if (vbFlags & CVertexBuffer::SecondaryColorFlag) _VBuffer.addValueEx(CVertexBuffer::SecondaryColor, CVertexBuffer::UChar4);
00269         if (vbFlags & CVertexBuffer::WeightFlag) _VBuffer.addValueEx(CVertexBuffer::Weight, CVertexBuffer::Float4);
00270         if (vbFlags & CVertexBuffer::PaletteSkinFlag) _VBuffer.addValueEx(CVertexBuffer::PaletteSkin, CVertexBuffer::UChar4);
00271         if (vbFlags & CVertexBuffer::FogFlag) _VBuffer.addValueEx(CVertexBuffer::Fog, CVertexBuffer::Float1);
00272 
00273         for (uint k = 0; k < CVertexBuffer::MaxStage; ++k)
00274         {
00275             if (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
00276             {
00277                 switch(m.NumCoords[k])
00278                 {
00279                     case 2:
00280                         _VBuffer.addValueEx((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), CVertexBuffer::Float2);
00281                     break;
00282                     case 3:
00283                         _VBuffer.addValueEx((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), CVertexBuffer::Float3);
00284                     break;
00285                     default:
00286                         nlassert(0);
00287                     break;
00288                 }
00289             }
00290         }
00291         _VBuffer.initEx();
00292     }
00293 
00294     // Set local flags for corner comparison.
00295     CCornerTmp::Flags= vbFlags;
00296     // Setup locals.
00297     TCornerSet  corners;
00298     const CFaceTmp      *pFace= &(*tmpFaces.begin());
00299     uint32      nFaceMB = 0;
00300     sint        N= tmpFaces.size();
00301     sint        currentVBIndex=0;
00302 
00303     m.VertLink.clear ();
00304 
00305     // process each face, building up the VB.
00306     for(;N>0;N--, pFace++)
00307     {
00308         sint    v0= pFace->Corner[0].Vertex;
00309         sint    v1= pFace->Corner[1].Vertex;
00310         sint    v2= pFace->Corner[2].Vertex;
00311         findVBId(corners, &pFace->Corner[0], currentVBIndex, m.Vertices[v0], m);
00312         findVBId(corners, &pFace->Corner[1], currentVBIndex, m.Vertices[v1], m);
00313         findVBId(corners, &pFace->Corner[2], currentVBIndex, m.Vertices[v2], m);
00314         CMesh::CVertLink vl1(nFaceMB, 0, pFace->Corner[0].VBId);
00315         CMesh::CVertLink vl2(nFaceMB, 1, pFace->Corner[1].VBId);
00316         CMesh::CVertLink vl3(nFaceMB, 2, pFace->Corner[2].VBId);
00317         m.VertLink.push_back(vl1);
00318         m.VertLink.push_back(vl2);
00319         m.VertLink.push_back(vl3);
00320         ++nFaceMB;
00321     }
00322 
00323 
00325     //================================
00326     uint    mb;
00327 
00328     // For each _MatrixBlocks, point on those materials.
00329     for(mb= 0;mb<_MatrixBlocks.size();mb++)
00330     {
00331         // Build RdrPass ids.
00332         _MatrixBlocks[mb].RdrPass.resize (numMaxMaterial);
00333 
00334         for(i=0;i<(sint)_MatrixBlocks[mb].RdrPass.size(); i++)
00335         {
00336             _MatrixBlocks[mb].RdrPass[i].MaterialId= i;
00337             // for build, force 32 bit indices
00338             _MatrixBlocks[mb].RdrPass[i].PBlock.setFormat(CIndexBuffer::Indices32);
00339         }
00340     }
00341 
00342 
00344     //===================================================
00345     pFace= &(*tmpFaces.begin());
00346     N= tmpFaces.size();
00347     for(;N>0;N--, pFace++)
00348     {
00349         sint    mbId= pFace->MatrixBlockId;
00350         nlassert(mbId>=0 && mbId<(sint)_MatrixBlocks.size());
00351         // Insert the face in good MatrixBlock/RdrPass.
00352         CIndexBuffer &ib = _MatrixBlocks[mbId].RdrPass[pFace->MaterialId].PBlock;
00353         uint index = ib.getNumIndexes();
00354         ib.setNumIndexes (index+3);
00355         CIndexBufferReadWrite iba;
00356         ib.lock (iba);
00357         iba.setTri(index, pFace->Corner[0].VBId, pFace->Corner[1].VBId, pFace->Corner[2].VBId);
00358     }
00359 
00360 
00362     //============================
00363     for(mb= 0;mb<_MatrixBlocks.size();mb++)
00364     {
00365         // NB: slow process (erase from a vector). Doens't matter since made at build.
00366         vector<CRdrPass>::iterator  itPass;
00367         for( itPass=_MatrixBlocks[mb].RdrPass.begin(); itPass!=_MatrixBlocks[mb].RdrPass.end(); )
00368         {
00369             // If this pass is empty, remove it.
00370             if( itPass->PBlock.getNumIndexes()==0 )
00371                 itPass= _MatrixBlocks[mb].RdrPass.erase(itPass);
00372             else
00373                 itPass++;
00374         }
00375     }
00376 
00378     //============================
00379     // BShapes
00380     this->_MeshMorpher->BlendShapes = m.BlendShapes;
00381 
00382     // sort triangles for better cache use.
00383     optimizeTriangleOrder();
00384 
00385     // SmartPtr Copy VertexProgram effect.
00386     this->_MeshVertexProgram= m.MeshVertexProgram;
00387 
00389     //=================================================
00390 
00391     // If skinned
00392     if(_Skinned)
00393     {
00394         // Reserve some space
00395         _BonesName.reserve (m.BonesNames.size ());
00396 
00397         // Current local bone
00398         uint currentBone = 0;
00399 
00400         // For each matrix block
00401         uint matrixBlock;
00402         for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
00403         {
00404             // Ref on the matrix block
00405             CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
00406 
00407             // Remap the skeleton index in model index
00408             std::map<uint, uint> remap;
00409 
00410             // For each matrix
00411             uint matrix;
00412             for (matrix=0; matrix<mb.NumMatrix; matrix++)
00413             {
00414                 // Get bone id in the skeleton
00415                 std::map<uint, uint>::iterator ite = remap.find (mb.MatrixId[matrix]);
00416 
00417                 // Not found
00418                 if (ite == remap.end())
00419                 {
00420                     // Insert it
00421                     remap.insert (std::map<uint, uint>::value_type (mb.MatrixId[matrix], currentBone));
00422 
00423                     // Check the matrix id
00424                     nlassert (mb.MatrixId[matrix] < m.BonesNames.size());
00425 
00426                     // Set the bone name
00427                     _BonesName.push_back (m.BonesNames[mb.MatrixId[matrix]]);
00428 
00429                     // Set the id in local
00430                     mb.MatrixId[matrix] = currentBone++;
00431                 }
00432                 else
00433                 {
00434                     // Set the id in local
00435                     mb.MatrixId[matrix] = ite->second;
00436                 }
00437             }
00438         }
00439 
00440         // Bone id in local
00441         _BoneIdComputed = false;
00442         _BoneIdExtended = false;
00443     }
00444 
00445     // Set the vertex buffer preferred memory
00446     bool avoidVBHard= _Skinned || ( _MeshMorpher && _MeshMorpher->BlendShapes.size()>0 );
00447     _VBuffer.setPreferredMemory (avoidVBHard?CVertexBuffer::RAMPreferred:CVertexBuffer::StaticPreferred, false);
00448 
00449     // End!!
00450     // Some runtime not serialized compilation
00451     compileRunTime();
00452 }
00453 
00454 // ***************************************************************************
00455 void CMeshGeom::setBlendShapes(std::vector<CBlendShape>&bs)
00456 {
00457     _MeshMorpher->BlendShapes = bs;
00458     // must update some RunTime parameters
00459     compileRunTime();
00460 }
00461 
00462 
00463 // ***************************************************************************
00464 void    CMeshGeom::applyMaterialRemap(const std::vector<sint> &remap)
00465 {
00466     for(uint mb=0;mb<getNbMatrixBlock();mb++)
00467     {
00468         for(uint rp=0;rp<getNbRdrPass(mb);rp++)
00469         {
00470             // remap
00471             uint32  &matId= _MatrixBlocks[mb].RdrPass[rp].MaterialId;
00472             nlassert(remap[matId]>=0);
00473             matId= remap[matId];
00474         }
00475     }
00476 }
00477 
00478 
00479 // ***************************************************************************
00480 void    CMeshGeom::initInstance(CMeshBaseInstance *mbi)
00481 {
00482     // init the instance with _MeshVertexProgram infos
00483     if(_MeshVertexProgram)
00484         _MeshVertexProgram->initInstance(mbi);
00485 }
00486 
00487 // ***************************************************************************
00488 bool    CMeshGeom::clip(const std::vector<CPlane>   &pyramid, const CMatrix &worldMatrix)
00489 {
00490     // Speed Clip: clip just the sphere.
00491     CBSphere    localSphere(_BBox.getCenter(), _BBox.getRadius());
00492     CBSphere    worldSphere;
00493 
00494     // transform the sphere in WorldMatrix (with nearly good scale info).
00495     localSphere.applyTransform(worldMatrix, worldSphere);
00496 
00497     // if out of only plane, entirely out.
00498     for(sint i=0;i<(sint)pyramid.size();i++)
00499     {
00500         // We are sure that pyramid has normalized plane normals.
00501         // if SpherMax OUT return false.
00502         float   d= pyramid[i]*worldSphere.Center;
00503         if(d>worldSphere.Radius)
00504             return false;
00505     }
00506 
00507     // test if must do a precise clip, according to mesh size.
00508     if( _PreciseClipping )
00509     {
00510         CPlane  localPlane;
00511 
00512         // if out of only plane, entirely out.
00513         for(sint i=0;i<(sint)pyramid.size();i++)
00514         {
00515             // Transform the pyramid in Object space.
00516             localPlane= pyramid[i]*worldMatrix;
00517             // localPlane must be normalized, because worldMatrix mya have a scale.
00518             localPlane.normalize();
00519             // if the box is not partially inside the plane, quit
00520             if( !_BBox.clipBack(localPlane) )
00521                 return false;
00522         }
00523     }
00524 
00525     return true;
00526 }
00527 
00528 // ***************************************************************************
00529 void    CMeshGeom::render(IDriver *drv, CTransformShape *trans, float polygonCount, uint32 rdrFlags, float globalAlpha)
00530 {
00531     nlassert(drv);
00532     // get the mesh instance.
00533     CMeshBaseInstance   *mi= safe_cast<CMeshBaseInstance*>(trans);
00534     // get a ptr on scene
00535     CScene          *ownerScene= mi->getOwnerScene();
00536     // get a ptr on renderTrav
00537     CRenderTrav     *renderTrav= &ownerScene->getRenderTrav();
00538 
00539     // Soft vb if not supported by the driver
00540     if (drv->slowUnlockVertexBufferHard())
00541         _VBuffer.setPreferredMemory (CVertexBuffer::RAMPreferred, false);
00542 
00543     // get the skeleton model to which I am binded (else NULL).
00544     CSkeletonModel      *skeleton;
00545     skeleton= mi->getSkeletonModel();
00546     // The mesh must not be skinned for render()
00547     nlassert(!(_Skinned && mi->isSkinned() && skeleton));
00548     bool bMorphApplied = _MeshMorpher->BlendShapes.size() > 0;
00549     bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
00550 
00551 
00552     // Profiling
00553     //===========
00554     H_AUTO( NL3D_MeshGeom_RenderNormal );
00555 
00556 
00557     // Morphing
00558     // ========
00559     if (bMorphApplied)
00560     {
00561         // If _Skinned (NB: the skin is not applied) and if lod.OriginalSkinRestored, then restoreOriginalSkinPart is
00562         // not called but mush morpher write changed vertices into VBHard so its ok. The unchanged vertices
00563         // are written in the preceding call to restoreOriginalSkinPart.
00564         if (_Skinned)
00565         {
00566             _MeshMorpher->initSkinned(&_VBufferOri,
00567                                  &_VBuffer,
00568                                  useTangentSpace,
00569                                  &_OriginalSkinVertices,
00570                                  &_OriginalSkinNormals,
00571                                  useTangentSpace ? &_OriginalTGSpace : NULL,
00572                                  false );
00573             _MeshMorpher->updateSkinned (mi->getBlendShapeFactors());
00574         }
00575         else // Not even skinned so we have to do all the stuff
00576         {
00577             _MeshMorpher->init(&_VBufferOri,
00578                                  &_VBuffer,
00579                                  useTangentSpace);
00580             _MeshMorpher->update (mi->getBlendShapeFactors());
00581         }
00582     }
00583 
00584 
00585     // Skinning
00586     // ========
00587 
00588     // else setup instance matrix
00589     drv->setupModelMatrix(trans->getWorldMatrix());
00590 
00591 
00592     // since instance skin is invalid but mesh is skinned , we must copy vertices/normals from original vertices.
00593     if (_Skinned)
00594     {
00595         // do it for this Lod only, and if cache say it is necessary.
00596         if (!_OriginalSkinRestored)
00597             restoreOriginalSkinVertices();
00598     }
00599 
00600 
00601     // Setup meshVertexProgram
00602     //===========
00603 
00604     // use MeshVertexProgram effect?
00605     bool    useMeshVP= _MeshVertexProgram != NULL;
00606     if( useMeshVP )
00607     {
00608         CMatrix     invertedObjectMatrix;
00609         invertedObjectMatrix = trans->getWorldMatrix().inverted();
00610         // really ok if success to begin VP
00611         useMeshVP= _MeshVertexProgram->begin(drv, ownerScene, mi, invertedObjectMatrix, renderTrav->CamPos);
00612         if (!useMeshVP && !mi->_VPWindTreeFixed)
00613         {
00614             if (dynamic_cast<CMeshVPWindTree *>(&(*_MeshVertexProgram)))
00615             {
00616                 // fix for mesh tree v.p : all material should be lighted
00617                 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
00618                 {
00619                     CMatrixBlock    &mBlock= _MatrixBlocks[mb];
00620                     for(uint i=0;i<mBlock.RdrPass.size();i++)
00621                     {
00622                         CMaterial &mat=mi->Materials[mBlock.RdrPass[i].MaterialId];
00623                         mat.setLighting(true, mat.getEmissive(), mat.getAmbient(), mat.getDiffuse(), mat.getSpecular());
00624                     }
00625                 }
00626             }
00627             mi->_VPWindTreeFixed = true;
00628         }
00629     }
00630 
00631 
00632 
00633     // Render the mesh.
00634     //===========
00635     // active VB.
00636     drv->activeVertexBuffer(_VBuffer);
00637 
00638 
00639     // Global alpha used ?
00640     uint32  globalAlphaUsed= rdrFlags & IMeshGeom::RenderGlobalAlpha;
00641     uint8   globalAlphaInt=(uint8)NLMISC::OptFastFloor(globalAlpha*255);
00642 
00643 
00644     // For all _MatrixBlocks
00645     for(uint mb=0;mb<_MatrixBlocks.size();mb++)
00646     {
00647         CMatrixBlock    &mBlock= _MatrixBlocks[mb];
00648         if(mBlock.RdrPass.size()==0)
00649             continue;
00650 
00651         // Global alpha ?
00652         if (globalAlphaUsed)
00653         {
00654             bool    gaDisableZWrite= (rdrFlags & IMeshGeom::RenderGADisableZWrite)?true:false;
00655 
00656             // Render all pass.
00657             for (uint i=0;i<mBlock.RdrPass.size();i++)
00658             {
00659                 CRdrPass    &rdrPass= mBlock.RdrPass[i];
00660                 // Render with the Materials of the MeshInstance.
00661                 if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
00662                      ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
00663                 {
00664                     // CMaterial Ref
00665                     CMaterial &material=mi->Materials[rdrPass.MaterialId];
00666 
00667                     // Use a MeshBlender to modify material and driver.
00668                     CMeshBlender    blender;
00669                     blender.prepareRenderForGlobalAlpha(material, drv, globalAlpha, globalAlphaInt, gaDisableZWrite);
00670 
00671                     // Setup VP material
00672                     if (useMeshVP)
00673                     {
00674                         _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
00675                     }
00676 
00677                     // Render
00678                     drv->activeIndexBuffer(rdrPass.PBlock);
00679                     drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
00680 
00681                     // Resetup material/driver
00682                     blender.restoreRender(material, drv, gaDisableZWrite);
00683                 }
00684             }
00685         }
00686         else
00687         {
00688             // Render all pass.
00689             for(uint i=0;i<mBlock.RdrPass.size();i++)
00690             {
00691                 CRdrPass    &rdrPass= mBlock.RdrPass[i];
00692                 // Render with the Materials of the MeshInstance.
00693                 if( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
00694                     ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) )     )
00695                 {
00696                     // CMaterial Ref
00697                     CMaterial &material=mi->Materials[rdrPass.MaterialId];
00698 
00699                     // Setup VP material
00700                     if (useMeshVP)
00701                     {
00702                         _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
00703                     }
00704 
00705                     // render primitives
00706                     drv->activeIndexBuffer(rdrPass.PBlock);
00707                     drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
00708                 }
00709             }
00710         }
00711     }
00712 
00713     // End VertexProgram effect
00714     if(useMeshVP)
00715     {
00716         // Apply it.
00717         _MeshVertexProgram->end(drv);
00718     }
00719 }
00720 
00721 
00722 // ***************************************************************************
00723 void    CMeshGeom::renderSkin(CTransformShape *trans, float alphaMRM)
00724 {
00725     // get the mesh instance.
00726     CMeshBaseInstance   *mi= safe_cast<CMeshBaseInstance*>(trans);
00727     // get a ptr on scene
00728     CScene          *ownerScene= mi->getOwnerScene();
00729     // get a ptr on renderTrav
00730     CRenderTrav     *renderTrav= &ownerScene->getRenderTrav();
00731     // get a ptr on the driver
00732     IDriver         *drv= renderTrav->getDriver();
00733     nlassert(drv);
00734 
00735     // get the skeleton model to which I am binded (else NULL).
00736     CSkeletonModel      *skeleton;
00737     skeleton= mi->getSkeletonModel();
00738     // must be skinned for renderSkin()
00739     nlassert(_Skinned && mi->isSkinned() && skeleton);
00740     bool bMorphApplied = _MeshMorpher->BlendShapes.size() > 0;
00741     bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
00742 
00743 
00744     // Profiling
00745     //===========
00746     H_AUTO( NL3D_MeshGeom_RenderSkinned );
00747 
00748 
00749     // Morphing
00750     // ========
00751     if (bMorphApplied)
00752     {
00753         // Since Skinned we must update original skin vertices and normals because skinning use it
00754         _MeshMorpher->initSkinned(&_VBufferOri,
00755                              &_VBuffer,
00756                              useTangentSpace,
00757                              &_OriginalSkinVertices,
00758                              &_OriginalSkinNormals,
00759                              useTangentSpace ? &_OriginalTGSpace : NULL,
00760                              true );
00761         _MeshMorpher->updateSkinned (mi->getBlendShapeFactors());
00762     }
00763 
00764 
00765     // Skinning
00766     // ========
00767 
00768     // NB: the skeleton matrix has already been setuped by CSkeletonModel
00769     // NB: the normalize flag has already been setuped by CSkeletonModel
00770 
00771 
00772     // apply the skinning: _VBuffer is modified.
00773     applySkin(skeleton);
00774 
00775 
00776     // Setup meshVertexProgram
00777     //===========
00778 
00779     // use MeshVertexProgram effect?
00780     bool    useMeshVP= _MeshVertexProgram != NULL;
00781     if( useMeshVP )
00782     {
00783         CMatrix     invertedObjectMatrix;
00784         invertedObjectMatrix = skeleton->getWorldMatrix().inverted();
00785         // really ok if success to begin VP
00786         useMeshVP= _MeshVertexProgram->begin(drv, ownerScene, mi, invertedObjectMatrix, renderTrav->CamPos);
00787     }
00788 
00789 
00790     // Render the mesh.
00791     //===========
00792     // active VB.
00793     drv->activeVertexBuffer(_VBuffer);
00794 
00795 
00796     // For all _MatrixBlocks
00797     for(uint mb=0;mb<_MatrixBlocks.size();mb++)
00798     {
00799         CMatrixBlock    &mBlock= _MatrixBlocks[mb];
00800         if(mBlock.RdrPass.size()==0)
00801             continue;
00802 
00803         // Render all pass.
00804         for(uint i=0;i<mBlock.RdrPass.size();i++)
00805         {
00806             CRdrPass    &rdrPass= mBlock.RdrPass[i];
00807 
00808             // CMaterial Ref
00809             CMaterial &material=mi->Materials[rdrPass.MaterialId];
00810 
00811             // Setup VP material
00812             if (useMeshVP)
00813             {
00814                 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
00815             }
00816 
00817             // render primitives
00818             drv->activeIndexBuffer(rdrPass.PBlock);
00819             drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
00820         }
00821     }
00822 
00823     // End VertexProgram effect
00824     if(useMeshVP)
00825     {
00826         // Apply it.
00827         _MeshVertexProgram->end(drv);
00828     }
00829 
00830 }
00831 
00832 
00833 // ***************************************************************************
00834 void    CMeshGeom::renderSimpleWithMaterial(IDriver *drv, const CMatrix &worldMatrix, CMaterial &mat)
00835 {
00836     H_AUTO( NL3D_MeshGeom_RenderSimpleWithMaterial );
00837 
00838     nlassert(drv);
00839 
00840     // setup matrix
00841     drv->setupModelMatrix(worldMatrix);
00842 
00843     // Active simple VB.
00844     drv->activeVertexBuffer(_VBuffer);
00845 
00846     // For all _MatrixBlocks
00847     for(uint mb=0;mb<_MatrixBlocks.size();mb++)
00848     {
00849         CMatrixBlock    &mBlock= _MatrixBlocks[mb];
00850         if(mBlock.RdrPass.size()==0)
00851             continue;
00852 
00853         // Render all pass.
00854         for(uint i=0;i<mBlock.RdrPass.size();i++)
00855         {
00856             CRdrPass    &rdrPass= mBlock.RdrPass[i];
00857 
00858             // render primitives
00859             drv->activeIndexBuffer(rdrPass.PBlock);
00860             drv->renderTriangles(mat, 0, rdrPass.PBlock.getNumIndexes()/3);
00861         }
00862     }
00863 
00864 }
00865 
00866 
00867 // ***************************************************************************
00868 void    CMeshGeom::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00869 {
00870     /* ***********************************************
00871      *  WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
00872      *  It can be loaded/called through CAsyncFileManager for instance
00873      * ***********************************************/
00874 
00875     /*
00876     Version 5:
00877         - Preferred memory.
00878     Version 4:
00879         - BonesName.
00880     Version 3:
00881         - MeshVertexProgram.
00882     Version 2:
00883         - precompute of triangle order. (nothing more to load).
00884     Version 1:
00885         - added blend shapes
00886     Version 0:
00887         - separate serialisation CMesh / CMeshGeom.
00888     */
00889     sint ver = f.serialVersion (4);
00890 
00891 
00892     // must have good original Skinned Vertex before writing.
00893     if( !f.isReading() && _Skinned && !_OriginalSkinRestored )
00894     {
00895         restoreOriginalSkinVertices();
00896     }
00897 
00898 
00899     // Version 4+: Array of bone name
00900     if (ver >= 4)
00901     {
00902         f.serialCont (_BonesName);
00903     }
00904 
00905     if (f.isReading())
00906     {
00907         // Version3-: Bones index are in skeleton model id list
00908         _BoneIdComputed = (ver < 4);
00909         // In all case, must recompute usage of parents.
00910         _BoneIdExtended= false;
00911     }
00912     else
00913     {
00914         // Warning, if you have skinned this shape, you can't write it anymore because skinning id have been changed!
00915         nlassert (_BoneIdComputed==false);
00916     }
00917 
00918     // Version3+: MeshVertexProgram.
00919     if (ver >= 3)
00920     {
00921         IMeshVertexProgram  *mvp= NULL;
00922         if(f.isReading())
00923         {
00924             f.serialPolyPtr(mvp);
00925             _MeshVertexProgram= mvp;
00926         }
00927         else
00928         {
00929             mvp= _MeshVertexProgram;
00930             f.serialPolyPtr(mvp);
00931         }
00932     }
00933     else if(f.isReading())
00934     {
00935         // release vp
00936         _MeshVertexProgram= NULL;
00937     }
00938 
00939     // TestYoyo
00940     //_MeshVertexProgram= NULL;
00941 
00942     // Version1+: _MeshMorpher.
00943     if (ver >= 1)
00944         f.serial (*_MeshMorpher);
00945 
00946     // serial geometry.
00947     f.serial (_VBuffer);
00948 
00949     f.serialCont (_MatrixBlocks);
00950     f.serial (_BBox);
00951     f.serial (_Skinned);
00952 
00953 
00954     // If _VertexBuffer changed, flag the VertexBufferHard.
00955     if(f.isReading())
00956     {
00957         // if >= version 2, reorder of triangles is precomputed, else compute it now.
00958         if(ver < 2 )
00959         {
00960             optimizeTriangleOrder();
00961         }
00962     }
00963 
00964     // Skinning: If Version < 4, _BonesName are not present, must compute _BonesId from localId
00965     // Else it is computed at first computeBonesId().
00966     if(ver < 4)
00967         buildBoneUsageVer3();
00968 
00969     // TestYoyo
00970     //_MeshVertexProgram= NULL;
00971     /*{
00972         uint numTris= 0;
00973         for(uint i=0;i<_MatrixBlocks.size();i++)
00974         {
00975             for(uint j=0;j<_MatrixBlocks[i].RdrPass.size();j++)
00976                 numTris+= _MatrixBlocks[i].RdrPass[j].PBlock.getNumTri();
00977         }
00978         nlinfo("YOYO: %d Vertices. %d Triangles.", _VBuffer.getNumVertices(), numTris);
00979     }*/
00980 
00981     // Some runtime not serialized compilation
00982     if(f.isReading())
00983         compileRunTime();
00984 }
00985 
00986 
00987 // ***************************************************************************
00988 void    CMeshGeom::compileRunTime()
00989 {
00990     /* ***********************************************
00991      *  WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
00992      *  It can be loaded/called through CAsyncFileManager for instance
00993      * ***********************************************/
00994 
00995     // if skinned, prepare skinning
00996     if(_Skinned)
00997     {
00998         // bkup vertices
00999         bkupOriginalSkinVertices();
01000         // build the shadow skin
01001         buildShadowSkin();
01002     }
01003 
01004     // Do precise clipping for big object??
01005     _PreciseClipping= _BBox.getRadius() >= NL3D_MESH_PRECISE_CLIP_THRESHOLD;
01006 
01007     // Support MeshBlockRendering only if not skinned/meshMorphed.
01008     bool    supportMeshBlockRendering= !_Skinned && _MeshMorpher->BlendShapes.size()==0;
01009 
01010     // true only if one matrix block, and at least one rdrPass.
01011     supportMeshBlockRendering= supportMeshBlockRendering && _MatrixBlocks.size()==1 && _MatrixBlocks[0].RdrPass.size()>0;
01012     if (supportMeshBlockRendering && _MeshVertexProgram)
01013     {
01014         supportMeshBlockRendering = supportMeshBlockRendering && _MeshVertexProgram->supportMeshBlockRendering();
01015     }
01016 
01017     // TestYoyo
01018     //supportMeshBlockRendering= false;
01019 
01020     // support MeshVertexProgram, but no material sorting...
01021     bool    supportMBRPerMaterial= supportMeshBlockRendering && _MeshVertexProgram==NULL;
01022 
01023 
01024     // setup flags
01025     _SupportMBRFlags= 0;
01026     if(supportMeshBlockRendering)
01027         _SupportMBRFlags|= MBROk;
01028     if(supportMBRPerMaterial)
01029         _SupportMBRFlags|= MBRSortPerMaterial;
01030 
01031     bool avoidVBHard= _Skinned || ( _MeshMorpher && _MeshMorpher->BlendShapes.size()>0 );
01032     _VBuffer.setPreferredMemory (avoidVBHard?CVertexBuffer::RAMPreferred:CVertexBuffer::StaticPreferred, false);
01033 }
01034 
01035 // ***************************************************************************
01036 bool    CMeshGeom::retrieveVertices(std::vector<NLMISC::CVector> &vertices) const
01037 {
01038     /* ***********************************************
01039      *  WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
01040      *  It can be loaded/called through CAsyncFileManager for instance
01041      * ***********************************************/
01042 
01043     uint    i;
01044 
01045     // if resident, fails!!! cannot read!
01046     const CVertexBuffer &vb= getVertexBuffer();
01047     if(vb.isResident())
01048         return false;
01049 
01050     vertices.clear();
01051     vertices.resize(vb.getNumVertices());
01052     {
01053         CVertexBufferRead vba;
01054         vb.lock (vba);
01055         const uint8 *pVert= (const uint8*)vba.getVertexCoordPointer(0);
01056         uint        vSize= vb.getVertexSize();
01057         for(i=0;i<vertices.size();i++)
01058         {
01059             vertices[i]= *(const CVector*)pVert;
01060             pVert+= vSize;
01061         }
01062     }
01063 
01064     return true;
01065 }
01066 
01067 // ***************************************************************************
01068 bool    CMeshGeom::retrieveTriangles(std::vector<uint32> &indices) const
01069 {
01070     /* ***********************************************
01071      *  WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
01072      *  It can be loaded/called through CAsyncFileManager for instance
01073      * ***********************************************/
01074 
01075     uint    i;
01076 
01077     indices.clear();
01078 
01079     // count numTris
01080     uint    numTris= 0;
01081     for(i=0;i<getNbMatrixBlock();i++)
01082     {
01083         for(uint rp=0;rp<getNbRdrPass(i);rp++)
01084         {
01085             // if resident, fails!!! cannot read!
01086             const CIndexBuffer  &pb= getRdrPassPrimitiveBlock(i, rp);
01087             if(pb.isResident())
01088                 return false;
01089             numTris+= getRdrPassPrimitiveBlock(i, rp).getNumIndexes()/3;
01090         }
01091     }
01092     indices.resize(numTris*3);
01093 
01094     // build indices
01095     uint    triIdx= 0;
01096     for(i=0;i<getNbMatrixBlock();i++)
01097     {
01098         for(uint rp=0;rp<getNbRdrPass(i);rp++)
01099         {
01100             const CIndexBuffer  &pb= getRdrPassPrimitiveBlock(i, rp);
01101             CIndexBufferRead iba;
01102             pb.lock (iba);
01103             // copy
01104             if (pb.getFormat() == CIndexBuffer::Indices32)
01105             {
01106                 memcpy(&indices[triIdx*3], iba.getPtr(), pb.getNumIndexes()*sizeof(uint32));
01107             }
01108             else
01109             {
01110                 // std::copy will convert from 16 bits index to 32 bit index
01111                 std::copy((uint16 *) iba.getPtr(), ((uint16 *) iba.getPtr()) +  pb.getNumIndexes(), &indices[triIdx*3]);
01112             }
01113             // next
01114             triIdx+= pb.getNumIndexes()/3;
01115         }
01116     }
01117 
01118     return true;
01119 }
01120 
01121 
01122 // ***************************************************************************
01123 // ***************************************************************************
01124 // Skinning.
01125 // ***************************************************************************
01126 // ***************************************************************************
01127 
01128 
01129 // ***************************************************************************
01130 void    CMeshGeom::buildSkin(CMesh::CMeshBuild &m, std::vector<CFaceTmp>    &tmpFaces)
01131 {
01132     sint    i,j,k;
01133     TBoneMap        remainingBones;
01134     list<uint>      remainingFaces;
01135 
01136 
01137     // 0. normalize SkinWeights: for all weights at 0, copy the matrixId from 0th matrix => no random/bad use of matrix.
01138     //================================
01139     for(i=0;i<(sint)m.SkinWeights.size();i++)
01140     {
01141         CMesh::CSkinWeight  &sw= m.SkinWeights[i];
01142 
01143         // 0th weight must not be 0.
01144         nlassert(sw.Weights[0]!=0);
01145 
01146         // Begin at 1, tests all other weights.
01147         for(j=1;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
01148         {
01149             // We don't use this entry??
01150             if(sw.Weights[j]==0)
01151             {
01152                 // Setup MatrixId so that this vertex do no use more matrix than it really wants.
01153                 sw.MatrixId[j]= sw.MatrixId[0];
01154             }
01155         }
01156     }
01157 
01158 
01159     // 1. build the list of used/remaining bones, in ascending order. (so we use the depth-first topolgy of hierarchy).
01160     //================================
01161     for(i=0;i<(sint)tmpFaces.size();i++)
01162     {
01163         CFaceTmp    &face= tmpFaces[i];
01164 
01165         for(j=0;j<3;j++)
01166         {
01167             CMesh::CSkinWeight  &sw= m.SkinWeights[face.Corner[j].Vertex];
01168             for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
01169             {
01170                 // insert (if not already here) the used bone in the set.
01171                 // and insert his refcount. (NB: ctor() init it to 0 :) ).
01172                 remainingBones[sw.MatrixId[k]].RefCount++;
01173             }
01174         }
01175     }
01176 
01177 
01178     // 2. Create the list of un-inserted faces.
01179     //================================
01180     for(i=0;i<(sint)tmpFaces.size();i++)
01181     {
01182         remainingFaces.push_back(i);
01183     }
01184 
01185 
01186 
01187     // 3. Create as many Blocks as necessary.
01188     //================================
01189     // Which bones a face use (up to 12).
01190     vector<uint>    boneUse;
01191     boneUse.reserve(NL3D_MESH_SKINNING_MAX_MATRIX*3);
01192 
01193     // While still exist faces.
01194     while(!remainingFaces.empty())
01195     {
01196         // create a new matrix block.
01197         _MatrixBlocks.push_back(CMatrixBlock());
01198         CMatrixBlock    &matrixBlock= _MatrixBlocks[_MatrixBlocks.size()-1];
01199         matrixBlock.NumMatrix=0;
01200 
01201         // a. reset remainingBones as not inserted in the current matrixBlock.
01202         //============================
01203         ItBoneMap   itBone;
01204         for(itBone= remainingBones.begin();itBone!=remainingBones.end();itBone++)
01205         {
01206             itBone->second.Inserted= false;
01207         }
01208 
01209 
01210         // b. while still exist bones, try to insert faces which use them in matrixBlock.
01211         //============================
01212         while(!remainingBones.empty())
01213         {
01214             // get the first bone from the map. (remind: depth-first order).
01215             uint        currentBoneId= remainingBones.begin()->first;
01216 
01217             // If no more faces in the remainingFace list use this bone, remove it, and continue.
01218             if(remainingBones.begin()->second.RefCount==0)
01219             {
01220                 remainingBones.erase(remainingBones.begin());
01221                 continue;
01222             }
01223 
01224             // this is a marker, to know if a face insertion will occurs.
01225             bool        faceAdded= false;
01226 
01227             // traverse all faces, trying to insert them in current MatrixBlock processed.
01228             list<uint>::iterator    itFace;
01229             for(itFace= remainingFaces.begin(); itFace!=remainingFaces.end();)
01230             {
01231                 bool    useCurrentBoneId;
01232                 uint    newBoneAdded;
01233 
01234                 // i/ Get info on current face.
01235                 //-----------------------------
01236 
01237                 // build which bones this face use.
01238                 tmpFaces[*itFace].buildBoneUse(boneUse, m.SkinWeights);
01239 
01240                 // test if this face use the currentBoneId.
01241                 useCurrentBoneId= false;
01242                 for(i=0;i<(sint)boneUse.size();i++)
01243                 {
01244                     // if this face use the currentBoneId
01245                     if(boneUse[i]==currentBoneId)
01246                     {
01247                         useCurrentBoneId= true;
01248                         break;
01249                     }
01250                 }
01251                 // compute how many bones that are not in the current matrixblock this face use.
01252                 newBoneAdded=0;
01253                 for(i=0;i<(sint)boneUse.size();i++)
01254                 {
01255                     // if this bone is not inserted in the current matrix block, inform it.
01256                     if(!remainingBones[boneUse[i]].Inserted)
01257                         newBoneAdded++;
01258                 }
01259 
01260 
01261                 // ii/ insert/reject face.
01262                 //------------------------
01263 
01264                 // If this face do not add any more bone, we can insert it into the current matrixblock.
01265                 // If it use the currentBoneId, and do not explode max count, we allow insert it too in the current matrixblock.
01266                 if( newBoneAdded==0 ||
01267                     (useCurrentBoneId && newBoneAdded+matrixBlock.NumMatrix < IDriver::MaxModelMatrix) )
01268                 {
01269                     // Insert this face in the current matrix block
01270 
01271                     CFaceTmp    &face= tmpFaces[*itFace];
01272 
01273                     // for all vertices of this face.
01274                     for(j=0;j<3;j++)
01275                     {
01276                         CMesh::CSkinWeight  &sw= m.SkinWeights[face.Corner[j].Vertex];
01277 
01278                         // for each corner weight (4)
01279                         for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
01280                         {
01281                             // get the global boneId this corner weight use.
01282                             uint        boneId= sw.MatrixId[k];
01283                             // get the CBoneTmp this corner weight use.
01284                             CBoneTmp    &bone= remainingBones[boneId];
01285 
01286                             // decRef the bone .
01287                             bone.RefCount--;
01288 
01289                             // Is this bone already inserted in the MatrixBlock ?
01290                             if( !bone.Inserted )
01291                             {
01292                                 // No, insert it.
01293                                 bone.Inserted= true;
01294                                 // link it to the MatrixId in the current matrixBlock.
01295                                 bone.MatrixIdInMB= matrixBlock.NumMatrix;
01296 
01297                                 // modify the matrixBlock
01298                                 matrixBlock.MatrixId[matrixBlock.NumMatrix]= boneId;
01299                                 // increment the number of matrix in the matrixBlock.
01300                                 matrixBlock.NumMatrix++;
01301                             }
01302 
01303                             // Copy Weight info for this Corner.
01304                             // Set what matrix in the current matrix block this corner use.
01305                             face.Corner[j].Palette.MatrixId[k]= bone.MatrixIdInMB;
01306                             // Set weight.
01307                             face.Corner[j].Weights[k]= sw.Weights[k];
01308                         }
01309                     }
01310 
01311                     // to Which matrixblock this face is inserted.
01312                     face.MatrixBlockId= _MatrixBlocks.size()-1;
01313 
01314                     // remove the face from remain face list.
01315                     itFace= remainingFaces.erase(itFace);
01316 
01317                     // inform the algorithm that a face has been added.
01318                     faceAdded= true;
01319                 }
01320                 else
01321                 {
01322                     // do not append this face to the current matrix block, skip to the next
01323                     itFace++;
01324                 }
01325             }
01326 
01327             // If no faces have been added during this pass, we are blocked, and either the MatrixBlock may be full,
01328             // or there is no more face. So quit this block and process a new one.
01329             if(!faceAdded)
01330                 break;
01331         }
01332 
01333     }
01334     // NB: at the end of this loop, remainingBones may not be empty(), but all remainingBones should have RefCount==0.
01335 
01336 
01337 
01338     // 4. Re-order matrix use in MatrixBlocks, for minimum matrix change between MatrixBlocks.
01339     //================================
01340     vector<CMatrixBlockRemap>   blockRemaps;
01341     blockRemaps.resize(_MatrixBlocks.size());
01342 
01343 
01344     // For all MatrixBlocks > first, try to "mirror" bones from previous.
01345     for(i=1;i<(sint)_MatrixBlocks.size();i++)
01346     {
01347         CMatrixBlock        &mBlock= _MatrixBlocks[i];
01348         CMatrixBlock        &mPrevBlock= _MatrixBlocks[i-1];
01349         CMatrixBlockRemap   &remap= blockRemaps[i];
01350 
01351         // First bkup the bone ids in remap table.
01352         for(j=0;j<(sint)mBlock.NumMatrix;j++)
01353         {
01354             remap.Remap[j]= mBlock.MatrixId[j];
01355         }
01356 
01357         // For all ids of this blocks, try to mirror them.
01358         for(j=0;j<(sint)mBlock.NumMatrix;j++)
01359         {
01360             // get the location of this bone in the prev bone.
01361             sint    idLoc= mPrevBlock.getMatrixIdLocation(mBlock.MatrixId[j]);
01362             // If not found, or if bigger than current array, fails (cant be mirrored).
01363             // Or if already mirrored.
01364             if(idLoc==-1 || idLoc>=(sint)mBlock.NumMatrix || idLoc==j)
01365             {
01366                 // next id.
01367                 j++;
01368             }
01369             else
01370             {
01371                 // puts me on my mirrored location. and swap with the current one at this mirrored location.
01372                 swap(mBlock.MatrixId[j], mBlock.MatrixId[idLoc]);
01373                 // mBlock.MatrixId[j] is now a candidate for mirror.
01374             }
01375         }
01376 
01377         // Then build the Remap table, to re-order faces matrixId which use this matrix block.
01378         for(j=0;j<(sint)mBlock.NumMatrix;j++)
01379         {
01380             // get the boneid which was at this position j before.
01381             uint    boneId= remap.Remap[j];
01382             // search his new position, and store the result in the remap table.
01383             remap.Remap[j]= mBlock.getMatrixIdLocation(boneId);
01384         }
01385 
01386         // NB: this matrixBlock is re-ordered. next matrixBlock use this state.
01387     }
01388 
01389 
01390     // For all faces/corners/weights, remap MatrixIds.
01391     for(i=0;i<(sint)tmpFaces.size();i++)
01392     {
01393         CFaceTmp    &face= tmpFaces[i];
01394         // do it but for matrixblock0.
01395         if(face.MatrixBlockId!=0)
01396         {
01397             CMatrixBlockRemap   &remap= blockRemaps[face.MatrixBlockId];
01398             // For all corners.
01399             for(j=0;j<3;j++)
01400             {
01401                 for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
01402                 {
01403                     uint    oldId= face.Corner[j].Palette.MatrixId[k];
01404                     face.Corner[j].Palette.MatrixId[k]= (uint8)remap.Remap[oldId];
01405                 }
01406             }
01407         }
01408     }
01409 
01410 }
01411 
01412 
01413 // ***************************************************************************
01414 void    CMeshGeom::CFaceTmp::buildBoneUse(vector<uint>  &boneUse, vector<CMesh::CSkinWeight> &skinWeights)
01415 {
01416     boneUse.clear();
01417 
01418     // For the 3 corners of the face.
01419     for(sint i=0;i<3;i++)
01420     {
01421         // get the CSkinWeight of this vertex.
01422         CMesh::CSkinWeight  &sw= skinWeights[Corner[i].Vertex];
01423 
01424         // For all skin weights of this vertex,
01425         for(sint j=0;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
01426         {
01427             uint    boneId= sw.MatrixId[j];
01428             // insert (if not in the array) this bone.
01429             if( find(boneUse.begin(), boneUse.end(), boneId)==boneUse.end() )
01430                 boneUse.push_back(boneId);
01431         }
01432     }
01433 
01434 
01435 }
01436 
01437 
01438 
01439 // ***************************************************************************
01440 sint    CMeshGeom::CMatrixBlock::getMatrixIdLocation(uint32 boneId) const
01441 {
01442     for(uint i=0;i<NumMatrix;i++)
01443     {
01444         if(MatrixId[i]==boneId)
01445             return i;
01446     }
01447 
01448     // not found.
01449     return -1;
01450 }
01451 
01452 
01453 // ***************************************************************************
01454 float   CMeshGeom::getNumTriangles (float distance)
01455 {
01456     // Sum of triangles
01457     uint32 triCount=0;
01458 
01459     // For each matrix block
01460     uint mbCount=_MatrixBlocks.size();
01461     for (uint mb=0; mb<mbCount; mb++)
01462     {
01463         CMatrixBlock &block=_MatrixBlocks[mb];
01464 
01465         // Count of primitive block
01466         uint pCount=block.RdrPass.size();
01467         for (uint pb=0; pb<pCount; pb++)
01468         {
01469             // Ref on the primitive block
01470             CRdrPass &pass=block.RdrPass[pb];
01471 
01472             // Sum tri
01473             triCount+=pass.PBlock.getNumIndexes ()/3;
01474         }
01475     }
01476     return (float)triCount;
01477 }
01478 
01479 
01480 // ***************************************************************************
01481 void    CMeshGeom::computeBonesId (CSkeletonModel *skeleton)
01482 {
01483     // Already computed ?
01484     if (!_BoneIdComputed)
01485     {
01486         // Get a pointer on the skeleton
01487         nlassert (skeleton);
01488         if (skeleton)
01489         {
01490             // **** For each bones, compute remap
01491             std::vector<uint> remap;
01492             skeleton->remapSkinBones(_BonesName, _BonesId, remap);
01493 
01494 
01495             // **** Remap matrix blocks
01496             for (uint matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
01497             {
01498                 // Ref on the matrix block
01499                 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
01500 
01501                 // For each matrix
01502                 uint matrix;
01503                 for (matrix=0; matrix<mb.NumMatrix; matrix++)
01504                 {
01505                     // Get bone id in the skeleton
01506                     nlassert (mb.MatrixId[matrix]<remap.size());
01507                     mb.MatrixId[matrix] = remap[mb.MatrixId[matrix]];
01508                 }
01509             }
01510 
01511             // **** Remap ShadowSkin, and compute Bone Sphere
01512             // Prepare Sphere compute
01513             static std::vector<CAABBox>     boneBBoxes;
01514             static std::vector<bool>        boneBBEmpty;
01515             boneBBoxes.clear();
01516             boneBBEmpty.clear();
01517             boneBBoxes.resize(_BonesId.size());
01518             boneBBEmpty.resize(_BonesId.size(), true);
01519 
01520             // For simplicity, use the shadow skin info only, to compute bone sphere
01521             for(uint vert=0;vert<_ShadowSkin.Vertices.size();vert++)
01522             {
01523                 CShadowVertex   &v= _ShadowSkin.Vertices[vert];
01524                 // Check id
01525                 uint    srcId= v.MatrixId;
01526                 nlassert ( srcId < remap.size());
01527                 // remap
01528                 v.MatrixId= remap[srcId];
01529 
01530                 // if the boneId is valid (ie found)
01531                 if(_BonesId[srcId]>=0)
01532                 {
01533                     // transform the vertex pos in BoneSpace
01534                     CVector     p= skeleton->Bones[_BonesId[srcId]].getBoneBase().InvBindPos * v.Vertex;
01535                     // extend the bone bbox.
01536                     if(boneBBEmpty[srcId])
01537                     {
01538                         boneBBoxes[srcId].setCenter(p);
01539                         boneBBEmpty[srcId]= false;
01540                     }
01541                     else
01542                     {
01543                         boneBBoxes[srcId].extend(p);
01544                     }
01545                 }
01546             }
01547 
01548             // Compile spheres
01549             _BonesSphere.resize(_BonesId.size());
01550             for(uint bone=0;bone<_BonesSphere.size();bone++)
01551             {
01552                 // If the bone is empty, mark with -1 in the radius.
01553                 if(boneBBEmpty[bone])
01554                 {
01555                     _BonesSphere[bone].Radius= -1;
01556                 }
01557                 else
01558                 {
01559                     _BonesSphere[bone].Center= boneBBoxes[bone].getCenter();
01560                     _BonesSphere[bone].Radius= boneBBoxes[bone].getRadius();
01561                 }
01562             }
01563 
01564 
01565             // Computed
01566             _BoneIdComputed = true;
01567         }
01568     }
01569 
01570     // Already extended ?
01571     if (!_BoneIdExtended)
01572     {
01573         nlassert (skeleton);
01574         if (skeleton)
01575         {
01576             // the total bone Usage of the mesh.
01577             vector<bool>    boneUsage;
01578             boneUsage.resize(skeleton->Bones.size(), false);
01579 
01580             // for all Bones marked as valid.
01581             uint    i;
01582             for(i=0; i<_BonesId.size(); i++)
01583             {
01584                 // if not a valid boneId, skip it.
01585                 if(_BonesId[i]<0)
01586                     continue;
01587 
01588                 // mark him and his father in boneUsage.
01589                 skeleton->flagBoneAndParents(_BonesId[i], boneUsage);
01590             }
01591 
01592             // fill _BonesIdExt with bones of _BonesId and their parents.
01593             _BonesIdExt.clear();
01594             for(i=0; i<boneUsage.size();i++)
01595             {
01596                 // if the bone is used by the mesh, add it to BoneIdExt.
01597                 if(boneUsage[i])
01598                     _BonesIdExt.push_back(i);
01599             }
01600 
01601         }
01602 
01603         // Extended
01604         _BoneIdExtended= true;
01605     }
01606 
01607 }
01608 
01609 
01610 // ***************************************************************************
01611 void    CMeshGeom::buildBoneUsageVer3 ()
01612 {
01613     if(_Skinned)
01614     {
01615         // parse all matrixBlocks, couting MaxBoneId used.
01616         uint32  maxBoneId= 0;
01617         // For each matrix block
01618         uint matrixBlock;
01619         for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
01620         {
01621             CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
01622             // For each matrix
01623             for (uint matrix=0; matrix<mb.NumMatrix; matrix++)
01624             {
01625                 maxBoneId= max(mb.MatrixId[matrix], maxBoneId);
01626             }
01627         }
01628 
01629         // alloc an array of maxBoneId+1, reset to 0.
01630         std::vector<uint8>      boneUsage;
01631         boneUsage.resize(maxBoneId+1, 0);
01632 
01633         // reparse all matrixBlocks, counting usage for each bone.
01634         for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
01635         {
01636             CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
01637             // For each matrix
01638             for (uint matrix=0; matrix<mb.NumMatrix; matrix++)
01639             {
01640                 // mark this bone as used.
01641                 boneUsage[mb.MatrixId[matrix]]= 1;
01642             }
01643         }
01644 
01645         // For each bone used
01646         _BonesId.clear();
01647         for(uint i=0; i<boneUsage.size();i++)
01648         {
01649             // if the bone is used by the mesh, add it to BoneId.
01650             if(boneUsage[i])
01651                 _BonesId.push_back(i);
01652         }
01653 
01654         // Must also compute _BonesSphere
01655         // Cannot do it easily, deprecated data format => suppose radius 0 sphere
01656         CBSphere    sphere(CVector::Null, 0.f);
01657         _BonesSphere.clear();
01658         _BonesSphere.resize(_BonesId.size(), sphere);
01659 
01660     }
01661 }
01662 
01663 
01664 // ***************************************************************************
01665 void    CMeshGeom::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
01666 {
01667     // For all Bones used by this mesh.
01668     for(uint i=0; i<_BonesIdExt.size();i++)
01669     {
01670         uint    boneId= _BonesIdExt[i];
01671         // Some explicit Error.
01672         if(boneId>=sm->Bones.size())
01673             nlerror(" Skin is incompatible with Skeleton: tries to use bone %d", boneId);
01674         // increment or decrement not Forced, because CMeshGeom use getActiveBoneSkinMatrix().
01675         if(increment)
01676             sm->incBoneUsage(boneId, CSkeletonModel::UsageNormal);
01677         else
01678             sm->decBoneUsage(boneId, CSkeletonModel::UsageNormal);
01679     }
01680 }
01681 
01682 
01683 // ***************************************************************************
01684 void    CMeshGeom::bkupOriginalSkinVertices()
01685 {
01686     nlassert(_Skinned);
01687 
01688     // reset
01689     contReset(_OriginalSkinVertices);
01690     contReset(_OriginalSkinNormals);
01691     contReset(_OriginalTGSpace);
01692 
01693     // get num of vertices
01694     uint    numVertices= _VBuffer.getNumVertices();
01695 
01696     CVertexBufferRead vba;
01697     _VBuffer.lock (vba);
01698 
01699     // Copy VBuffer content into Original vertices normals.
01700     if(_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag)
01701     {
01702         // copy vertices from VBuffer. (NB: unuseful geomorphed vertices are still copied, but doesn't matter).
01703         _OriginalSkinVertices.resize(numVertices);
01704         for(uint i=0; i<numVertices;i++)
01705         {
01706             _OriginalSkinVertices[i]= *vba.getVertexCoordPointer(i);
01707         }
01708     }
01709     if(_VBuffer.getVertexFormat() & CVertexBuffer::NormalFlag)
01710     {
01711         // copy normals from VBuffer. (NB: unuseful geomorphed normals are still copied, but doesn't matter).
01712         _OriginalSkinNormals.resize(numVertices);
01713         for(uint i=0; i<numVertices;i++)
01714         {
01715             _OriginalSkinNormals[i]= *vba.getNormalCoordPointer(i);
01716         }
01717     }
01718 
01719     // is there tangent space added ?
01720     if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
01721     {
01722         // yes, backup it
01723         nlassert(_VBuffer.getNumTexCoordUsed() > 0);
01724         uint tgSpaceStage = _VBuffer.getNumTexCoordUsed() - 1;
01725         _OriginalTGSpace.resize(numVertices);
01726         for(uint i=0; i<numVertices;i++)
01727         {
01728             _OriginalTGSpace[i]= *(CVector*)vba.getTexCoordPointer(i, tgSpaceStage);
01729         }
01730     }
01731 }
01732 
01733 
01734 // ***************************************************************************
01735 void    CMeshGeom::restoreOriginalSkinVertices()
01736 {
01737     nlassert(_Skinned);
01738 
01739     // get num of vertices
01740     uint    numVertices= _VBuffer.getNumVertices();
01741 
01742     CVertexBufferReadWrite vba;
01743     _VBuffer.lock (vba);
01744 
01745     // Copy VBuffer content into Original vertices normals.
01746     if(_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag)
01747     {
01748         // copy vertices from VBuffer. (NB: unuseful geomorphed vertices are still copied, but doesn't matter).
01749         for(uint i=0; i<numVertices;i++)
01750         {
01751             *vba.getVertexCoordPointer(i)= _OriginalSkinVertices[i];
01752         }
01753     }
01754     if(_VBuffer.getVertexFormat() & CVertexBuffer::NormalFlag)
01755     {
01756         // copy normals from VBuffer. (NB: unuseful geomorphed normals are still copied, but doesn't matter).
01757         for(uint i=0; i<numVertices;i++)
01758         {
01759             *vba.getNormalCoordPointer(i)= _OriginalSkinNormals[i];
01760         }
01761     }
01762     if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
01763     {
01764         uint numTexCoords = _VBuffer.getNumTexCoordUsed();
01765         nlassert(numTexCoords >= 2);
01766         nlassert(_OriginalTGSpace.size() == numVertices);
01767         // copy tangent space vectors
01768         for(uint i = 0; i < numVertices; ++i)
01769         {
01770             *(CVector*)vba.getTexCoordPointer(i, numTexCoords - 1)= _OriginalTGSpace[i];
01771         }
01772     }
01773 
01774     // cleared
01775     _OriginalSkinRestored= true;
01776 }
01777 
01778 
01779 // ***************************************************************************
01780 // Flags for software vertex skinning.
01781 #define NL3D_SOFTSKIN_VNEEDCOMPUTE  3
01782 #define NL3D_SOFTSKIN_VMUSTCOMPUTE  1
01783 #define NL3D_SOFTSKIN_VCOMPUTED     0
01784 // 3 means "vertex may need compute".
01785 // 1 means "Primitive say vertex must be computed".
01786 // 0 means "vertex is computed".
01787 
01788 
01789 // ***************************************************************************
01790 void    CMeshGeom::applySkin(CSkeletonModel *skeleton)
01791 {
01792     // init.
01793     //===================
01794     if(_OriginalSkinVertices.empty())
01795         return;
01796 
01797     // Use correct skinning
01798     TSkinType   skinType;
01799     if( _OriginalSkinNormals.empty() )
01800         skinType= SkinPosOnly;
01801     else if( _OriginalTGSpace.empty() )
01802         skinType= SkinWithNormal;
01803     else
01804         skinType= SkinWithTgSpace;
01805 
01806     // Get VB src/dst info/ptrs.
01807     uint    numVertices= _OriginalSkinVertices.size();
01808     uint    dstStride= _VBuffer.getVertexSize();
01809     // Get dst TgSpace.
01810     uint    tgSpaceStage = 0;
01811     if( skinType>= SkinWithTgSpace)
01812     {
01813         nlassert(_VBuffer.getNumTexCoordUsed() > 0);
01814         tgSpaceStage= _VBuffer.getNumTexCoordUsed() - 1;
01815     }
01816 
01817     // Mark all vertices flag to not computed.
01818     static  vector<uint8>   skinFlags;
01819     skinFlags.resize(numVertices);
01820     // reset all flags
01821     memset(&skinFlags[0], NL3D_SOFTSKIN_VNEEDCOMPUTE, numVertices );
01822 
01823     CVertexBufferRead vba;
01824     _VBuffer.lock (vba);
01825 
01826     // For all MatrixBlocks
01827     //===================
01828     for(uint mb= 0; mb<_MatrixBlocks.size();mb++)
01829     {
01830         // compute matrixes for this block.
01831         static  CMatrix3x4  matrixes[IDriver::MaxModelMatrix];
01832         computeSkinMatrixes(skeleton, matrixes, mb==0?NULL:&_MatrixBlocks[mb-1], _MatrixBlocks[mb]);
01833 
01834         // check what vertex to skin for this PB.
01835         flagSkinVerticesForMatrixBlock(&skinFlags[0], _MatrixBlocks[mb]);
01836 
01837         // Get VB src/dst ptrs.
01838         uint8       *pFlag= &skinFlags[0];
01839         CVector     *srcVector= &_OriginalSkinVertices[0];
01840         uint8       *srcPal= (uint8*)vba.getPaletteSkinPointer(0);
01841         uint8       *srcWgt= (uint8*)vba.getWeightPointer(0);
01842         uint8       *dstVector= (uint8*)vba.getVertexCoordPointer(0);
01843         // Normal.
01844         CVector     *srcNormal= NULL;
01845         uint8       *dstNormal= NULL;
01846         if(skinType>=SkinWithNormal)
01847         {
01848             srcNormal= &_OriginalSkinNormals[0];
01849             dstNormal= (uint8*)vba.getNormalCoordPointer(0);
01850         }
01851         // TgSpace.
01852         CVector     *srcTgSpace= NULL;
01853         uint8       *dstTgSpace= NULL;
01854         if(skinType>=SkinWithTgSpace)
01855         {
01856             srcTgSpace= &_OriginalTGSpace[0];
01857             dstTgSpace= (uint8*)vba.getTexCoordPointer(0, tgSpaceStage);
01858         }
01859 
01860 
01861         // For all vertices that need to be computed.
01862         uint        size= numVertices;
01863         for(;size>0;size--)
01864         {
01865             // If we must compute this vertex.
01866             if(*pFlag==NL3D_SOFTSKIN_VMUSTCOMPUTE)
01867             {
01868                 // Flag this vertex as computed.
01869                 *pFlag=NL3D_SOFTSKIN_VCOMPUTED;
01870 
01871                 CPaletteSkin    *psPal= (CPaletteSkin*)srcPal;
01872 
01873                 // checks indices.
01874                 nlassert(psPal->MatrixId[0]<IDriver::MaxModelMatrix);
01875                 nlassert(psPal->MatrixId[1]<IDriver::MaxModelMatrix);
01876                 nlassert(psPal->MatrixId[2]<IDriver::MaxModelMatrix);
01877                 nlassert(psPal->MatrixId[3]<IDriver::MaxModelMatrix);
01878 
01879                 // compute vertex part.
01880                 computeSoftwarePointSkinning(matrixes, srcVector, psPal, (float*)srcWgt, (CVector*)dstVector);
01881 
01882                 // compute normal part.
01883                 if(skinType>=SkinWithNormal)
01884                     computeSoftwareVectorSkinning(matrixes, srcNormal, psPal, (float*)srcWgt, (CVector*)dstNormal);
01885 
01886                 // compute tg part.
01887                 if(skinType>=SkinWithTgSpace)
01888                     computeSoftwareVectorSkinning(matrixes, srcTgSpace, psPal, (float*)srcWgt, (CVector*)dstTgSpace);
01889             }
01890 
01891             // inc flags.
01892             pFlag++;
01893             // inc src (all whatever skin type used...)
01894             srcVector++;
01895             srcNormal++;
01896             srcTgSpace++;
01897             // inc paletteSkin and dst  (all whatever skin type used...)
01898             srcPal+= dstStride;
01899             srcWgt+= dstStride;
01900             dstVector+= dstStride;
01901             dstNormal+= dstStride;
01902             dstTgSpace+= dstStride;
01903         }
01904     }
01905 
01906 
01907     // dirt
01908     _OriginalSkinRestored= false;
01909 }
01910 
01911 
01912 // ***************************************************************************
01913 void    CMeshGeom::flagSkinVerticesForMatrixBlock(uint8 *skinFlags, CMatrixBlock &mb)
01914 {
01915     for(uint i=0; i<mb.RdrPass.size(); i++)
01916     {
01917         CIndexBuffer    &PB= mb.RdrPass[i].PBlock;
01918 
01919         uint    nIndex;
01920 
01921         // This may be better to flags in 2 pass (first traverse primitives, then test vertices).
01922         // Better sol for BTB..., because number of tests are divided by 6 (for triangles).
01923 
01924         // for all prims, indicate which vertex we must compute.
01925         // nothing if not already computed (ie 0), because 0&1==0.
01926         // Lines.
01927         // Tris.
01928         CIndexBufferRead iba;
01929         PB.lock (iba);
01930         nIndex= PB.getNumIndexes();
01931         if (iba.getFormat() == CIndexBuffer::Indices32)
01932         {
01933             uint32 *pIndex= (uint32*)iba.getPtr();
01934             for(;nIndex>0;nIndex--, pIndex++)
01935                 skinFlags[*pIndex]&= NL3D_SOFTSKIN_VMUSTCOMPUTE;
01936         }
01937         else
01938         {
01939             uint16 *pIndex= (uint16*)iba.getPtr();
01940             for(;nIndex>0;nIndex--, pIndex++)
01941                 skinFlags[*pIndex]&= NL3D_SOFTSKIN_VMUSTCOMPUTE;
01942         }
01943     }
01944 }
01945 
01946 
01947 // ***************************************************************************
01948 void    CMeshGeom::computeSoftwarePointSkinning(CMatrix3x4 *matrixes, CVector *srcVec, CPaletteSkin *srcPal, float *srcWgt, CVector *pDst)
01949 {
01950     CMatrix3x4      *pMat;
01951 
01952     // 0th matrix influence.
01953     pMat= matrixes + srcPal->MatrixId[0];
01954     pMat->mulSetPoint(*srcVec, srcWgt[0], *pDst);
01955     // 1th matrix influence.
01956     pMat= matrixes + srcPal->MatrixId[1];
01957     pMat->mulAddPoint(*srcVec, srcWgt[1], *pDst);
01958     // 2th matrix influence.
01959     pMat= matrixes + srcPal->MatrixId[2];
01960     pMat->mulAddPoint(*srcVec, srcWgt[2], *pDst);
01961     // 3th matrix influence.
01962     pMat= matrixes + srcPal->MatrixId[3];
01963     pMat->mulAddPoint(*srcVec, srcWgt[3], *pDst);
01964 }
01965 
01966 
01967 // ***************************************************************************
01968 void    CMeshGeom::computeSoftwareVectorSkinning(CMatrix3x4 *matrixes, CVector *srcVec, CPaletteSkin *srcPal, float *srcWgt, CVector *pDst)
01969 {
01970     CMatrix3x4      *pMat;
01971 
01972     // 0th matrix influence.
01973     pMat= matrixes + srcPal->MatrixId[0];
01974     pMat->mulSetVector(*srcVec, srcWgt[0], *pDst);
01975     // 1th matrix influence.
01976     pMat= matrixes + srcPal->MatrixId[1];
01977     pMat->mulAddVector(*srcVec, srcWgt[1], *pDst);
01978     // 2th matrix influence.
01979     pMat= matrixes + srcPal->MatrixId[2];
01980     pMat->mulAddVector(*srcVec, srcWgt[2], *pDst);
01981     // 3th matrix influence.
01982     pMat= matrixes + srcPal->MatrixId[3];
01983     pMat->mulAddVector(*srcVec, srcWgt[3], *pDst);
01984 }
01985 
01986 
01987 // ***************************************************************************
01988 void    CMeshGeom::computeSkinMatrixes(CSkeletonModel *skeleton, CMatrix3x4 *matrixes, CMatrixBlock  *prevBlock, CMatrixBlock  &mBlock)
01989 {
01990     // For all matrix of this mBlock.
01991     for(uint idMat=0;idMat<mBlock.NumMatrix;idMat++)
01992     {
01993         uint    curBoneId= mBlock.MatrixId[idMat];
01994 
01995         // If same matrix binded as previous block, no need to bind!!
01996         if(prevBlock && idMat<prevBlock->NumMatrix && prevBlock->MatrixId[idMat]== curBoneId)
01997             continue;
01998 
01999         // Else, we must setup the matrix
02000         matrixes[idMat].set(skeleton->getActiveBoneSkinMatrix(curBoneId));
02001     }
02002 }
02003 
02004 
02005 // ***************************************************************************
02006 void    CMeshGeom::profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, float polygonCount, uint32 rdrFlags)
02007 {
02008     // get the mesh instance.
02009     CMeshBaseInstance   *mi= safe_cast<CMeshBaseInstance*>(trans);
02010 
02011     // For all _MatrixBlocks
02012     uint    triCount= 0;
02013     for(uint mb=0;mb<_MatrixBlocks.size();mb++)
02014     {
02015         CMatrixBlock    &mBlock= _MatrixBlocks[mb];
02016 
02017         // Profile all pass.
02018         for (uint i=0;i<mBlock.RdrPass.size();i++)
02019         {
02020             CRdrPass    &rdrPass= mBlock.RdrPass[i];
02021             // Profile with the Materials of the MeshInstance.
02022             if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
02023                  ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
02024             {
02025                 triCount+= rdrPass.PBlock.getNumIndexes()/3;
02026             }
02027         }
02028     }
02029 
02030     // Profile
02031     if(triCount)
02032     {
02033         // tri per VBFormat
02034         rdrTrav->Scene->incrementProfileTriVBFormat(rdrTrav->Scene->BenchRes.MeshProfileTriVBFormat,
02035             _VBuffer.getVertexFormat(), triCount);
02036 
02037         // VBHard
02038         if(_VBuffer.getPreferredMemory()!=CVertexBuffer::RAMPreferred)
02039             rdrTrav->Scene->BenchRes.NumMeshVBufferHard++;
02040         else
02041             rdrTrav->Scene->BenchRes.NumMeshVBufferStd++;
02042 
02043         // rendered in BlockRendering, only if not transparent pass (known it if RenderTransparentMaterial is set)
02044         if(supportMeshBlockRendering() && (rdrFlags & IMeshGeom::RenderTransparentMaterial)==0 )
02045         {
02046             if(isMeshInVBHeap())
02047             {
02048                 rdrTrav->Scene->BenchRes.NumMeshRdrBlockWithVBHeap++;
02049                 rdrTrav->Scene->BenchRes.NumMeshTriRdrBlockWithVBHeap+= triCount;
02050             }
02051             else
02052             {
02053                 rdrTrav->Scene->BenchRes.NumMeshRdrBlock++;
02054                 rdrTrav->Scene->BenchRes.NumMeshTriRdrBlock+= triCount;
02055             }
02056         }
02057         else
02058         {
02059             rdrTrav->Scene->BenchRes.NumMeshRdrNormal++;
02060             rdrTrav->Scene->BenchRes.NumMeshTriRdrNormal+= triCount;
02061         }
02062     }
02063 }
02064 
02065 // ***************************************************************************
02066 bool    CMeshGeom::intersectSkin(CTransformShape    *mi, const CMatrix &toRaySpace, float &dist2D, float &distZ, bool computeDist2D)
02067 {
02068     // for Mesh, Use the Shadow Skinning (simple version).
02069 
02070     // get skeleton
02071     if(!mi || _OriginalSkinVertices.empty())
02072         return false;
02073     CSkeletonModel  *skeleton= mi->getSkeletonModel();
02074     if(!skeleton)
02075         return false;
02076 
02077     // Compute skinning with all matrix this Mesh use. (the shadow geometry cannot use other Matrix than the mesh use).
02078     static std::vector<uint32>  matInfs;
02079     matInfs.resize(_BonesId.size());
02080     for(uint i=0;i<matInfs.size();i++)
02081     {
02082         // treat any "missing bone" as the root one.
02083         matInfs[i]= max(_BonesId[i], (sint32)0);
02084     }
02085     return _ShadowSkin.getRayIntersection(toRaySpace, *skeleton, matInfs, dist2D, distZ, computeDist2D);
02086 }
02087 
02088 // ***************************************************************************
02089 void    CMeshGeom::buildShadowSkin()
02090 {
02091     /* ***********************************************
02092      *  WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
02093      *  It can be loaded/called through CAsyncFileManager for instance
02094      * ***********************************************/
02095 
02096     // reset
02097     contReset(_ShadowSkin.Vertices);
02098     contReset(_ShadowSkin.Triangles);
02099 
02100     nlassert(_Skinned && (_VBuffer.getVertexFormat() & CVertexBuffer::PaletteSkinFlag)
02101         && (_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag) );
02102 
02103 
02104     // *** Copy VBuffer content
02105     {
02106         // get num of vertices
02107         uint    numVertices= _VBuffer.getNumVertices();
02108 
02109         // lock VB
02110         CVertexBufferRead vba;
02111         _VBuffer.lock (vba);
02112         uint8       *srcPal= (uint8*)vba.getPaletteSkinPointer(0);
02113         uint8       *srcVert= (uint8*)vba.getVertexCoordPointer(0);
02114         uint32      srcVertSize= _VBuffer.getVertexSize();
02115 
02116         // copy vertices from VBuffer
02117         _ShadowSkin.Vertices.resize(numVertices);
02118         for(uint i=0; i<numVertices;i++)
02119         {
02120             // Copy Vertex
02121             _ShadowSkin.Vertices[i].Vertex= *((CVector*)srcVert);
02122             // Suppose the 0 matrix inf is the highest (we are at least sure it is not 0)
02123             // And SkinWeight Export show the 0th is the highest one...
02124             _ShadowSkin.Vertices[i].MatrixId= ((CPaletteSkin*)srcPal)->MatrixId[0];
02125 
02126             // Next
02127             srcVert+= srcVertSize;
02128             srcPal+= srcVertSize;
02129         }
02130     }
02131 
02132     // But _ShadowSkin.Vertices[i].MatrixId is incorrect, since < IDriver::MaxModelMatrix
02133 
02134 
02135     // *** Count number of triangles, and get start index of each matrix block in the final Tri list
02136     uint    numIndices= 0;
02137     uint    mb;
02138     // can't be static cause of ThreadSafe
02139     vector<pair<uint32,uint32> >        mbIndexRange;
02140     mbIndexRange.resize(_MatrixBlocks.size());
02141     for(mb=0;mb<_MatrixBlocks.size();mb++)
02142     {
02143         // this matrix block start here
02144         mbIndexRange[mb].first= numIndices;
02145 
02146         // count tris rendered for this matrix block
02147         const CMatrixBlock  &mBlock= _MatrixBlocks[mb];
02148         for(uint rp=0;rp<mBlock.RdrPass.size();rp++)
02149         {
02150             const CRdrPass  &rPass= mBlock.RdrPass[rp];
02151             numIndices+= rPass.PBlock.getNumIndexes();
02152         }
02153 
02154         // this matrix block end here
02155         mbIndexRange[mb].second= numIndices;
02156     }
02157 
02158 
02159     // *** Fill Triangles
02160     nlverify(retrieveTriangles(_ShadowSkin.Triangles));
02161     nlassert(numIndices==_ShadowSkin.Triangles.size());
02162 
02163 
02164     // *** Reindex correctly MatrixId, (ie unpack matrix blocks)
02165     // can't be static cause of ThreadSafe
02166     vector<bool>    vertReIndexed;
02167     vertReIndexed.resize(_ShadowSkin.Vertices.size(), false);
02168     // for all matrix blocks
02169     for(mb=0;mb<mbIndexRange.size();mb++)
02170     {
02171         const CMatrixBlock  &mBlock= _MatrixBlocks[mb];
02172 
02173         uint    iStart= mbIndexRange[mb].first;
02174         uint    iEnd= mbIndexRange[mb].second;
02175         nlassert(iStart <= iEnd && iEnd<=_ShadowSkin.Triangles.size());
02176 
02177         // For all indices in this range
02178         uint32  *pIndex= &_ShadowSkin.Triangles[iStart];
02179         uint    nbIndex= iEnd - iStart;
02180         for(;nbIndex>0;--nbIndex, pIndex++)
02181         {
02182             uint    index= *pIndex;
02183             // if not already reindexed
02184             if(!vertReIndexed[index])
02185             {
02186                 vertReIndexed[index]= true;
02187                 // reindex
02188                 uint    matId= _ShadowSkin.Vertices[index].MatrixId;
02189                 nlassert(matId<mBlock.NumMatrix);
02190                 _ShadowSkin.Vertices[index].MatrixId= mBlock.MatrixId[matId];
02191             }
02192         }
02193     }
02194 }
02195 
02196 
02197 // ***************************************************************************
02198 // ***************************************************************************
02199 // Mesh Block Render Interface
02200 // ***************************************************************************
02201 // ***************************************************************************
02202 
02203 
02204 // ***************************************************************************
02205 bool    CMeshGeom::supportMeshBlockRendering () const
02206 {
02207     return _SupportMBRFlags!=0;
02208 }
02209 
02210 // ***************************************************************************
02211 bool    CMeshGeom::sortPerMaterial() const
02212 {
02213     return (_SupportMBRFlags & MBRSortPerMaterial)!=0;
02214 }
02215 // ***************************************************************************
02216 uint    CMeshGeom::getNumRdrPassesForMesh() const
02217 {
02218     return _MatrixBlocks[0].RdrPass.size();
02219 }
02220 // ***************************************************************************
02221 uint    CMeshGeom::getNumRdrPassesForInstance(CMeshBaseInstance *inst) const
02222 {
02223     return _MatrixBlocks[0].RdrPass.size();
02224 }
02225 // ***************************************************************************
02226 void    CMeshGeom::beginMesh(CMeshGeomRenderContext &rdrCtx)
02227 {
02228     if(rdrCtx.RenderThroughVBHeap)
02229     {
02230         // Don't setup VB in this case, since use the VBHeap setuped one.
02231         // NB: no VertexProgram test since VBHeap not possible with it...
02232         nlassert( (_SupportMBRFlags & MBRCurrentUseVP)==0 );
02233     }
02234     else
02235     {
02236         // use MeshVertexProgram effect?
02237         if( _MeshVertexProgram != NULL && _MeshVertexProgram->isMBRVpOk(rdrCtx.Driver) )
02238         {
02239             // Ok will use it.
02240             _SupportMBRFlags|= MBRCurrentUseVP;
02241             // Before VB activation
02242             _MeshVertexProgram->beginMBRMesh(rdrCtx.Driver, rdrCtx.Scene );
02243         }
02244 
02245         // active VB. SoftwareSkinning: reset flags for skinning.
02246         rdrCtx.Driver->activeVertexBuffer(_VBuffer);
02247     }
02248 }
02249 // ***************************************************************************
02250 void    CMeshGeom::activeInstance(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *inst, float polygonCount, void *vbDst)
02251 {
02252     // setup instance matrix
02253     rdrCtx.Driver->setupModelMatrix(inst->getWorldMatrix());
02254 
02255     // setupLighting.
02256     inst->changeLightSetup(rdrCtx.RenderTrav);
02257 
02258     // MeshVertexProgram ?
02259     if( _SupportMBRFlags & MBRCurrentUseVP )
02260     {
02261         CMatrix     invertedObjectMatrix;
02262         invertedObjectMatrix = inst->getWorldMatrix().inverted();
02263         _MeshVertexProgram->beginMBRInstance(rdrCtx.Driver, rdrCtx.Scene, inst, invertedObjectMatrix);
02264     }
02265 }
02266 // ***************************************************************************
02267 void    CMeshGeom::renderPass(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *mi, float polygonCount, uint rdrPassId)
02268 {
02269     CMatrixBlock    &mBlock= _MatrixBlocks[0];
02270 
02271     CRdrPass        &rdrPass= mBlock.RdrPass[rdrPassId];
02272     // Render with the Materials of the MeshInstance, only if not blended.
02273     if( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) ) )
02274     {
02275         CMaterial   &material= mi->Materials[rdrPass.MaterialId];
02276 
02277         // MeshVertexProgram ?
02278         if( _SupportMBRFlags & MBRCurrentUseVP )
02279         {
02280             rdrCtx.RenderTrav->changeVPLightSetupMaterial(material, false);
02281         }
02282 
02283         if(rdrCtx.RenderThroughVBHeap)
02284         {
02285             // render shifted primitives
02286             rdrCtx.Driver->activeIndexBuffer(rdrPass.VBHeapPBlock);
02287             rdrCtx.Driver->renderTriangles(material, 0, rdrPass.VBHeapPBlock.getNumIndexes()/3);
02288         }
02289         else
02290         {
02291             // render primitives
02292             rdrCtx.Driver->activeIndexBuffer(rdrPass.PBlock);
02293             rdrCtx.Driver->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
02294         }
02295     }
02296 }
02297 // ***************************************************************************
02298 void    CMeshGeom::endMesh(CMeshGeomRenderContext &rdrCtx)
02299 {
02300     // MeshVertexProgram ?
02301     if( _SupportMBRFlags & MBRCurrentUseVP )
02302     {
02303         // End Mesh
02304         _MeshVertexProgram->endMBRMesh( rdrCtx.Driver );
02305 
02306         // and remove Current Flag.
02307         _SupportMBRFlags&= ~MBRCurrentUseVP;
02308     }
02309 }
02310 
02311 // ***************************************************************************
02312 bool    CMeshGeom::getVBHeapInfo(uint &vertexFormat, uint &numVertices)
02313 {
02314     // CMeshGeom support VBHeap rendering, assuming supportMeshBlockRendering is true.
02315     if( _SupportMBRFlags )
02316     /* Yoyo: If VertexProgram, DON'T SUPPORT!! because VB need to be activated AFTER meshVP activation
02317         NB: still possible with complex code to do it (sort per VP type (with or not)...), but tests in Ryzom
02318         shows that VBHeap is not really important (not so much different shapes...)
02319     */
02320     if( _MeshVertexProgram==NULL )
02321     {
02322         vertexFormat= _VBuffer.getVertexFormat();
02323         numVertices= _VBuffer.getNumVertices();
02324         return true;
02325     }
02326 
02327     return false;
02328 }
02329 
02330 // ***************************************************************************
02331 void    CMeshGeom::computeMeshVBHeap(void *dst, uint indexStart)
02332 {
02333     // Fill dst with Buffer content.
02334     CVertexBufferRead vba;
02335     _VBuffer.lock (vba);
02336     memcpy(dst, vba.getVertexCoordPointer(), _VBuffer.getNumVertices()*_VBuffer.getVertexSize() );
02337 
02338     // NB: only 1 MB is possible ...
02339     nlassert(_MatrixBlocks.size()==1);
02340     CMatrixBlock    &mBlock= _MatrixBlocks[0];
02341     // For all rdrPass.
02342     for(uint i=0;i<mBlock.RdrPass.size();i++)
02343     {
02344         // shift the PB
02345         CIndexBuffer    &srcPb= mBlock.RdrPass[i].PBlock;
02346         CIndexBuffer    &dstPb= mBlock.RdrPass[i].VBHeapPBlock;
02347         uint j;
02348 
02349         // Tris.
02350         dstPb.setNumIndexes(srcPb.getNumIndexes());
02351         CIndexBufferRead ibaRead;
02352         srcPb.lock (ibaRead);
02353         CIndexBufferReadWrite ibaWrite;
02354         dstPb.lock (ibaWrite);
02355         // nico : apparently not used, so don't manage 16 bits index here
02356         nlassert(ibaRead.getFormat() == CIndexBuffer::Indices32);
02357         nlassert(ibaWrite.getFormat() == CIndexBuffer::Indices32);
02358         const uint32    *srcTriPtr= (const uint32 *) ibaRead.getPtr();
02359         uint32          *dstTriPtr= (uint32 *) ibaWrite.getPtr();
02360         for(j=0; j<dstPb.getNumIndexes();j++)
02361         {
02362             dstTriPtr[j]= srcTriPtr[j]+indexStart;
02363         }
02364     }
02365 }
02366 
02367 
02368 // ***************************************************************************
02369 // ***************************************************************************
02370 // CMeshBuild components.
02371 // ***************************************************************************
02372 // ***************************************************************************
02373 
02374 
02375 
02376 // ***************************************************************************
02377 CMesh::CCorner::CCorner()
02378 {
02379     sint    i;
02380     Vertex= 0;
02381     Normal= CVector::Null;
02382     for(i=0;i<CVertexBuffer::MaxStage;i++)
02383     {
02384         Uvws[i]= CUVW(0, 0, 0);
02385     }
02386     Color.set(255,255,255,255);
02387     Specular.set(0,0,0,0);
02388 }
02389 
02390 
02391 // ***************************************************************************
02392 void CMesh::CCorner::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02393 {
02394     nlassert(0); // not used
02395     f.serial(Vertex);
02396     f.serial(Normal);
02397     for(int i=0;i<CVertexBuffer::MaxStage;++i) f.serial(Uvws[i]);
02398     f.serial(Color);
02399     f.serial(Specular);
02400 }
02401 
02402 // ***************************************************************************
02403 void CMesh::CFace::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02404 {
02405     for(int i=0;i<3;++i)
02406         f.serial(Corner[i]);
02407     f.serial(MaterialId);
02408     f.serial(SmoothGroup);
02409 }
02410 
02411 // ***************************************************************************
02412 void CMesh::CSkinWeight::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02413 {
02414     for(int i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;++i)
02415     {
02416         f.serial(MatrixId[i]);
02417         f.serial(Weights[i]);
02418     }
02419 }
02420 
02421 // ***************************************************************************
02422 /* Serialization is not used.
02423 void CMesh::CMeshBuild::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02424 {
02425     sint    ver= f.serialVersion(0);
02426 
02427     // Serial mesh base (material info).
02428     CMeshBaseBuild::serial(f);
02429 
02430     // Serial Geometry.
02431     f.serial( VertexFlags );
02432     f.serialCont( Vertices );
02433     f.serialCont( SkinWeights );
02434     f.serialCont( Faces );
02435 
02436 }*/
02437 
02438 
02439 //************************************
02440 CMesh::CMeshBuild::CMeshBuild()
02441 {
02442     for (uint k = 0; k < CVertexBuffer::MaxStage; ++k)
02443     {
02444         NumCoords[k] = 2;
02445         UVRouting[k] = k;
02446     }
02447 }
02448 
02449 
02450 // ***************************************************************************
02451 // ***************************************************************************
02452 // CMesh.
02453 // ***************************************************************************
02454 // ***************************************************************************
02455 
02456 
02457 
02458 // ***************************************************************************
02459 CMesh::CMesh()
02460 {
02461     /* ***********************************************
02462      *  WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
02463      *  It can be loaded/called through CAsyncFileManager for instance
02464      * ***********************************************/
02465 
02466     // create the MeshGeom
02467     _MeshGeom= new CMeshGeom;
02468 }
02469 // ***************************************************************************
02470 CMesh::~CMesh()
02471 {
02472     /* ***********************************************
02473      *  WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
02474      *  It can be loaded/called through CAsyncFileManager for instance
02475      * ***********************************************/
02476 
02477     // delete the MeshGeom
02478     delete _MeshGeom;
02479 }
02480 
02481 
02482 // ***************************************************************************
02483 CMesh::CMesh(const CMesh &mesh) : CMeshBase()
02484 {
02485     // create the MeshGeom
02486     _MeshGeom= new CMeshGeom(*mesh._MeshGeom);
02487 }
02488 
02489 
02490 // ***************************************************************************
02491 CMesh   &CMesh::operator=(const CMesh &mesh)
02492 {
02493     // Copy CMeshBase part
02494     (CMeshBase&)*this= (CMeshBase&)mesh;
02495 
02496     // copy content of meshGeom.
02497     *_MeshGeom= *mesh._MeshGeom;
02498 
02499 
02500     return *this;
02501 }
02502 
02503 
02504 
02505 // ***************************************************************************
02506 void    CMesh::build (CMeshBase::CMeshBaseBuild &mbase, CMeshBuild &m)
02507 {
02509     CMeshBase::buildMeshBase (mbase);
02510 
02511     // build the geometry.
02512     _MeshGeom->build (m, mbase.Materials.size());
02513 
02514     // compile some stuff
02515     compileRunTime();
02516 }
02517 
02518 
02519 // ***************************************************************************
02520 void    CMesh::optimizeMaterialUsage(std::vector<sint> &remap)
02521 {
02522     // For each material, count usage.
02523     vector<bool>    materialUsed;
02524     materialUsed.resize(CMeshBase::_Materials.size(), false);
02525     for(uint mb=0;mb<getNbMatrixBlock();mb++)
02526     {
02527         for(uint rp=0;rp<getNbRdrPass(mb);rp++)
02528         {
02529             uint    matId= getRdrPassMaterial(mb, rp);
02530             // flag as used.
02531             materialUsed[matId]= true;
02532         }
02533     }
02534 
02535     // Apply it to meshBase
02536     CMeshBase::applyMaterialUsageOptim(materialUsed, remap);
02537 
02538     // Apply lut to meshGeom.
02539     _MeshGeom->applyMaterialRemap(remap);
02540 }
02541 
02542 
02543 // ***************************************************************************
02544 void CMesh::setBlendShapes(std::vector<CBlendShape>&bs)
02545 {
02546     _MeshGeom->setBlendShapes (bs);
02547 }
02548 
02549 // ***************************************************************************
02550 void    CMesh::build(CMeshBase::CMeshBaseBuild &mbuild, CMeshGeom &meshGeom)
02551 {
02553     CMeshBase::buildMeshBase(mbuild);
02554 
02555     // build the geometry.
02556     *_MeshGeom= meshGeom;
02557 
02558     // compile some stuff
02559     compileRunTime();
02560 }
02561 
02562 
02563 // ***************************************************************************
02564 CTransformShape     *CMesh::createInstance(CScene &scene)
02565 {
02566     // Create a CMeshInstance, an instance of a mesh.
02567     //===============================================
02568     CMeshInstance       *mi= (CMeshInstance*)scene.createModel(NL3D::MeshInstanceId);
02569     mi->Shape= this;
02570 
02571     // instanciate the material part of the Mesh, ie the CMeshBase.
02572     CMeshBase::instanciateMeshBase(mi, &scene);
02573 
02574 
02575     // do some instance init for MeshGeom
02576     _MeshGeom->initInstance(mi);
02577 
02578     // init render Filter
02579     mi->initRenderFilterType();
02580 
02581     return mi;
02582 }
02583 
02584 
02585 // ***************************************************************************
02586 bool    CMesh::clip(const std::vector<CPlane>   &pyramid, const CMatrix &worldMatrix)
02587 {
02588     return _MeshGeom->clip(pyramid, worldMatrix);
02589 }
02590 
02591 
02592 // ***************************************************************************
02593 void    CMesh::render(IDriver *drv, CTransformShape *trans, bool passOpaque)
02594 {
02595     // 0 or 0xFFFFFFFF
02596     uint32  mask= (0-(uint32)passOpaque);
02597     uint32  rdrFlags;
02598     // select rdrFlags, without ifs.
02599     rdrFlags=   mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
02600     rdrFlags|=  ~mask & (IMeshGeom::RenderTransparentMaterial);
02601     // render the mesh
02602     _MeshGeom->render(drv, trans, 0, rdrFlags, 1);
02603 }
02604 
02605 
02606 // ***************************************************************************
02607 void    CMesh::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02608 {
02609     /* ***********************************************
02610      *  WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
02611      *  It can be loaded/called through CAsyncFileManager for instance
02612      * ***********************************************/
02613 
02614     /*
02615     Version 6:
02616         - cut in serialisation, because of:
02617             - bad ITexture serialisation (with no version....) => must cut.  (see CMeshBase serial).
02618             - because of this and to simplify, make a cut too in CMesh serialisation.
02619     NB : all old version code is dropped.
02620     */
02621     sint    ver= f.serialVersion(6);
02622 
02623 
02624     if(ver<6)
02625         throw NLMISC::EStream(f, "Mesh in Stream is too old (Mesh version < 6)");
02626 
02627 
02628     // serial Materials infos contained in CMeshBase.
02629     CMeshBase::serialMeshBase(f);
02630 
02631 
02632     // serial geometry.
02633     _MeshGeom->serial(f);
02634 
02635     // if reading, compile some stuff
02636     if(f.isReading())
02637         compileRunTime();
02638 }
02639 
02640 
02641 // ***************************************************************************
02642 const NLMISC::CAABBoxExt& CMesh::getBoundingBox() const
02643 {
02644     return _MeshGeom->getBoundingBox();
02645 }
02646 // ***************************************************************************
02647 const CVertexBuffer &CMesh::getVertexBuffer() const
02648 {
02649     return _MeshGeom->getVertexBuffer() ;
02650 }
02651 // ***************************************************************************
02652 uint CMesh::getNbMatrixBlock() const
02653 {
02654     return _MeshGeom->getNbMatrixBlock();
02655 }
02656 // ***************************************************************************
02657 uint CMesh::getNbRdrPass(uint matrixBlockIndex) const
02658 {
02659     return _MeshGeom->getNbRdrPass(matrixBlockIndex) ;
02660 }
02661 // ***************************************************************************
02662 const CIndexBuffer &CMesh::getRdrPassPrimitiveBlock(uint matrixBlockIndex, uint renderingPassIndex) const
02663 {
02664     return _MeshGeom->getRdrPassPrimitiveBlock(matrixBlockIndex, renderingPassIndex) ;
02665 }
02666 // ***************************************************************************
02667 uint32 CMesh::getRdrPassMaterial(uint matrixBlockIndex, uint renderingPassIndex) const
02668 {
02669     return _MeshGeom->getRdrPassMaterial(matrixBlockIndex, renderingPassIndex) ;
02670 }
02671 // ***************************************************************************
02672 float   CMesh::getNumTriangles (float distance)
02673 {
02674     // A CMesh do not degrad himself, so return 0, to not be taken into account.
02675     return 0;
02676 }
02677 // ***************************************************************************
02678 const   CMeshGeom& CMesh::getMeshGeom () const
02679 {
02680     return *_MeshGeom;
02681 }
02682 // ***************************************************************************
02683 void    CMesh::computeBonesId (CSkeletonModel *skeleton)
02684 {
02685     nlassert (_MeshGeom);
02686     _MeshGeom->computeBonesId (skeleton);
02687 }
02688 
02689 
02690 // ***************************************************************************
02691 void    CMesh::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
02692 {
02693     nlassert (_MeshGeom);
02694     _MeshGeom->updateSkeletonUsage(sm, increment);
02695 }
02696 
02697 // ***************************************************************************
02698 IMeshGeom   *CMesh::supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const
02699 {
02700     // Ok if meshGeom is ok.
02701     if(_MeshGeom->supportMeshBlockRendering())
02702     {
02703         polygonCount= 0;
02704         return _MeshGeom;
02705     }
02706     else
02707         return NULL;
02708 }
02709 
02710 
02711 // ***************************************************************************
02712 void    CMesh::profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, bool passOpaque)
02713 {
02714     // 0 or 0xFFFFFFFF
02715     uint32  mask= (0-(uint32)passOpaque);
02716     uint32  rdrFlags;
02717     // select rdrFlags, without ifs.
02718     rdrFlags=   mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
02719     rdrFlags|=  ~mask & (IMeshGeom::RenderTransparentMaterial);
02720     // render the mesh
02721     _MeshGeom->profileSceneRender(rdrTrav, trans, 0, rdrFlags);
02722 }
02723 
02724 // ***************************************************************************
02725 void    CMesh::compileRunTime()
02726 {
02727     /* ***********************************************
02728      *  WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
02729      *  It can be loaded/called through CAsyncFileManager for instance
02730      * ***********************************************/
02731 
02732     // **** try to build a Visual Collision Mesh
02733     // clear first
02734     if(_VisualCollisionMesh)
02735     {
02736         delete _VisualCollisionMesh;
02737         _VisualCollisionMesh= NULL;
02738     }
02739     // build only if wanted
02740     if( (_CollisionMeshGeneration==AutoCameraCol && !_LightInfos.empty()) ||
02741         _CollisionMeshGeneration==ForceCameraCol )
02742     {
02743 
02744         vector<CVector>     vertices;
02745         vector<uint32>      indices;
02746         if(_MeshGeom->retrieveVertices(vertices) && _MeshGeom->retrieveTriangles(indices))
02747         {
02748             // ok, can build!
02749             _VisualCollisionMesh= new CVisualCollisionMesh;
02750             // if fails to build cause of too many vertices/indices for instance
02751             if( !_VisualCollisionMesh->build(vertices, indices,const_cast<CVertexBuffer&>(_MeshGeom->getVertexBuffer())) )
02752             {
02753                 // delete
02754                 delete _VisualCollisionMesh;
02755                 _VisualCollisionMesh= NULL;
02756             }
02757         }
02758     }
02759 }
02760 
02761 // ***************************************************************************
02762 void    CMesh::buildSystemGeometry()
02763 {
02764     // clear any
02765     _SystemGeometry.clear();
02766 
02767     // don't build a system copy if skinned. In this case, ray intersection is done through CSkeletonModel
02768     // and intersectSkin() scheme
02769     if(_MeshGeom->isSkinned())
02770         return;
02771 
02772     // retrieve geometry (if VB/IB not resident)
02773     if( !_MeshGeom->retrieveVertices(_SystemGeometry.Vertices) ||
02774         !_MeshGeom->retrieveTriangles(_SystemGeometry.Triangles))
02775     {
02776         _SystemGeometry.clear();
02777     }
02778 
02779     // TestYoyo
02780     /*static uint32 totalMem= 0;
02781     totalMem+= _SystemGeometry.Vertices.size()*sizeof(CVector);
02782     totalMem+= _SystemGeometry.Triangles.size()*sizeof(uint32);
02783     nlinfo("CMesh: TotalMem: %d", totalMem);*/
02784 }
02785 
02786 
02787 } // NL3D
02788 
02789 
02790 

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