From 0ea5fc66924303d1bf73ba283a383e2aadee02f2 Mon Sep 17 00:00:00 2001 From: neodarz Date: Sat, 11 Aug 2018 20:21:34 +0200 Subject: Initial commit --- docs/doxygen/nel/mesh_8cpp-source.html | 2421 ++++++++++++++++++++++++++++++++ 1 file changed, 2421 insertions(+) create mode 100644 docs/doxygen/nel/mesh_8cpp-source.html (limited to 'docs/doxygen/nel/mesh_8cpp-source.html') diff --git a/docs/doxygen/nel/mesh_8cpp-source.html b/docs/doxygen/nel/mesh_8cpp-source.html new file mode 100644 index 00000000..a80456a6 --- /dev/null +++ b/docs/doxygen/nel/mesh_8cpp-source.html @@ -0,0 +1,2421 @@ + + + + nevrax.org : docs + + + + + + + + + + + + + + +
# Home   # nevrax.com   
+ + + + +
Nevrax
+ + + + + + + + + + +
+ + +
+ Nevrax.org
+ + + + + + + +
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
+
+ + +
+ + +
+Docs + +
+  + + + + + +
Documentation 
+ +
+Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  
+

mesh.cpp

Go to the documentation of this file.
00001 
+00007 /* Copyright, 2000 Nevrax Ltd.
+00008  *
+00009  * This file is part of NEVRAX NEL.
+00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
+00011  * it under the terms of the GNU General Public License as published by
+00012  * the Free Software Foundation; either version 2, or (at your option)
+00013  * any later version.
+00014 
+00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
+00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
+00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+00018  * General Public License for more details.
+00019 
+00020  * You should have received a copy of the GNU General Public License
+00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
+00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+00023  * MA 02111-1307, USA.
+00024  */
+00025 
+00026 #include "std3d.h"
+00027 
+00028 #include "3d/mesh.h"
+00029 #include "3d/mesh_instance.h"
+00030 #include "3d/scene.h"
+00031 #include "3d/skeleton_model.h"
+00032 #include "3d/mesh_morpher.h"
+00033 #include "nel/misc/bsphere.h"
+00034 #include "3d/stripifier.h"
+00035 #include "3d/fast_floor.h"
+00036 #include "nel/misc/hierarchical_timer.h"
+00037 #include "3d/mesh_blender.h"
+00038 #include "3d/matrix_3x4.h"
+00039 #include "3d/render_trav.h"
+00040 
+00041 
+00042 using namespace std;
+00043 using namespace NLMISC;
+00044 
+00045 
+00046 namespace NL3D 
+00047 {
+00048 
+00049 
+00050 // ***************************************************************************
+00051 // ***************************************************************************
+00052 // MeshGeom Tools.
+00053 // ***************************************************************************
+00054 // ***************************************************************************
+00055 
+00056 
+00057 // ***************************************************************************
+00058 static  NLMISC::CAABBoxExt      makeBBox(const std::vector<CVector>     &Vertices)
+00059 {
+00060         NLMISC::CAABBox         ret;
+00061         nlassert(Vertices.size());
+00062         ret.setCenter(Vertices[0]);
+00063         for(sint i=0;i<(sint)Vertices.size();i++)
+00064         {
+00065                 ret.extend(Vertices[i]);
+00066         }
+00067 
+00068         return ret;
+00069 }
+00070 
+00071 
+00072 // ***************************************************************************
+00073 sint    CMeshGeom::CCornerTmp::Flags=0;
+00074 
+00075 
+00076 // ***************************************************************************
+00077 bool    CMeshGeom::CCornerTmp::operator<(const CCornerTmp &c) const
+00078 {
+00079         sint    i;
+00080 
+00081         // Vert first.
+00082         if(Vertex!=c.Vertex)
+00083                 return Vertex<c.Vertex;
+00084 
+00085         // Order: normal, uvs, color0, color1, skinning.
+00086         if((CCornerTmp::Flags & CVertexBuffer::NormalFlag) && Normal!=c.Normal)
+00087                 return Normal<c.Normal;
+00088         for(i=0; i<CVertexBuffer::MaxStage; i++)
+00089         {
+00090                 if((CCornerTmp::Flags & (CVertexBuffer::TexCoord0Flag<<i)) && Uvws[i]!=c.Uvws[i])
+00091                         return Uvws[i]<c.Uvws[i];
+00092         }
+00093         if((CCornerTmp::Flags & CVertexBuffer::PrimaryColorFlag) && Color!=c.Color)
+00094                 return Color<c.Color;
+00095         if((CCornerTmp::Flags & CVertexBuffer::SecondaryColorFlag) && Specular!=c.Specular)
+00096                 return Specular<c.Specular;
+00097 
+00098         if ((CCornerTmp::Flags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag)
+00099         {
+00100                 for(i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
+00101                 {
+00102                         if(Palette.MatrixId[i] != c.Palette.MatrixId[i])
+00103                                 return Palette.MatrixId[i] < c.Palette.MatrixId[i];
+00104                         if(Weights[i] != c.Weights[i])
+00105                                 return Weights[i] < c.Weights[i];
+00106                 }
+00107         }
+00108 
+00109 
+00110         // All are equal!!
+00111         return false;
+00112 }
+00113 
+00114 
+00115 // ***************************************************************************
+00116 // ***************************************************************************
+00117 // CMeshGeom.
+00118 // ***************************************************************************
+00119 // ***************************************************************************
+00120 
+00121 
+00122 // ***************************************************************************
+00123 CMeshGeom::CMeshGeom()
+00124 {
+00125         _Skinned= false;
+00126         _OriginalSkinRestored= true;
+00127         _VertexBufferHardDirty= true;
+00128         _MeshMorpher = new CMeshMorpher;
+00129         _BoneIdComputed = false;
+00130         _BoneIdExtended= false;
+00131         _PreciseClipping= false;
+00132 }
+00133 
+00134 
+00135 // ***************************************************************************
+00136 CMeshGeom::~CMeshGeom()
+00137 {
+00138         // test (refptr) if the object still exist in memory.
+00139         if(_VertexBufferHard!=NULL)
+00140         {
+00141                 // A vbufferhard should still exist only if driver still exist.
+00142                 nlassert(_Driver!=NULL);
+00143 
+00144                 // delete it from driver.
+00145                 _Driver->deleteVertexBufferHard(_VertexBufferHard);
+00146                 _VertexBufferHard= NULL;
+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         // Dirt the VBuffer.
+00177         _VertexBufferHardDirty= true;
+00178 
+00179         // Empty geometry?
+00180         if(m.Vertices.size()==0 || m.Faces.size()==0)
+00181         {
+00182                 _VBuffer.setNumVertices(0);
+00183                 _VBuffer.reserve(0);
+00184                 _MatrixBlocks.clear();
+00185                 _BBox.setCenter(CVector::Null);
+00186                 _BBox.setSize(CVector::Null);
+00187                 return;
+00188         }
+00189         nlassert(numMaxMaterial>0);
+00190 
+00191 
+00193         //======================
+00194         _BBox= makeBBox(m.Vertices);
+00195 
+00196 
+00198         //================================================
+00199 
+00200         // First, copy Face array.
+00201         vector<CFaceTmp>        tmpFaces;
+00202         tmpFaces.resize(m.Faces.size());
+00203         for(i=0;i<(sint)tmpFaces.size();i++)
+00204                 tmpFaces[i]= m.Faces[i];
+00205 
+00206         _Skinned= ((m.VertexFlags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag);
+00207         // Skinning is OK only if SkinWeights are of same size as vertices.
+00208         _Skinned= _Skinned && (m.Vertices.size()==m.SkinWeights.size());
+00209 
+00210         // If skinning is KO, remove the Skin option.
+00211         uint    vbFlags= m.VertexFlags;
+00212         if(!_Skinned)
+00213                 vbFlags&= ~CVertexBuffer::PaletteSkinFlag;
+00214         // Force presence of vertex.
+00215         vbFlags|= CVertexBuffer::PositionFlag;
+00216 
+00217 
+00218         // If the mesh is not skinned, we have just 1 _MatrixBlocks.
+00219         if(!_Skinned)
+00220         {
+00221                 _MatrixBlocks.resize(1);
+00222                 // For each faces, assign it to the matrix block 0.
+00223                 for(i=0;i<(sint)tmpFaces.size();i++)
+00224                         tmpFaces[i].MatrixBlockId= 0;
+00225         }
+00226         // Else We must group/compute the matrixs blocks.
+00227         else
+00228         {
+00229                 // reset matrix blocks.
+00230                 _MatrixBlocks.clear();
+00231                 // build matrix blocks, and link faces to good matrix blocks.
+00232                 buildSkin(m, tmpFaces);
+00233         }
+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 
+00335                 for(i=0;i<(sint)_MatrixBlocks[mb].RdrPass.size(); i++)
+00336                 {
+00337                         _MatrixBlocks[mb].RdrPass[i].MaterialId= i;
+00338                 }
+00339         }
+00340 
+00341         
+00343         //===================================================
+00344         pFace= &(*tmpFaces.begin());
+00345         N= tmpFaces.size();
+00346         for(;N>0;N--, pFace++)
+00347         {
+00348                 sint    mbId= pFace->MatrixBlockId;
+00349                 nlassert(mbId>=0 && mbId<(sint)_MatrixBlocks.size());
+00350                 // Insert the face in good MatrixBlock/RdrPass.
+00351                 _MatrixBlocks[mbId].RdrPass[pFace->MaterialId].PBlock.addTri(pFace->Corner[0].VBId, pFace->Corner[1].VBId, pFace->Corner[2].VBId);
+00352         }
+00353 
+00354 
+00356         //============================
+00357         for(mb= 0;mb<_MatrixBlocks.size();mb++)
+00358         {
+00359                 // NB: slow process (erase from a vector). Doens't matter since made at build.
+00360                 vector<CRdrPass>::iterator      itPass;
+00361                 for( itPass=_MatrixBlocks[mb].RdrPass.begin(); itPass!=_MatrixBlocks[mb].RdrPass.end(); )
+00362                 {
+00363                         // If this pass is empty, remove it.
+00364                         if( itPass->PBlock.getNumTri()==0 )
+00365                                 itPass= _MatrixBlocks[mb].RdrPass.erase(itPass);
+00366                         else
+00367                                 itPass++;
+00368                 }
+00369         }
+00370 
+00372         //============================
+00373         // BShapes
+00374         this->_MeshMorpher->BlendShapes = m.BlendShapes;
+00375 
+00376         // sort triangles for better cache use.
+00377         optimizeTriangleOrder();
+00378 
+00379         // SmartPtr Copy VertexProgram effect.
+00380         this->_MeshVertexProgram= m.MeshVertexProgram;
+00381 
+00383         //=================================================     
+00384 
+00385         // If skinned
+00386         if(_Skinned)
+00387         {
+00388                 // Reserve some space
+00389                 _BonesName.reserve (m.BonesNames.size ());
+00390 
+00391                 // Current local bone
+00392                 uint currentBone = 0;
+00393 
+00394                 // For each matrix block
+00395                 uint matrixBlock;
+00396                 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
+00397                 {
+00398                         // Ref on the matrix block
+00399                         CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
+00400 
+00401                         // Remap the skeleton index in model index
+00402                         std::map<uint, uint> remap;
+00403 
+00404                         // For each matrix
+00405                         uint matrix;
+00406                         for (matrix=0; matrix<mb.NumMatrix; matrix++)
+00407                         {
+00408                                 // Get bone id in the skeleton
+00409                                 std::map<uint, uint>::iterator ite = remap.find (mb.MatrixId[matrix]);
+00410 
+00411                                 // Not found
+00412                                 if (ite == remap.end())
+00413                                 {
+00414                                         // Insert it
+00415                                         remap.insert (std::map<uint, uint>::value_type (mb.MatrixId[matrix], currentBone));
+00416 
+00417                                         // Check the matrix id
+00418                                         nlassert (mb.MatrixId[matrix] < m.BonesNames.size());
+00419 
+00420                                         // Set the bone name
+00421                                         _BonesName.push_back (m.BonesNames[mb.MatrixId[matrix]]);
+00422 
+00423                                         // Set the id in local
+00424                                         mb.MatrixId[matrix] = currentBone++;
+00425                                 }
+00426                                 else
+00427                                 {
+00428                                         // Set the id in local
+00429                                         mb.MatrixId[matrix] = ite->second;
+00430                                 }
+00431                         }
+00432                 }
+00433 
+00434                 // Bone id in local
+00435                 _BoneIdComputed = false;
+00436                 _BoneIdExtended = false;
+00437         }
+00438 
+00439 
+00440         // End!!
+00441         // Some runtime not serialized compilation
+00442         compileRunTime();
+00443 }
+00444 
+00445 // ***************************************************************************
+00446 void CMeshGeom::setBlendShapes(std::vector<CBlendShape>&bs)
+00447 {
+00448         _MeshMorpher->BlendShapes = bs;
+00449         // must update some RunTime parameters
+00450         compileRunTime();
+00451 }
+00452 
+00453 
+00454 // ***************************************************************************
+00455 void    CMeshGeom::applyMaterialRemap(const std::vector<sint> &remap)
+00456 {
+00457         for(uint mb=0;mb<getNbMatrixBlock();mb++)
+00458         {
+00459                 for(uint rp=0;rp<getNbRdrPass(mb);rp++)
+00460                 {
+00461                         // remap
+00462                         uint32  &matId= _MatrixBlocks[mb].RdrPass[rp].MaterialId;
+00463                         nlassert(remap[matId]>=0);
+00464                         matId= remap[matId];
+00465                 }
+00466         }
+00467 }
+00468 
+00469 
+00470 // ***************************************************************************
+00471 void    CMeshGeom::initInstance(CMeshBaseInstance *mbi)
+00472 {
+00473         // init the instance with _MeshVertexProgram infos
+00474         if(_MeshVertexProgram)
+00475                 _MeshVertexProgram->initInstance(mbi);
+00476 }
+00477 
+00478 // ***************************************************************************
+00479 bool    CMeshGeom::clip(const std::vector<CPlane>       &pyramid, const CMatrix &worldMatrix)
+00480 {
+00481         // Speed Clip: clip just the sphere.
+00482         CBSphere        localSphere(_BBox.getCenter(), _BBox.getRadius());
+00483         CBSphere        worldSphere;
+00484 
+00485         // transform the sphere in WorldMatrix (with nearly good scale info).
+00486         localSphere.applyTransform(worldMatrix, worldSphere);
+00487 
+00488         // if out of only plane, entirely out.
+00489         for(sint i=0;i<(sint)pyramid.size();i++)
+00490         {
+00491                 // We are sure that pyramid has normalized plane normals.
+00492                 // if SpherMax OUT return false.
+00493                 float   d= pyramid[i]*worldSphere.Center;
+00494                 if(d>worldSphere.Radius)
+00495                         return false;
+00496         }
+00497 
+00498         // test if must do a precise clip, according to mesh size.
+00499         if( _PreciseClipping )
+00500         {
+00501                 CPlane  localPlane;
+00502 
+00503                 // if out of only plane, entirely out.
+00504                 for(sint i=0;i<(sint)pyramid.size();i++)
+00505                 {
+00506                         // Transform the pyramid in Object space.
+00507                         localPlane= pyramid[i]*worldMatrix;
+00508                         // localPlane must be normalized, because worldMatrix mya have a scale.
+00509                         localPlane.normalize();
+00510                         // if the box is not partially inside the plane, quit
+00511                         if( !_BBox.clipBack(localPlane) )
+00512                                 return false;
+00513                 }
+00514         }
+00515 
+00516         return true;
+00517 }
+00518 
+00519 // ***************************************************************************
+00520 void    CMeshGeom::updateVertexBufferHard(IDriver *drv)
+00521 {
+00522         if(!drv->supportVertexBufferHard())
+00523                 return;
+00524 
+00525 
+00526         /* If the mesh is skinned, still use normal CVertexBuffer.
+00527          * \todo yoyo: optimize. not done now because CMesh Skinned are not so used in game, 
+00528          *      and CMesh skinning is far not optimized (4 matrix mul all the time). Should use later the renderSkinGroupGeom()
+00529          *      scheme
+00530          *      Also, if the driver has slow VBhard unlock()  (ie ATI gl extension), avoid use of them if MeshMorpher 
+00531          *      is used.
+00532          */
+00533         bool    avoidVBHard;
+00534         avoidVBHard= _Skinned || ( _MeshMorpher && _MeshMorpher->BlendShapes.size()>0 && drv->slowUnlockVertexBufferHard() );
+00535         if( _VertexBufferHardDirty && avoidVBHard )
+00536         {
+00537                 // delete possible old VBHard.
+00538                 if(_VertexBufferHard!=NULL)
+00539                 {
+00540                         // VertexBufferHard lifetime < Driver lifetime.
+00541                         nlassert(_Driver!=NULL);
+00542                         _Driver->deleteVertexBufferHard(_VertexBufferHard);
+00543                 }
+00544                 return;
+00545         }
+00546 
+00547         // If the vbufferhard is not synced to the vbuffer.
+00548         if(_VertexBufferHardDirty || _VertexBufferHard==NULL)
+00549         {
+00550                 _VertexBufferHardDirty= false;
+00551 
+00552                 // delete possible old VBHard.
+00553                 if(_VertexBufferHard!=NULL)
+00554                 {
+00555                         // VertexBufferHard lifetime < Driver lifetime.
+00556                         nlassert(_Driver!=NULL);
+00557                         _Driver->deleteVertexBufferHard(_VertexBufferHard);
+00558                 }
+00559 
+00560                 // bkup drv in a refptr. (so we know if the vbuffer hard has to be deleted).
+00561                 _Driver= drv;
+00562                 // try to create new one, in AGP Ram
+00563                 _VertexBufferHard= _Driver->createVertexBufferHard(_VBuffer.getVertexFormat(), _VBuffer.getValueTypePointer (), _VBuffer.getNumVertices(), IDriver::VBHardAGP);
+00564 
+00565                 // If KO, use normal VertexBuffer.
+00566                 if(_VertexBufferHard==NULL)
+00567                         return;
+00568                 // else, Fill it with VertexBuffer.
+00569                 else
+00570                 {
+00571                         void    *vertexPtr= _VertexBufferHard->lock();
+00572 
+00573                         nlassert(_VBuffer.getVertexFormat() == _VertexBufferHard->getVertexFormat());
+00574                         nlassert(_VBuffer.getNumVertices() == _VertexBufferHard->getNumVertices());
+00575                         nlassert(_VBuffer.getVertexSize() == _VertexBufferHard->getVertexSize());
+00576 
+00577                         // \todo yoyo: TODO_DX8 and DX8 ???
+00578                         // Because same internal format, just copy all block.
+00579                         memcpy(vertexPtr, _VBuffer.getVertexCoordPointer(), _VBuffer.getNumVertices() * _VBuffer.getVertexSize() );
+00580 
+00581                         _VertexBufferHard->unlock();
+00582                 }
+00583 
+00584         }
+00585 }
+00586 
+00587 
+00588 // ***************************************************************************
+00589 void    CMeshGeom::render(IDriver *drv, CTransformShape *trans, float polygonCount, uint32 rdrFlags, float globalAlpha)
+00590 {
+00591         nlassert(drv);
+00592         // get the mesh instance.
+00593         CMeshBaseInstance       *mi= safe_cast<CMeshBaseInstance*>(trans);
+00594         // get a ptr on scene
+00595         CScene                  *ownerScene= mi->getScene();
+00596         // get a ptr on renderTrav
+00597         CRenderTrav             *renderTrav= ownerScene->getRenderTrav();
+00598 
+00599 
+00600         // update the VBufferHard (create/delete), to maybe render in AGP memory.
+00601         updateVertexBufferHard (drv);
+00602         /* currentVBHard is NULL if must disable it temporarily
+00603                 For now, never disable it, but switch of VBHard may be VERY EXPENSIVE if NV_vertex_array_range2 is not
+00604                 supported (old drivers).
+00605         */
+00606         IVertexBufferHard               *currentVBHard= _VertexBufferHard;
+00607 
+00608 
+00609         // get the skeleton model to which I am binded (else NULL).
+00610         CSkeletonModel          *skeleton;
+00611         skeleton= mi->getSkeletonModel();
+00612         // The mesh must not be skinned for render()
+00613         nlassert(!(_Skinned && mi->isSkinned() && skeleton));
+00614         bool bMorphApplied = _MeshMorpher->BlendShapes.size() > 0;
+00615         bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
+00616 
+00617 
+00618         // Profiling
+00619         //===========
+00620         H_AUTO( NL3D_MeshGeom_RenderNormal );
+00621 
+00622 
+00623         // Morphing
+00624         // ========
+00625         if (bMorphApplied)
+00626         {
+00627                 // If _Skinned (NB: the skin is not applied) and if lod.OriginalSkinRestored, then restoreOriginalSkinPart is
+00628                 // not called but mush morpher write changed vertices into VBHard so its ok. The unchanged vertices
+00629                 // are written in the preceding call to restoreOriginalSkinPart.
+00630                 if (_Skinned)
+00631                 {
+00632                         _MeshMorpher->initSkinned(&_VBufferOri,
+00633                                                                  &_VBuffer,
+00634                                                                  currentVBHard,
+00635                                                                  useTangentSpace,
+00636                                                                  &_OriginalSkinVertices,
+00637                                                                  &_OriginalSkinNormals,
+00638                                                                  useTangentSpace ? &_OriginalTGSpace : NULL,
+00639                                                                  false );
+00640                         _MeshMorpher->updateSkinned (mi->getBlendShapeFactors());
+00641                 }
+00642                 else // Not even skinned so we have to do all the stuff
+00643                 {
+00644                         _MeshMorpher->init(&_VBufferOri,
+00645                                                                  &_VBuffer,
+00646                                                                  currentVBHard,
+00647                                                                  useTangentSpace);
+00648                         _MeshMorpher->update (mi->getBlendShapeFactors());
+00649                 }
+00650         }
+00651 
+00652 
+00653         // Skinning
+00654         // ========
+00655 
+00656         // else setup instance matrix
+00657         drv->setupModelMatrix(trans->getWorldMatrix());
+00658 
+00659 
+00660         // since instance skin is invalid but mesh is skinned , we must copy vertices/normals from original vertices.
+00661         if (_Skinned)
+00662         {
+00663                 // do it for this Lod only, and if cache say it is necessary.
+00664                 if (!_OriginalSkinRestored)
+00665                         restoreOriginalSkinVertices();
+00666         }
+00667 
+00668 
+00669         // Setup meshVertexProgram
+00670         //===========
+00671 
+00672         // use MeshVertexProgram effect?
+00673         bool    useMeshVP= _MeshVertexProgram != NULL;
+00674         if( useMeshVP )
+00675         {
+00676                 CMatrix         invertedObjectMatrix;
+00677                 invertedObjectMatrix = trans->getWorldMatrix().inverted();
+00678                 // really ok if success to begin VP
+00679                 useMeshVP= _MeshVertexProgram->begin(drv, ownerScene, mi, invertedObjectMatrix, renderTrav->CamPos);
+00680         }
+00681         
+00682 
+00683         // Render the mesh.
+00684         //===========
+00685         // active VB.
+00686         if(currentVBHard != NULL)
+00687                 drv->activeVertexBufferHard(currentVBHard);
+00688         else
+00689                 drv->activeVertexBuffer(_VBuffer);
+00690 
+00691 
+00692         // Global alpha used ?
+00693         uint32  globalAlphaUsed= rdrFlags & IMeshGeom::RenderGlobalAlpha;
+00694         uint8   globalAlphaInt=(uint8)OptFastFloor(globalAlpha*255);
+00695 
+00696 
+00697         // For all _MatrixBlocks
+00698         for(uint mb=0;mb<_MatrixBlocks.size();mb++)
+00699         {
+00700                 CMatrixBlock    &mBlock= _MatrixBlocks[mb];
+00701                 if(mBlock.RdrPass.size()==0)
+00702                         continue;
+00703 
+00704                 // Global alpha ?
+00705                 if (globalAlphaUsed)
+00706                 {
+00707                         bool    gaDisableZWrite= (rdrFlags & IMeshGeom::RenderGADisableZWrite)?true:false;
+00708 
+00709                         // Render all pass.
+00710                         for (uint i=0;i<mBlock.RdrPass.size();i++)
+00711                         {
+00712                                 CRdrPass        &rdrPass= mBlock.RdrPass[i];
+00713                                 // Render with the Materials of the MeshInstance.
+00714                                 if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
+00715                                          ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
+00716                                 {
+00717                                         // CMaterial Ref
+00718                                         CMaterial &material=mi->Materials[rdrPass.MaterialId];
+00719 
+00720                                         // Use a MeshBlender to modify material and driver.
+00721                                         CMeshBlender    blender;
+00722                                         blender.prepareRenderForGlobalAlpha(material, drv, globalAlpha, globalAlphaInt, gaDisableZWrite);
+00723 
+00724                                         // Setup VP material
+00725                                         if (useMeshVP)
+00726                                         {
+00727                                                 if(currentVBHard)
+00728                                                         _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, currentVBHard);
+00729                                                 else
+00730                                                         _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
+00731                                         }
+00732 
+00733                                         // Render
+00734                                         drv->render(rdrPass.PBlock, material);
+00735 
+00736                                         // Resetup material/driver
+00737                                         blender.restoreRender(material, drv, gaDisableZWrite);
+00738                                 }
+00739                         }
+00740                 }
+00741                 else
+00742                 {
+00743                         // Render all pass.
+00744                         for(uint i=0;i<mBlock.RdrPass.size();i++)
+00745                         {
+00746                                 CRdrPass        &rdrPass= mBlock.RdrPass[i];
+00747                                 // Render with the Materials of the MeshInstance.
+00748                                 if( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
+00749                                         ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) )         )
+00750                                 {
+00751                                         // CMaterial Ref
+00752                                         CMaterial &material=mi->Materials[rdrPass.MaterialId];
+00753 
+00754                                         // Setup VP material
+00755                                         if (useMeshVP)
+00756                                         {
+00757                                                 if(currentVBHard)
+00758                                                         _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, currentVBHard);
+00759                                                 else
+00760                                                         _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
+00761                                         }                                                                       
+00762 
+00763                                         // render primitives
+00764                                         drv->render(rdrPass.PBlock, material);
+00765                                 }
+00766                         }
+00767                 }
+00768         }
+00769 
+00770         // End VertexProgram effect
+00771         if(useMeshVP)
+00772         {
+00773                 // Apply it.
+00774                 _MeshVertexProgram->end(drv);
+00775         }
+00776 }
+00777 
+00778 
+00779 // ***************************************************************************
+00780 void    CMeshGeom::renderSkin(CTransformShape *trans, float alphaMRM)
+00781 {
+00782         // get the mesh instance.
+00783         CMeshBaseInstance       *mi= safe_cast<CMeshBaseInstance*>(trans);
+00784         // get a ptr on scene
+00785         CScene                  *ownerScene= mi->getScene();
+00786         // get a ptr on renderTrav
+00787         CRenderTrav             *renderTrav= ownerScene->getRenderTrav();
+00788         // get a ptr on the driver
+00789         IDriver                 *drv= renderTrav->getDriver();
+00790         nlassert(drv);
+00791 
+00792 
+00793         // update the VBufferHard (create/delete), to maybe render in AGP memory.
+00794         updateVertexBufferHard (drv);
+00795         /* currentVBHard is NULL if must disable it temporarily
+00796                 For now, never disable it, but switch of VBHard may be VERY EXPENSIVE if NV_vertex_array_range2 is not
+00797                 supported (old drivers).
+00798         */
+00799         IVertexBufferHard               *currentVBHard= _VertexBufferHard;
+00800 
+00801 
+00802         // get the skeleton model to which I am binded (else NULL).
+00803         CSkeletonModel          *skeleton;
+00804         skeleton= mi->getSkeletonModel();
+00805         // must be skinned for renderSkin()
+00806         nlassert(_Skinned && mi->isSkinned() && skeleton);
+00807         bool bMorphApplied = _MeshMorpher->BlendShapes.size() > 0;
+00808         bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
+00809 
+00810 
+00811         // Profiling
+00812         //===========
+00813         H_AUTO( NL3D_MeshGeom_RenderSkinned );
+00814 
+00815 
+00816         // Morphing
+00817         // ========
+00818         if (bMorphApplied)
+00819         {
+00820                 // Since Skinned we must update original skin vertices and normals because skinning use it
+00821                 _MeshMorpher->initSkinned(&_VBufferOri,
+00822                                                          &_VBuffer,
+00823                                                          currentVBHard,
+00824                                                          useTangentSpace,
+00825                                                          &_OriginalSkinVertices,
+00826                                                          &_OriginalSkinNormals,
+00827                                                          useTangentSpace ? &_OriginalTGSpace : NULL,
+00828                                                          true );
+00829                 _MeshMorpher->updateSkinned (mi->getBlendShapeFactors());
+00830         }
+00831 
+00832 
+00833         // Skinning
+00834         // ========
+00835 
+00836         // NB: the skeleton matrix has already been setuped by CSkeletonModel
+00837         // NB: the normalize flag has already been setuped by CSkeletonModel
+00838 
+00839 
+00840         // apply the skinning: _VBuffer is modified.
+00841         applySkin(skeleton);
+00842 
+00843 
+00844         // Setup meshVertexProgram
+00845         //===========
+00846 
+00847         // use MeshVertexProgram effect?
+00848         bool    useMeshVP= _MeshVertexProgram != NULL;
+00849         if( useMeshVP )
+00850         {
+00851                 CMatrix         invertedObjectMatrix;
+00852                 invertedObjectMatrix = skeleton->getWorldMatrix().inverted();
+00853                 // really ok if success to begin VP
+00854                 useMeshVP= _MeshVertexProgram->begin(drv, ownerScene, mi, invertedObjectMatrix, renderTrav->CamPos);
+00855         }
+00856         
+00857 
+00858         // Render the mesh.
+00859         //===========
+00860         // active VB.
+00861         if(currentVBHard != NULL)
+00862                 drv->activeVertexBufferHard(currentVBHard);
+00863         else
+00864                 drv->activeVertexBuffer(_VBuffer);
+00865 
+00866 
+00867         // For all _MatrixBlocks
+00868         for(uint mb=0;mb<_MatrixBlocks.size();mb++)
+00869         {
+00870                 CMatrixBlock    &mBlock= _MatrixBlocks[mb];
+00871                 if(mBlock.RdrPass.size()==0)
+00872                         continue;
+00873 
+00874                 // Render all pass.
+00875                 for(uint i=0;i<mBlock.RdrPass.size();i++)
+00876                 {
+00877                         CRdrPass        &rdrPass= mBlock.RdrPass[i];
+00878 
+00879                         // CMaterial Ref
+00880                         CMaterial &material=mi->Materials[rdrPass.MaterialId];
+00881 
+00882                         // Setup VP material
+00883                         if (useMeshVP)
+00884                         {
+00885                                 if(currentVBHard)
+00886                                         _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, currentVBHard);
+00887                                 else
+00888                                         _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
+00889                         }                                                                       
+00890 
+00891                         // render primitives
+00892                         drv->render(rdrPass.PBlock, material);
+00893                 }
+00894         }
+00895 
+00896         // End VertexProgram effect
+00897         if(useMeshVP)
+00898         {
+00899                 // Apply it.
+00900                 _MeshVertexProgram->end(drv);
+00901         }
+00902 
+00903 }
+00904 
+00905 
+00906 // ***************************************************************************
+00907 void    CMeshGeom::renderSimpleWithMaterial(IDriver *drv, const CMatrix &worldMatrix, CMaterial &mat)
+00908 {
+00909         nlassert(drv);
+00910 
+00911         // setup matrix
+00912         drv->setupModelMatrix(worldMatrix);
+00913 
+00914         // active VB.
+00915         drv->activeVertexBuffer(_VBuffer);
+00916 
+00917         // For all _MatrixBlocks
+00918         for(uint mb=0;mb<_MatrixBlocks.size();mb++)
+00919         {
+00920                 CMatrixBlock    &mBlock= _MatrixBlocks[mb];
+00921                 if(mBlock.RdrPass.size()==0)
+00922                         continue;
+00923 
+00924                 // Render all pass.
+00925                 for(uint i=0;i<mBlock.RdrPass.size();i++)
+00926                 {
+00927                         CRdrPass        &rdrPass= mBlock.RdrPass[i];
+00928 
+00929                         // render primitives
+00930                         drv->render(rdrPass.PBlock, mat);
+00931                 }
+00932         }
+00933 
+00934 }
+00935 
+00936 
+00937 // ***************************************************************************
+00938 void    CMeshGeom::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
+00939 {
+00940         /*
+00941         Version 4:
+00942                 - BonesName.
+00943         Version 3:
+00944                 - MeshVertexProgram.
+00945         Version 2:
+00946                 - precompute of triangle order. (nothing more to load).
+00947         Version 1:
+00948                 - added blend shapes
+00949         Version 0:
+00950                 - separate serialisation CMesh / CMeshGeom.
+00951         */
+00952         sint ver = f.serialVersion (4);
+00953 
+00954 
+00955         // must have good original Skinned Vertex before writing.
+00956         if( !f.isReading() && _Skinned && !_OriginalSkinRestored )
+00957         {
+00958                 restoreOriginalSkinVertices();
+00959         }
+00960 
+00961 
+00962         // Version 4+: Array of bone name
+00963         if (ver >= 4)
+00964         {
+00965                 f.serialCont (_BonesName);
+00966         }
+00967 
+00968         if (f.isReading())
+00969         {
+00970                 // Version3-: Bones index are in skeleton model id list
+00971                 _BoneIdComputed = (ver < 4);
+00972                 // In all case, must recompute usage of parents.
+00973                 _BoneIdExtended= false;
+00974         }
+00975         else
+00976         {
+00977                 // Warning, if you have skinned this shape, you can't write it anymore because skinning id have been changed! 
+00978                 nlassert (_BoneIdComputed==false);
+00979         }
+00980 
+00981         // Version3+: MeshVertexProgram.
+00982         if (ver >= 3)
+00983         {
+00984                 IMeshVertexProgram      *mvp= NULL;
+00985                 if(f.isReading())
+00986                 {
+00987                         f.serialPolyPtr(mvp);
+00988                         _MeshVertexProgram= mvp;
+00989                 }
+00990                 else
+00991                 {
+00992                         mvp= _MeshVertexProgram;
+00993                         f.serialPolyPtr(mvp);
+00994                 }
+00995         }
+00996         else if(f.isReading())
+00997         {
+00998                 // release vp
+00999                 _MeshVertexProgram= NULL;
+01000         }
+01001 
+01002         // Version1+: _MeshMorpher.
+01003         if (ver >= 1)
+01004                 f.serial (*_MeshMorpher);
+01005 
+01006         // serial geometry.
+01007         f.serial (_VBuffer);
+01008         f.serialCont (_MatrixBlocks);
+01009         f.serial (_BBox);
+01010         f.serial (_Skinned);
+01011 
+01012 
+01013         // If _VertexBuffer changed, flag the VertexBufferHard.
+01014         if(f.isReading())
+01015         {
+01016                 _VertexBufferHardDirty = true;
+01017 
+01018                 // if >= version 2, reorder of triangles is precomputed, else compute it now.
+01019                 if(ver < 2 )
+01020                 {
+01021                         optimizeTriangleOrder();
+01022                 }
+01023         }
+01024 
+01025         // Skinning: If Version < 4, _BonesName are not present, must compute _BonesId from localId
+01026         // Else it is computed at first computeBonesId().
+01027         if(ver < 4)
+01028                 buildBoneUsageVer3();
+01029 
+01030         // TestYoyo
+01031         //_MeshVertexProgram= NULL;
+01032         /*{
+01033                 uint numTris= 0;
+01034                 for(uint i=0;i<_MatrixBlocks.size();i++)
+01035                 {
+01036                         for(uint j=0;j<_MatrixBlocks[i].RdrPass.size();j++)
+01037                                 numTris+= _MatrixBlocks[i].RdrPass[j].PBlock.getNumTri();
+01038                 }
+01039                 nlinfo("YOYO: %d Vertices. %d Triangles.", _VBuffer.getNumVertices(), numTris);
+01040         }*/
+01041 
+01042         // Some runtime not serialized compilation
+01043         if(f.isReading())
+01044                 compileRunTime();
+01045 }
+01046 
+01047 
+01048 // ***************************************************************************
+01049 void    CMeshGeom::compileRunTime()
+01050 {
+01051         // if skinned, prepare skinning
+01052         if(_Skinned)
+01053                 bkupOriginalSkinVertices();
+01054 
+01055         // Do precise clipping for big object??
+01056         _PreciseClipping= _BBox.getRadius() >= NL3D_MESH_PRECISE_CLIP_THRESHOLD;
+01057 
+01058         // Support MeshBlockRendering only if not skinned/meshMorphed.
+01059         _SupportMeshBlockRendering= !_Skinned && _MeshMorpher->BlendShapes.size()==0;
+01060 
+01061         // true only if one matrix block, and at least one rdrPass.
+01062         _SupportMeshBlockRendering= _SupportMeshBlockRendering && _MatrixBlocks.size()==1 && _MatrixBlocks[0].RdrPass.size()>0;
+01063 
+01064         // \todo yoyo: support later MeshVertexProgram 
+01065         _SupportMeshBlockRendering= _SupportMeshBlockRendering && _MeshVertexProgram==NULL;
+01066 
+01067         // TestYoyo
+01068         //_SupportMeshBlockRendering= false;
+01069 }
+01070 
+01071 
+01072 // ***************************************************************************
+01073 // ***************************************************************************
+01074 // Skinning.
+01075 // ***************************************************************************
+01076 // ***************************************************************************
+01077 
+01078 
+01079 // ***************************************************************************
+01080 void    CMeshGeom::buildSkin(CMesh::CMeshBuild &m, std::vector<CFaceTmp>        &tmpFaces)
+01081 {
+01082         sint    i,j,k;
+01083         TBoneMap                remainingBones;
+01084         list<uint>              remainingFaces;
+01085 
+01086 
+01087         // 0. normalize SkinWeights: for all weights at 0, copy the matrixId from 0th matrix => no random/bad use of matrix.
+01088         //================================
+01089         for(i=0;i<(sint)m.SkinWeights.size();i++)
+01090         {
+01091                 CMesh::CSkinWeight      &sw= m.SkinWeights[i];
+01092 
+01093                 // 0th weight must not be 0.
+01094                 nlassert(sw.Weights[0]!=0);
+01095 
+01096                 // Begin at 1, tests all other weights.
+01097                 for(j=1;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
+01098                 {
+01099                         // We don't use this entry??
+01100                         if(sw.Weights[j]==0)
+01101                         {
+01102                                 // Setup MatrixId so that this vertex do no use more matrix than it really wants.
+01103                                 sw.MatrixId[j]= sw.MatrixId[0];
+01104                         }
+01105                 }
+01106         }
+01107 
+01108 
+01109         // 1. build the list of used/remaining bones, in ascending order. (so we use the depth-first topolgy of hierarchy).
+01110         //================================
+01111         for(i=0;i<(sint)tmpFaces.size();i++)
+01112         {
+01113                 CFaceTmp        &face= tmpFaces[i];
+01114 
+01115                 for(j=0;j<3;j++)
+01116                 {
+01117                         CMesh::CSkinWeight      &sw= m.SkinWeights[face.Corner[j].Vertex];
+01118                         for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
+01119                         {
+01120                                 // insert (if not already here) the used bone in the set.
+01121                                 // and insert his refcount. (NB: ctor() init it to 0 :) ).
+01122                                 remainingBones[sw.MatrixId[k]].RefCount++;
+01123                         }
+01124                 }
+01125         }
+01126 
+01127 
+01128         // 2. Create the list of un-inserted faces.
+01129         //================================
+01130         for(i=0;i<(sint)tmpFaces.size();i++)
+01131         {
+01132                 remainingFaces.push_back(i);
+01133         }
+01134 
+01135 
+01136 
+01137         // 3. Create as many Blocks as necessary.
+01138         //================================
+01139         // Which bones a face use (up to 12).
+01140         vector<uint>    boneUse;
+01141         boneUse.reserve(NL3D_MESH_SKINNING_MAX_MATRIX*3);
+01142 
+01143         // While still exist faces.
+01144         while(!remainingFaces.empty())
+01145         {
+01146                 // create a new matrix block.
+01147                 _MatrixBlocks.push_back(CMatrixBlock());
+01148                 CMatrixBlock    &matrixBlock= _MatrixBlocks[_MatrixBlocks.size()-1];
+01149                 matrixBlock.NumMatrix=0;
+01150 
+01151                 // a. reset remainingBones as not inserted in the current matrixBlock.
+01152                 //============================
+01153                 ItBoneMap       itBone;
+01154                 for(itBone= remainingBones.begin();itBone!=remainingBones.end();itBone++)
+01155                 {
+01156                         itBone->second.Inserted= false;
+01157                 }
+01158 
+01159 
+01160                 // b. while still exist bones, try to insert faces which use them in matrixBlock.
+01161                 //============================
+01162                 while(!remainingBones.empty())
+01163                 {
+01164                         // get the first bone from the map. (remind: depth-first order).
+01165                         uint            currentBoneId= remainingBones.begin()->first;
+01166 
+01167                         // If no more faces in the remainingFace list use this bone, remove it, and continue.
+01168                         if(remainingBones.begin()->second.RefCount==0)
+01169                         {
+01170                                 remainingBones.erase(remainingBones.begin());
+01171                                 continue;
+01172                         }
+01173 
+01174                         // this is a marker, to know if a face insertion will occurs.
+01175                         bool            faceAdded= false;
+01176 
+01177                         // traverse all faces, trying to insert them in current MatrixBlock processed.
+01178                         list<uint>::iterator    itFace;
+01179                         for(itFace= remainingFaces.begin(); itFace!=remainingFaces.end();)
+01180                         {
+01181                                 bool    useCurrentBoneId;
+01182                                 uint    newBoneAdded;
+01183 
+01184                                 // i/ Get info on current face.
+01185                                 //-----------------------------
+01186 
+01187                                 // build which bones this face use.
+01188                                 tmpFaces[*itFace].buildBoneUse(boneUse, m.SkinWeights);
+01189 
+01190                                 // test if this face use the currentBoneId.
+01191                                 useCurrentBoneId= false;
+01192                                 for(i=0;i<(sint)boneUse.size();i++)
+01193                                 {
+01194                                         // if this face use the currentBoneId
+01195                                         if(boneUse[i]==currentBoneId)
+01196                                         {
+01197                                                 useCurrentBoneId= true;
+01198                                                 break;
+01199                                         }
+01200                                 }
+01201                                 // compute how many bones that are not in the current matrixblock this face use.
+01202                                 newBoneAdded=0;
+01203                                 for(i=0;i<(sint)boneUse.size();i++)
+01204                                 {
+01205                                         // if this bone is not inserted in the current matrix block, inform it.
+01206                                         if(!remainingBones[boneUse[i]].Inserted)
+01207                                                 newBoneAdded++;
+01208                                 }
+01209                                 
+01210                                 
+01211                                 // ii/ insert/reject face.
+01212                                 //------------------------
+01213 
+01214                                 // If this face do not add any more bone, we can insert it into the current matrixblock.
+01215                                 // If it use the currentBoneId, and do not explode max count, we allow insert it too in the current matrixblock.
+01216                                 if( newBoneAdded==0 || 
+01217                                         (useCurrentBoneId && newBoneAdded+matrixBlock.NumMatrix < IDriver::MaxModelMatrix) )
+01218                                 {
+01219                                         // Insert this face in the current matrix block
+01220 
+01221                                         CFaceTmp        &face= tmpFaces[*itFace];
+01222 
+01223                                         // for all vertices of this face.
+01224                                         for(j=0;j<3;j++)
+01225                                         {
+01226                                                 CMesh::CSkinWeight      &sw= m.SkinWeights[face.Corner[j].Vertex];
+01227 
+01228                                                 // for each corner weight (4)
+01229                                                 for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
+01230                                                 {
+01231                                                         // get the global boneId this corner weight use.
+01232                                                         uint            boneId= sw.MatrixId[k];
+01233                                                         // get the CBoneTmp this corner weight use.
+01234                                                         CBoneTmp        &bone= remainingBones[boneId];
+01235 
+01236                                                         // decRef the bone .
+01237                                                         bone.RefCount--;
+01238 
+01239                                                         // Is this bone already inserted in the MatrixBlock ?
+01240                                                         if( !bone.Inserted )
+01241                                                         {
+01242                                                                 // No, insert it.
+01243                                                                 bone.Inserted= true;
+01244                                                                 // link it to the MatrixId in the current matrixBlock.
+01245                                                                 bone.MatrixIdInMB= matrixBlock.NumMatrix;
+01246 
+01247                                                                 // modify the matrixBlock
+01248                                                                 matrixBlock.MatrixId[matrixBlock.NumMatrix]= boneId;
+01249                                                                 // increment the number of matrix in the matrixBlock.
+01250                                                                 matrixBlock.NumMatrix++;
+01251                                                         }
+01252 
+01253                                                         // Copy Weight info for this Corner.
+01254                                                         // Set what matrix in the current matrix block this corner use.
+01255                                                         face.Corner[j].Palette.MatrixId[k]= bone.MatrixIdInMB;
+01256                                                         // Set weight.
+01257                                                         face.Corner[j].Weights[k]= sw.Weights[k];
+01258                                                 }
+01259                                         }
+01260 
+01261                                         // to Which matrixblock this face is inserted.
+01262                                         face.MatrixBlockId= _MatrixBlocks.size()-1;
+01263                                         
+01264                                         // remove the face from remain face list.
+01265                                         itFace= remainingFaces.erase(itFace);
+01266 
+01267                                         // inform the algorithm that a face has been added.
+01268                                         faceAdded= true;
+01269                                 }
+01270                                 else
+01271                                 {
+01272                                         // do not append this face to the current matrix block, skip to the next
+01273                                         itFace++;
+01274                                 }
+01275                         }
+01276 
+01277                         // If no faces have been added during this pass, we are blocked, and either the MatrixBlock may be full,
+01278                         // or there is no more face. So quit this block and process a new one.
+01279                         if(!faceAdded)
+01280                                 break;
+01281                 }
+01282 
+01283         }
+01284         // NB: at the end of this loop, remainingBones may not be empty(), but all remainingBones should have RefCount==0.
+01285 
+01286 
+01287 
+01288         // 4. Re-order matrix use in MatrixBlocks, for minimum matrix change between MatrixBlocks.
+01289         //================================
+01290         vector<CMatrixBlockRemap>       blockRemaps;
+01291         blockRemaps.resize(_MatrixBlocks.size());
+01292 
+01293 
+01294         // For all MatrixBlocks > first, try to "mirror" bones from previous.
+01295         for(i=1;i<(sint)_MatrixBlocks.size();i++)
+01296         {
+01297                 CMatrixBlock            &mBlock= _MatrixBlocks[i];
+01298                 CMatrixBlock            &mPrevBlock= _MatrixBlocks[i-1];
+01299                 CMatrixBlockRemap       &remap= blockRemaps[i];
+01300 
+01301                 // First bkup the bone ids in remap table.
+01302                 for(j=0;j<(sint)mBlock.NumMatrix;j++)
+01303                 {
+01304                         remap.Remap[j]= mBlock.MatrixId[j];
+01305                 }
+01306 
+01307                 // For all ids of this blocks, try to mirror them.
+01308                 for(j=0;j<(sint)mBlock.NumMatrix;j++)
+01309                 {
+01310                         // get the location of this bone in the prev bone.
+01311                         sint    idLoc= mPrevBlock.getMatrixIdLocation(mBlock.MatrixId[j]);
+01312                         // If not found, or if bigger than current array, fails (cant be mirrored).
+01313                         // Or if already mirrored.
+01314                         if(idLoc==-1 || idLoc>=(sint)mBlock.NumMatrix || idLoc==j)
+01315                         {
+01316                                 // next id.
+01317                                 j++;
+01318                         }
+01319                         else
+01320                         {
+01321                                 // puts me on my mirrored location. and swap with the current one at this mirrored location.
+01322                                 swap(mBlock.MatrixId[j], mBlock.MatrixId[idLoc]);
+01323                                 // mBlock.MatrixId[j] is now a candidate for mirror.
+01324                         }
+01325                 }
+01326 
+01327                 // Then build the Remap table, to re-order faces matrixId which use this matrix block.
+01328                 for(j=0;j<(sint)mBlock.NumMatrix;j++)
+01329                 {
+01330                         // get the boneid which was at this position j before.
+01331                         uint    boneId= remap.Remap[j];
+01332                         // search his new position, and store the result in the remap table.
+01333                         remap.Remap[j]= mBlock.getMatrixIdLocation(boneId);
+01334                 }
+01335 
+01336                 // NB: this matrixBlock is re-ordered. next matrixBlock use this state.
+01337         }
+01338 
+01339 
+01340         // For all faces/corners/weights, remap MatrixIds.
+01341         for(i=0;i<(sint)tmpFaces.size();i++)
+01342         {
+01343                 CFaceTmp        &face= tmpFaces[i];
+01344                 // do it but for matrixblock0.
+01345                 if(face.MatrixBlockId!=0)
+01346                 {
+01347                         CMatrixBlockRemap       &remap= blockRemaps[face.MatrixBlockId];
+01348                         // For all corners.
+01349                         for(j=0;j<3;j++)
+01350                         {
+01351                                 for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
+01352                                 {
+01353                                         uint    oldId= face.Corner[j].Palette.MatrixId[k];
+01354                                         face.Corner[j].Palette.MatrixId[k]= (uint8)remap.Remap[oldId];
+01355                                 }
+01356                         }
+01357                 }
+01358         }
+01359 
+01360 }
+01361 
+01362 
+01363 // ***************************************************************************
+01364 void    CMeshGeom::CFaceTmp::buildBoneUse(vector<uint>  &boneUse, vector<CMesh::CSkinWeight> &skinWeights)
+01365 {
+01366         boneUse.clear();
+01367 
+01368         // For the 3 corners of the face.
+01369         for(sint i=0;i<3;i++)
+01370         {
+01371                 // get the CSkinWeight of this vertex.
+01372                 CMesh::CSkinWeight      &sw= skinWeights[Corner[i].Vertex];
+01373 
+01374                 // For all skin weights of this vertex,
+01375                 for(sint j=0;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
+01376                 {
+01377                         uint    boneId= sw.MatrixId[j];
+01378                         // insert (if not in the array) this bone.
+01379                         if( find(boneUse.begin(), boneUse.end(), boneId)==boneUse.end() )
+01380                                 boneUse.push_back(boneId);
+01381                 }
+01382         }
+01383 
+01384 
+01385 }
+01386 
+01387 
+01388 
+01389 // ***************************************************************************
+01390 sint    CMeshGeom::CMatrixBlock::getMatrixIdLocation(uint32 boneId) const
+01391 {
+01392         for(uint i=0;i<NumMatrix;i++)
+01393         {
+01394                 if(MatrixId[i]==boneId)
+01395                         return i;
+01396         }
+01397 
+01398         // not found.
+01399         return -1;
+01400 }
+01401 
+01402 
+01403 // ***************************************************************************
+01404 float   CMeshGeom::getNumTriangles (float distance)
+01405 {
+01406         // Sum of triangles
+01407         uint32 triCount=0;
+01408 
+01409         // For each matrix block
+01410         uint mbCount=_MatrixBlocks.size();
+01411         for (uint mb=0; mb<mbCount; mb++)
+01412         {
+01413                 CMatrixBlock &block=_MatrixBlocks[mb];
+01414 
+01415                 // Count of primitive block
+01416                 uint pCount=block.RdrPass.size();
+01417                 for (uint pb=0; pb<pCount; pb++)
+01418                 {
+01419                         // Ref on the primitive block
+01420                         CRdrPass &pass=block.RdrPass[pb];
+01421 
+01422                         // Sum tri
+01423                         triCount+=pass.PBlock.getNumTriangles ();
+01424                 }
+01425         }
+01426         return (float)triCount;
+01427 }
+01428 
+01429 
+01430 // ***************************************************************************
+01431 void    CMeshGeom::computeBonesId (CSkeletonModel *skeleton)
+01432 {
+01433         // Already computed ?
+01434         if (!_BoneIdComputed)
+01435         {
+01436                 // Get a pointer on the skeleton
+01437                 nlassert (skeleton);
+01438                 if (skeleton)
+01439                 {
+01440                         // Resize boneId to the good size.
+01441                         _BonesId.resize(_BonesName.size());
+01442 
+01443                         // For each matrix block
+01444                         uint matrixBlock;
+01445                         for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
+01446                         {
+01447                                 // Ref on the matrix block
+01448                                 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
+01449 
+01450                                 // For each matrix
+01451                                 uint matrix;
+01452                                 for (matrix=0; matrix<mb.NumMatrix; matrix++)
+01453                                 {
+01454                                         // Get bone id in the skeleton
+01455                                         nlassert (mb.MatrixId[matrix]<_BonesName.size());
+01456                                         sint32 boneId = skeleton->getBoneIdByName (_BonesName[mb.MatrixId[matrix]]);
+01457 
+01458                                         // Setup the _BoneId.
+01459                                         _BonesId[mb.MatrixId[matrix]]= boneId;
+01460 
+01461                                         // Bones found ?
+01462                                         if (boneId != -1)
+01463                                         {
+01464                                                 // Set the bone id
+01465                                                 mb.MatrixId[matrix] = (uint32)boneId;
+01466                                         }
+01467                                         else
+01468                                         {
+01469                                                 // Put id 0
+01470                                                 mb.MatrixId[matrix] = 0;
+01471 
+01472                                                 // Error
+01473                                                 nlwarning ("Bone %s not found in the skeleton.", _BonesName[mb.MatrixId[matrix]].c_str());
+01474                                         }
+01475                                 }
+01476                         }
+01477 
+01478                         // Computed
+01479                         _BoneIdComputed = true;
+01480                 }
+01481         }
+01482 
+01483         // Already extended ?
+01484         if (!_BoneIdExtended)
+01485         {
+01486                 nlassert (skeleton);
+01487                 if (skeleton)
+01488                 {
+01489                         // the total bone Usage of the mesh.
+01490                         vector<bool>    boneUsage;
+01491                         boneUsage.resize(skeleton->Bones.size(), false);
+01492 
+01493                         // for all Bones marked as valid.
+01494                         uint    i;
+01495                         for(i=0; i<_BonesId.size(); i++)
+01496                         {
+01497                                 // if not a valid boneId, skip it.
+01498                                 if(_BonesId[i]<0)
+01499                                         continue;
+01500 
+01501                                 // mark him and his father in boneUsage.
+01502                                 skeleton->flagBoneAndParents(_BonesId[i], boneUsage);
+01503                         }
+01504 
+01505                         // fill _BonesIdExt with bones of _BonesId and their parents.
+01506                         _BonesIdExt.clear();
+01507                         for(i=0; i<boneUsage.size();i++)
+01508                         {
+01509                                 // if the bone is used by the mesh, add it to BoneIdExt.
+01510                                 if(boneUsage[i])
+01511                                         _BonesIdExt.push_back(i);
+01512                         }
+01513 
+01514                 }
+01515 
+01516                 // Extended
+01517                 _BoneIdExtended= true;
+01518         }
+01519 
+01520 }
+01521 
+01522 
+01523 // ***************************************************************************
+01524 void    CMeshGeom::buildBoneUsageVer3 ()
+01525 {
+01526         if(_Skinned)
+01527         {
+01528                 // parse all matrixBlocks, couting MaxBoneId used.
+01529                 uint32  maxBoneId= 0;
+01530                 // For each matrix block
+01531                 uint matrixBlock;
+01532                 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
+01533                 {
+01534                         CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
+01535                         // For each matrix
+01536                         for (uint matrix=0; matrix<mb.NumMatrix; matrix++)
+01537                         {
+01538                                 maxBoneId= max(mb.MatrixId[matrix], maxBoneId);
+01539                         }
+01540                 }
+01541 
+01542                 // alloc an array of maxBoneId+1, reset to 0.
+01543                 std::vector<uint8>              boneUsage;
+01544                 boneUsage.resize(maxBoneId+1, 0);
+01545 
+01546                 // reparse all matrixBlocks, counting usage for each bone.
+01547                 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
+01548                 {
+01549                         CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
+01550                         // For each matrix
+01551                         for (uint matrix=0; matrix<mb.NumMatrix; matrix++)
+01552                         {
+01553                                 // mark this bone as used.
+01554                                 boneUsage[mb.MatrixId[matrix]]= 1;
+01555                         }
+01556                 }
+01557 
+01558                 // For each bone used
+01559                 _BonesId.clear();
+01560                 for(uint i=0; i<boneUsage.size();i++)
+01561                 {
+01562                         // if the bone is used by the mesh, add it to BoneId.
+01563                         if(boneUsage[i])
+01564                                 _BonesId.push_back(i);
+01565                 }
+01566         }
+01567 }
+01568 
+01569 
+01570 // ***************************************************************************
+01571 void    CMeshGeom::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
+01572 {
+01573         // For all Bones used by this mesh.
+01574         for(uint i=0; i<_BonesIdExt.size();i++)
+01575         {
+01576                 uint    boneId= _BonesIdExt[i];
+01577                 // Some explicit Error.
+01578                 if(boneId>=sm->Bones.size())
+01579                         nlerror(" Skin is incompatible with Skeleton: tries to use bone %d", boneId);
+01580                 // increment or decrement not Forced, because CMeshGeom use getActiveBoneSkinMatrix().
+01581                 if(increment)
+01582                         sm->incBoneUsage(boneId, CSkeletonModel::UsageNormal);
+01583                 else
+01584                         sm->decBoneUsage(boneId, CSkeletonModel::UsageNormal);
+01585         }
+01586 }
+01587 
+01588 
+01589 // ***************************************************************************
+01590 void    CMeshGeom::bkupOriginalSkinVertices()
+01591 {
+01592         nlassert(_Skinned);
+01593 
+01594         // reset
+01595         contReset(_OriginalSkinVertices);
+01596         contReset(_OriginalSkinNormals);
+01597         contReset(_OriginalTGSpace);
+01598 
+01599         // get num of vertices
+01600         uint    numVertices= _VBuffer.getNumVertices();
+01601 
+01602         // Copy VBuffer content into Original vertices normals.
+01603         if(_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag)
+01604         {
+01605                 // copy vertices from VBuffer. (NB: unusefull geomorphed vertices are still copied, but doesn't matter).
+01606                 _OriginalSkinVertices.resize(numVertices);
+01607                 for(uint i=0; i<numVertices;i++)
+01608                 {
+01609                         _OriginalSkinVertices[i]= *(CVector*)_VBuffer.getVertexCoordPointer(i);
+01610                 }
+01611         }
+01612         if(_VBuffer.getVertexFormat() & CVertexBuffer::NormalFlag)
+01613         {
+01614                 // copy normals from VBuffer. (NB: unusefull geomorphed normals are still copied, but doesn't matter).
+01615                 _OriginalSkinNormals.resize(numVertices);
+01616                 for(uint i=0; i<numVertices;i++)
+01617                 {
+01618                         _OriginalSkinNormals[i]= *(CVector*)_VBuffer.getNormalCoordPointer(i);
+01619                 }
+01620         }
+01621 
+01622         // is there tangent space added ?
+01623         if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
+01624         {
+01625                 // yes, backup it
+01626                 nlassert(_VBuffer.getNumTexCoordUsed() > 0);
+01627                 uint tgSpaceStage = _VBuffer.getNumTexCoordUsed() - 1;
+01628                 _OriginalTGSpace.resize(numVertices);
+01629                 for(uint i=0; i<numVertices;i++)
+01630                 {
+01631                         _OriginalTGSpace[i]= *(CVector*)_VBuffer.getTexCoordPointer(i, tgSpaceStage);
+01632                 }
+01633         }
+01634 }
+01635 
+01636 
+01637 // ***************************************************************************
+01638 void    CMeshGeom::restoreOriginalSkinVertices()
+01639 {
+01640         nlassert(_Skinned);
+01641 
+01642         // get num of vertices
+01643         uint    numVertices= _VBuffer.getNumVertices();
+01644 
+01645         // Copy VBuffer content into Original vertices normals.
+01646         if(_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag)
+01647         {
+01648                 // copy vertices from VBuffer. (NB: unusefull geomorphed vertices are still copied, but doesn't matter).
+01649                 for(uint i=0; i<numVertices;i++)
+01650                 {
+01651                         *(CVector*)_VBuffer.getVertexCoordPointer(i)= _OriginalSkinVertices[i];
+01652                 }
+01653         }
+01654         if(_VBuffer.getVertexFormat() & CVertexBuffer::NormalFlag)
+01655         {
+01656                 // copy normals from VBuffer. (NB: unusefull geomorphed normals are still copied, but doesn't matter).
+01657                 for(uint i=0; i<numVertices;i++)
+01658                 {
+01659                         *(CVector*)_VBuffer.getNormalCoordPointer(i)= _OriginalSkinNormals[i];
+01660                 }
+01661         }
+01662         if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
+01663         {
+01664                 uint numTexCoords = _VBuffer.getNumTexCoordUsed();
+01665                 nlassert(numTexCoords >= 2);
+01666                 nlassert(_OriginalTGSpace.size() == numVertices);
+01667                 // copy tangent space vectors
+01668                 for(uint i = 0; i < numVertices; ++i)
+01669                 {
+01670                         *(CVector*)_VBuffer.getTexCoordPointer(i, numTexCoords - 1)= _OriginalTGSpace[i];
+01671                 }
+01672         }
+01673 
+01674         // cleared
+01675         _OriginalSkinRestored= true;
+01676 }
+01677 
+01678 
+01679 // ***************************************************************************
+01680 // Flags for software vertex skinning.
+01681 #define NL3D_SOFTSKIN_VNEEDCOMPUTE      3
+01682 #define NL3D_SOFTSKIN_VMUSTCOMPUTE      1
+01683 #define NL3D_SOFTSKIN_VCOMPUTED         0
+01684 // 3 means "vertex may need compute".
+01685 // 1 means "Primitive say vertex must be computed".
+01686 // 0 means "vertex is computed".
+01687 
+01688 
+01689 // ***************************************************************************
+01690 void    CMeshGeom::applySkin(CSkeletonModel *skeleton)
+01691 {
+01692         // init.
+01693         //===================
+01694         if(_OriginalSkinVertices.empty())
+01695                 return;
+01696 
+01697         // Use correct skinning
+01698         TSkinType       skinType;
+01699         if( _OriginalSkinNormals.empty() )
+01700                 skinType= SkinPosOnly;
+01701         else if( _OriginalTGSpace.empty() )
+01702                 skinType= SkinWithNormal;
+01703         else
+01704                 skinType= SkinWithTgSpace;
+01705 
+01706         // Get VB src/dst info/ptrs.
+01707         uint    numVertices= _OriginalSkinVertices.size();
+01708         uint    dstStride= _VBuffer.getVertexSize();
+01709         // Get dst TgSpace.
+01710         uint    tgSpaceStage = 0;
+01711         if( skinType>= SkinWithTgSpace)
+01712         {
+01713                 nlassert(_VBuffer.getNumTexCoordUsed() > 0);
+01714                 tgSpaceStage= _VBuffer.getNumTexCoordUsed() - 1;
+01715         }
+01716 
+01717         // Mark all vertices flag to not computed.
+01718         static  vector<uint8>   skinFlags;
+01719         skinFlags.resize(numVertices);
+01720         // reset all flags
+01721         memset(&skinFlags[0], NL3D_SOFTSKIN_VNEEDCOMPUTE, numVertices );
+01722 
+01723 
+01724         // For all MatrixBlocks
+01725         //===================
+01726         for(uint mb= 0; mb<_MatrixBlocks.size();mb++)
+01727         {
+01728                 // compute matrixes for this block.
+01729                 static  CMatrix3x4      matrixes[IDriver::MaxModelMatrix];
+01730                 computeSkinMatrixes(skeleton, matrixes, mb==0?NULL:&_MatrixBlocks[mb-1], _MatrixBlocks[mb]);
+01731 
+01732                 // check what vertex to skin for this PB.
+01733                 flagSkinVerticesForMatrixBlock(&skinFlags[0], _MatrixBlocks[mb]);
+01734 
+01735                 // Get VB src/dst ptrs.
+01736                 uint8           *pFlag= &skinFlags[0];
+01737                 CVector         *srcVector= &_OriginalSkinVertices[0];
+01738                 uint8           *srcPal= (uint8*)_VBuffer.getPaletteSkinPointer(0);
+01739                 uint8           *srcWgt= (uint8*)_VBuffer.getWeightPointer(0);
+01740                 uint8           *dstVector= (uint8*)_VBuffer.getVertexCoordPointer(0);
+01741                 // Normal.
+01742                 CVector         *srcNormal= NULL;
+01743                 uint8           *dstNormal= NULL;
+01744                 if(skinType>=SkinWithNormal)
+01745                 {
+01746                         srcNormal= &_OriginalSkinNormals[0];
+01747                         dstNormal= (uint8*)_VBuffer.getNormalCoordPointer(0);
+01748                 }
+01749                 // TgSpace.
+01750                 CVector         *srcTgSpace= NULL;
+01751                 uint8           *dstTgSpace= NULL;
+01752                 if(skinType>=SkinWithTgSpace)
+01753                 {
+01754                         srcTgSpace= &_OriginalTGSpace[0];
+01755                         dstTgSpace= (uint8*)_VBuffer.getTexCoordPointer(0, tgSpaceStage);
+01756                 }
+01757 
+01758 
+01759                 // For all vertices that need to be computed.
+01760                 uint            size= numVertices;
+01761                 for(;size>0;size--)
+01762                 {
+01763                         // If we must compute this vertex.
+01764                         if(*pFlag==NL3D_SOFTSKIN_VMUSTCOMPUTE)
+01765                         {
+01766                                 // Flag this vertex as computed.
+01767                                 *pFlag=NL3D_SOFTSKIN_VCOMPUTED;
+01768 
+01769                                 CPaletteSkin    *psPal= (CPaletteSkin*)srcPal;
+01770 
+01771                                 // checks indices.
+01772                                 nlassert(psPal->MatrixId[0]<IDriver::MaxModelMatrix);
+01773                                 nlassert(psPal->MatrixId[1]<IDriver::MaxModelMatrix);
+01774                                 nlassert(psPal->MatrixId[2]<IDriver::MaxModelMatrix);
+01775                                 nlassert(psPal->MatrixId[3]<IDriver::MaxModelMatrix);
+01776 
+01777                                 // compute vertex part.
+01778                                 computeSoftwarePointSkinning(matrixes, srcVector, psPal, (float*)srcWgt, (CVector*)dstVector);
+01779 
+01780                                 // compute normal part.
+01781                                 if(skinType>=SkinWithNormal)
+01782                                         computeSoftwareVectorSkinning(matrixes, srcNormal, psPal, (float*)srcWgt, (CVector*)dstNormal);
+01783 
+01784                                 // compute tg part.
+01785                                 if(skinType>=SkinWithTgSpace)
+01786                                         computeSoftwareVectorSkinning(matrixes, srcTgSpace, psPal, (float*)srcWgt, (CVector*)dstTgSpace);
+01787                         }
+01788 
+01789                         // inc flags.
+01790                         pFlag++;
+01791                         // inc src (all whatever skin type used...)
+01792                         srcVector++;
+01793                         srcNormal++;
+01794                         srcTgSpace++;
+01795                         // inc paletteSkin and dst  (all whatever skin type used...)
+01796                         srcPal+= dstStride;
+01797                         srcWgt+= dstStride;
+01798                         dstVector+= dstStride;
+01799                         dstNormal+= dstStride;
+01800                         dstTgSpace+= dstStride;
+01801                 }
+01802         }
+01803 
+01804 
+01805         // dirt
+01806         _OriginalSkinRestored= false;
+01807 }
+01808 
+01809 
+01810 // ***************************************************************************
+01811 void    CMeshGeom::flagSkinVerticesForMatrixBlock(uint8 *skinFlags, CMatrixBlock &mb)
+01812 {
+01813         for(uint i=0; i<mb.RdrPass.size(); i++)
+01814         {
+01815                 CPrimitiveBlock &PB= mb.RdrPass[i].PBlock;
+01816 
+01817                 uint32  *pIndex;
+01818                 uint    nIndex;
+01819 
+01820                 // This may be better to flags in 2 pass (first traverse primitives, then test vertices).
+01821                 // Better sol for BTB..., because number of tests are divided by 6 (for triangles).
+01822 
+01823                 // for all prims, indicate which vertex we must compute.
+01824                 // nothing if not already computed (ie 0), because 0&1==0.
+01825                 // Lines.
+01826                 pIndex= (uint32*)PB.getLinePointer();
+01827                 nIndex= PB.getNumLine()*2;
+01828                 for(;nIndex>0;nIndex--, pIndex++)
+01829                         skinFlags[*pIndex]&= NL3D_SOFTSKIN_VMUSTCOMPUTE;
+01830                 // Tris.
+01831                 pIndex= (uint32*)PB.getTriPointer();
+01832                 nIndex= PB.getNumTri()*3;
+01833                 for(;nIndex>0;nIndex--, pIndex++)
+01834                         skinFlags[*pIndex]&= NL3D_SOFTSKIN_VMUSTCOMPUTE;
+01835                 // Quads.
+01836                 pIndex= (uint32*)PB.getQuadPointer();
+01837                 nIndex= PB.getNumQuad()*4;
+01838                 for(;nIndex>0;nIndex--, pIndex++)
+01839                         skinFlags[*pIndex]&= NL3D_SOFTSKIN_VMUSTCOMPUTE;
+01840         }
+01841 }
+01842 
+01843 
+01844 // ***************************************************************************
+01845 void    CMeshGeom::computeSoftwarePointSkinning(CMatrix3x4 *matrixes, CVector *srcVec, CPaletteSkin *srcPal, float *srcWgt, CVector *pDst)
+01846 {
+01847         CMatrix3x4              *pMat;
+01848 
+01849         // \todo yoyo: TODO_OPTIMIZE: SSE verion...
+01850 
+01851         // 0th matrix influence.
+01852         pMat= matrixes + srcPal->MatrixId[0];
+01853         pMat->mulSetPoint(*srcVec, srcWgt[0], *pDst);
+01854         // 1th matrix influence.
+01855         pMat= matrixes + srcPal->MatrixId[1];
+01856         pMat->mulAddPoint(*srcVec, srcWgt[1], *pDst);
+01857         // 2th matrix influence.
+01858         pMat= matrixes + srcPal->MatrixId[2];
+01859         pMat->mulAddPoint(*srcVec, srcWgt[2], *pDst);
+01860         // 3th matrix influence.
+01861         pMat= matrixes + srcPal->MatrixId[3];
+01862         pMat->mulAddPoint(*srcVec, srcWgt[3], *pDst);
+01863 }
+01864 
+01865 
+01866 // ***************************************************************************
+01867 void    CMeshGeom::computeSoftwareVectorSkinning(CMatrix3x4 *matrixes, CVector *srcVec, CPaletteSkin *srcPal, float *srcWgt, CVector *pDst)
+01868 {
+01869         CMatrix3x4              *pMat;
+01870 
+01871         // \todo yoyo: TODO_OPTIMIZE: SSE verion...
+01872 
+01873         // 0th matrix influence.
+01874         pMat= matrixes + srcPal->MatrixId[0];
+01875         pMat->mulSetVector(*srcVec, srcWgt[0], *pDst);
+01876         // 1th matrix influence.
+01877         pMat= matrixes + srcPal->MatrixId[1];
+01878         pMat->mulAddVector(*srcVec, srcWgt[1], *pDst);
+01879         // 2th matrix influence.
+01880         pMat= matrixes + srcPal->MatrixId[2];
+01881         pMat->mulAddVector(*srcVec, srcWgt[2], *pDst);
+01882         // 3th matrix influence.
+01883         pMat= matrixes + srcPal->MatrixId[3];
+01884         pMat->mulAddVector(*srcVec, srcWgt[3], *pDst);
+01885 }
+01886 
+01887 
+01888 // ***************************************************************************
+01889 void    CMeshGeom::computeSkinMatrixes(CSkeletonModel *skeleton, CMatrix3x4 *matrixes, CMatrixBlock  *prevBlock, CMatrixBlock  &mBlock)
+01890 {
+01891         // For all matrix of this mBlock.
+01892         for(uint idMat=0;idMat<mBlock.NumMatrix;idMat++)
+01893         {
+01894                 uint    curBoneId= mBlock.MatrixId[idMat];
+01895 
+01896                 // If same matrix binded as previous block, no need to bind!!
+01897                 if(prevBlock && idMat<prevBlock->NumMatrix && prevBlock->MatrixId[idMat]== curBoneId)
+01898                         continue;
+01899 
+01900                 // Else, we must setup the matrix 
+01901                 matrixes[idMat].set(skeleton->getActiveBoneSkinMatrix(curBoneId));
+01902         }
+01903 }
+01904 
+01905 
+01906 // ***************************************************************************
+01907 // ***************************************************************************
+01908 // Mesh Block Render Interface
+01909 // ***************************************************************************
+01910 // ***************************************************************************
+01911 
+01912 
+01913 // ***************************************************************************
+01914 bool    CMeshGeom::supportMeshBlockRendering () const
+01915 {
+01916         return _SupportMeshBlockRendering;
+01917 }
+01918 
+01919 // ***************************************************************************
+01920 bool    CMeshGeom::sortPerMaterial() const
+01921 {
+01922         return true;
+01923 }
+01924 // ***************************************************************************
+01925 uint    CMeshGeom::getNumRdrPasses() const 
+01926 {
+01927         return _MatrixBlocks[0].RdrPass.size();
+01928 }
+01929 // ***************************************************************************
+01930 void    CMeshGeom::beginMesh(CMeshGeomRenderContext &rdrCtx) 
+01931 {
+01932         if(rdrCtx.RenderThroughVBHeap)
+01933         {
+01934                 // Don't setup VB in this case, since use the VBHeap setuped one.
+01935         }
+01936         else
+01937         {
+01938                 // update the VBufferHard (create/delete), to maybe render in AGP memory.
+01939                 updateVertexBufferHard ( rdrCtx.Driver );
+01940 
+01941 
+01942                 // if VB Hard is here, use it.
+01943                 if(_VertexBufferHard != NULL)
+01944                 {
+01945                         // active VB Hard.
+01946                         rdrCtx.Driver->activeVertexBufferHard(_VertexBufferHard);
+01947                 }
+01948                 else
+01949                 {
+01950                         // active VB. SoftwareSkinning: reset flags for skinning.
+01951                         rdrCtx.Driver->activeVertexBuffer(_VBuffer);
+01952                 }
+01953         }
+01954 }
+01955 // ***************************************************************************
+01956 void    CMeshGeom::activeInstance(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *inst, float polygonCount) 
+01957 {
+01958         // setup instance matrix
+01959         rdrCtx.Driver->setupModelMatrix(inst->getWorldMatrix());
+01960 
+01961         // setupLighting.
+01962         inst->changeLightSetup(rdrCtx.RenderTrav);
+01963 
+01964         // \todo yoyo: MeshVertexProgram.
+01965 }
+01966 // ***************************************************************************
+01967 void    CMeshGeom::renderPass(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *mi, float polygonCount, uint rdrPassId) 
+01968 {
+01969         CMatrixBlock    &mBlock= _MatrixBlocks[0];
+01970 
+01971         CRdrPass                &rdrPass= mBlock.RdrPass[rdrPassId];
+01972         // Render with the Materials of the MeshInstance, only if not blended.
+01973         if( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) ) )
+01974         {
+01975                 // \todo yoyo: MeshVertexProgram.
+01976 
+01977                 if(rdrCtx.RenderThroughVBHeap)
+01978                         // render shifted primitives
+01979                         rdrCtx.Driver->render(rdrPass.VBHeapPBlock, mi->Materials[rdrPass.MaterialId]);
+01980                 else
+01981                         // render primitives
+01982                         rdrCtx.Driver->render(rdrPass.PBlock, mi->Materials[rdrPass.MaterialId]);
+01983         }
+01984 }
+01985 // ***************************************************************************
+01986 void    CMeshGeom::endMesh(CMeshGeomRenderContext &rdrCtx) 
+01987 {
+01988         // nop.
+01989         // \todo yoyo: MeshVertexProgram.
+01990 }
+01991 
+01992 // ***************************************************************************
+01993 bool    CMeshGeom::getVBHeapInfo(uint &vertexFormat, uint &numVertices)
+01994 {
+01995         // CMeshGeom support VBHeap rendering, assuming _SupportMeshBlockRendering is true
+01996         vertexFormat= _VBuffer.getVertexFormat();
+01997         numVertices= _VBuffer.getNumVertices();
+01998         return _SupportMeshBlockRendering;
+01999 }
+02000 
+02001 // ***************************************************************************
+02002 void    CMeshGeom::computeMeshVBHeap(void *dst, uint indexStart)
+02003 {
+02004         // Fill dst with Buffer content.
+02005         memcpy(dst, _VBuffer.getVertexCoordPointer(), _VBuffer.getNumVertices()*_VBuffer.getVertexSize() );
+02006 
+02007         // NB: only 1 MB is possible ...
+02008         nlassert(_MatrixBlocks.size()==1);
+02009         CMatrixBlock    &mBlock= _MatrixBlocks[0];
+02010         // For all rdrPass.
+02011         for(uint i=0;i<mBlock.RdrPass.size();i++)
+02012         {
+02013                 // shift the PB
+02014                 CPrimitiveBlock &srcPb= mBlock.RdrPass[i].PBlock;
+02015                 CPrimitiveBlock &dstPb= mBlock.RdrPass[i].VBHeapPBlock;
+02016                 uint j;
+02017 
+02018                 // Lines.
+02019                 dstPb.setNumLine(srcPb.getNumLine());
+02020                 uint32                  *srcLinePtr= srcPb.getLinePointer();
+02021                 uint32                  *dstLinePtr= dstPb.getLinePointer();
+02022                 for(j=0; j<dstPb.getNumLine()*2;j++)
+02023                 {
+02024                         dstLinePtr[j]= srcLinePtr[j]+indexStart;
+02025                 }
+02026                 // Tris.
+02027                 dstPb.setNumTri(srcPb.getNumTri());
+02028                 uint32                  *srcTriPtr= srcPb.getTriPointer();
+02029                 uint32                  *dstTriPtr= dstPb.getTriPointer();
+02030                 for(j=0; j<dstPb.getNumTri()*3;j++)
+02031                 {
+02032                         dstTriPtr[j]= srcTriPtr[j]+indexStart;
+02033                 }
+02034                 // Quads.
+02035                 dstPb.setNumQuad(srcPb.getNumQuad());
+02036                 uint32                  *srcQuadPtr= srcPb.getQuadPointer();
+02037                 uint32                  *dstQuadPtr= dstPb.getQuadPointer();
+02038                 for(j=0; j<dstPb.getNumQuad()*4;j++)
+02039                 {
+02040                         dstQuadPtr[j]= srcQuadPtr[j]+indexStart;
+02041                 }
+02042         }
+02043 }
+02044 
+02045 
+02046 // ***************************************************************************
+02047 // ***************************************************************************
+02048 // CMeshBuild components.
+02049 // ***************************************************************************
+02050 // ***************************************************************************
+02051 
+02052 
+02053 
+02054 // ***************************************************************************
+02055 CMesh::CCorner::CCorner()
+02056 {
+02057         sint    i;
+02058         Vertex= 0;
+02059         Normal= CVector::Null;
+02060         for(i=0;i<CVertexBuffer::MaxStage;i++)
+02061         {
+02062                 Uvws[i]= CUVW(0, 0, 0); 
+02063         }
+02064         Color.set(255,255,255,255);
+02065         Specular.set(0,0,0,0);
+02066 }
+02067 
+02068 
+02069 // ***************************************************************************
+02070 void CMesh::CCorner::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
+02071 {
+02072         nlassert(0); // not used
+02073         f.serial(Vertex);
+02074         f.serial(Normal);
+02075         for(int i=0;i<CVertexBuffer::MaxStage;++i) f.serial(Uvws[i]);
+02076         f.serial(Color);
+02077         f.serial(Specular);
+02078 }
+02079 
+02080 // ***************************************************************************
+02081 void CMesh::CFace::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
+02082 {
+02083         for(int i=0;i<3;++i) 
+02084                 f.serial(Corner[i]);
+02085         f.serial(MaterialId);
+02086         f.serial(SmoothGroup);
+02087 }
+02088 
+02089 // ***************************************************************************
+02090 void CMesh::CSkinWeight::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
+02091 {
+02092         for(int i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;++i)
+02093         {
+02094                 f.serial(MatrixId[i]);
+02095                 f.serial(Weights[i]);
+02096         }
+02097 }
+02098 
+02099 // ***************************************************************************
+02100 /* Serialization is not used.
+02101 void CMesh::CMeshBuild::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
+02102 {
+02103         sint    ver= f.serialVersion(0);
+02104 
+02105         // Serial mesh base (material info).
+02106         CMeshBaseBuild::serial(f);
+02107 
+02108         // Serial Geometry.
+02109         f.serial( VertexFlags );
+02110         f.serialCont( Vertices );
+02111         f.serialCont( SkinWeights );
+02112         f.serialCont( Faces );
+02113 
+02114 }*/
+02115 
+02116 
+02117 //************************************
+02118 CMesh::CMeshBuild::CMeshBuild()
+02119 {
+02120         for (uint k = 0; k < CVertexBuffer::MaxStage; ++k)
+02121         {
+02122                 NumCoords[k] = 2;
+02123         }
+02124 }
+02125 
+02126 
+02127 // ***************************************************************************
+02128 // ***************************************************************************
+02129 // CMesh.
+02130 // ***************************************************************************
+02131 // ***************************************************************************
+02132 
+02133 
+02134 
+02135 // ***************************************************************************
+02136 CMesh::CMesh()
+02137 {
+02138         // create the MeshGeom
+02139         _MeshGeom= new CMeshGeom;
+02140 }
+02141 // ***************************************************************************
+02142 CMesh::~CMesh()
+02143 {
+02144         // delete the MeshGeom
+02145         delete _MeshGeom;
+02146 }
+02147 
+02148 
+02149 // ***************************************************************************
+02150 CMesh::CMesh(const CMesh &mesh)
+02151 {
+02152         // create the MeshGeom
+02153         _MeshGeom= new CMeshGeom(*mesh._MeshGeom);
+02154 }
+02155 
+02156 
+02157 // ***************************************************************************
+02158 CMesh   &CMesh::operator=(const CMesh &mesh)
+02159 {
+02160         // Copy CMeshBase part
+02161         (CMeshBase&)*this= (CMeshBase&)mesh;
+02162 
+02163         // copy content of meshGeom.
+02164         *_MeshGeom= *mesh._MeshGeom;
+02165 
+02166 
+02167         return *this;
+02168 }
+02169 
+02170 
+02171 
+02172 // ***************************************************************************
+02173 void    CMesh::build (CMeshBase::CMeshBaseBuild &mbase, CMeshBuild &m)
+02174 {
+02176         CMeshBase::buildMeshBase (mbase);
+02177 
+02178         // build the geometry.
+02179         _MeshGeom->build (m, mbase.Materials.size());
+02180 }
+02181 
+02182 
+02183 // ***************************************************************************
+02184 void    CMesh::optimizeMaterialUsage(std::vector<sint> &remap)
+02185 {
+02186         // For each material, count usage.
+02187         vector<bool>    materialUsed;
+02188         materialUsed.resize(CMeshBase::_Materials.size(), false);
+02189         for(uint mb=0;mb<getNbMatrixBlock();mb++)
+02190         {
+02191                 for(uint rp=0;rp<getNbRdrPass(mb);rp++)
+02192                 {
+02193                         uint    matId= getRdrPassMaterial(mb, rp);
+02194                         // flag as used.
+02195                         materialUsed[matId]= true;
+02196                 }
+02197         }
+02198 
+02199         // Apply it to meshBase
+02200         CMeshBase::applyMaterialUsageOptim(materialUsed, remap);
+02201 
+02202         // Apply lut to meshGeom.
+02203         _MeshGeom->applyMaterialRemap(remap);
+02204 }
+02205 
+02206 
+02207 // ***************************************************************************
+02208 void CMesh::setBlendShapes(std::vector<CBlendShape>&bs)
+02209 {
+02210         _MeshGeom->setBlendShapes (bs);
+02211 }
+02212 
+02213 // ***************************************************************************
+02214 void    CMesh::build(CMeshBase::CMeshBaseBuild &mbuild, CMeshGeom &meshGeom)
+02215 {
+02217         CMeshBase::buildMeshBase(mbuild);
+02218 
+02219         // build the geometry.
+02220         *_MeshGeom= meshGeom;
+02221 }
+02222 
+02223 
+02224 // ***************************************************************************
+02225 CTransformShape         *CMesh::createInstance(CScene &scene)
+02226 {
+02227         // Create a CMeshInstance, an instance of a mesh.
+02228         //===============================================
+02229         CMeshInstance           *mi= (CMeshInstance*)scene.createModel(NL3D::MeshInstanceId);
+02230         mi->Shape= this;
+02231 
+02232 
+02233         // instanciate the material part of the Mesh, ie the CMeshBase.
+02234         CMeshBase::instanciateMeshBase(mi, &scene);
+02235 
+02236 
+02237         // do some instance init for MeshGeom
+02238         _MeshGeom->initInstance(mi);
+02239 
+02240 
+02241         return mi;
+02242 }
+02243 
+02244 
+02245 // ***************************************************************************
+02246 bool    CMesh::clip(const std::vector<CPlane>   &pyramid, const CMatrix &worldMatrix)
+02247 {
+02248         return _MeshGeom->clip(pyramid, worldMatrix);
+02249 }
+02250 
+02251 
+02252 // ***************************************************************************
+02253 void    CMesh::render(IDriver *drv, CTransformShape *trans, bool passOpaque)
+02254 {
+02255         // 0 or 0xFFFFFFFF
+02256         uint32  mask= (0-(uint32)passOpaque);
+02257         uint32  rdrFlags;
+02258         // select rdrFlags, without ifs.
+02259         rdrFlags=       mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
+02260         rdrFlags|=      ~mask & (IMeshGeom::RenderTransparentMaterial);
+02261         // render the mesh
+02262         _MeshGeom->render(drv, trans, 0, rdrFlags, 1);
+02263 }
+02264 
+02265 
+02266 // ***************************************************************************
+02267 void    CMesh::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
+02268 {
+02269         /*
+02270         Version 6:
+02271                 - cut in serialisation, because of:
+02272                         - bad ITexture serialisation (with no version....) => must cut.  (see CMeshBase serial).
+02273                         - because of this and to simplify, make a cut too in CMesh serialisation.
+02274         NB : all old version code is dropped.
+02275         */
+02276         sint    ver= f.serialVersion(6);
+02277 
+02278 
+02279         if(ver<6)
+02280                 throw NLMISC::EStream(f, "Mesh in Stream is too old (Mesh version < 6)");
+02281 
+02282 
+02283         // serial Materials infos contained in CMeshBase.
+02284         CMeshBase::serialMeshBase(f);
+02285 
+02286 
+02287         // serial geometry.
+02288         _MeshGeom->serial(f);
+02289 
+02290 }
+02291 
+02292 
+02293 // ***************************************************************************
+02294 const NLMISC::CAABBoxExt& CMesh::getBoundingBox() const
+02295 {
+02296         return _MeshGeom->getBoundingBox();
+02297 }
+02298 // ***************************************************************************
+02299 const CVertexBuffer &CMesh::getVertexBuffer() const 
+02300 { 
+02301         return _MeshGeom->getVertexBuffer() ; 
+02302 }
+02303 // ***************************************************************************
+02304 uint CMesh::getNbMatrixBlock() const 
+02305 { 
+02306         return _MeshGeom->getNbMatrixBlock(); 
+02307 }
+02308 // ***************************************************************************
+02309 uint CMesh::getNbRdrPass(uint matrixBlockIndex) const 
+02310 { 
+02311         return _MeshGeom->getNbRdrPass(matrixBlockIndex) ; 
+02312 }
+02313 // ***************************************************************************
+02314 const CPrimitiveBlock &CMesh::getRdrPassPrimitiveBlock(uint matrixBlockIndex, uint renderingPassIndex) const
+02315 {
+02316         return _MeshGeom->getRdrPassPrimitiveBlock(matrixBlockIndex, renderingPassIndex) ;
+02317 }
+02318 // ***************************************************************************
+02319 uint32 CMesh::getRdrPassMaterial(uint matrixBlockIndex, uint renderingPassIndex) const
+02320 {
+02321         return _MeshGeom->getRdrPassMaterial(matrixBlockIndex, renderingPassIndex) ;
+02322 }
+02323 // ***************************************************************************
+02324 float   CMesh::getNumTriangles (float distance)
+02325 {
+02326         // A CMesh do not degrad himself, so return 0, to not be taken into account.
+02327         return 0;
+02328 }
+02329 // ***************************************************************************
+02330 const   CMeshGeom& CMesh::getMeshGeom () const
+02331 {
+02332         return *_MeshGeom;
+02333 }
+02334 // ***************************************************************************
+02335 void    CMesh::computeBonesId (CSkeletonModel *skeleton)
+02336 {
+02337         nlassert (_MeshGeom);
+02338         _MeshGeom->computeBonesId (skeleton);
+02339 }
+02340 
+02341 
+02342 // ***************************************************************************
+02343 void    CMesh::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
+02344 {
+02345         nlassert (_MeshGeom);
+02346         _MeshGeom->updateSkeletonUsage(sm, increment);
+02347 }
+02348 
+02349 // ***************************************************************************
+02350 IMeshGeom       *CMesh::supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const
+02351 {
+02352         // Ok if meshGeom is ok.
+02353         if(_MeshGeom->supportMeshBlockRendering())
+02354         {
+02355                 polygonCount= 0;
+02356                 return _MeshGeom;
+02357         }
+02358         else
+02359                 return NULL;
+02360 }
+02361 
+02362 
+02363 } // NL3D
+02364 
+02365 
+02366 
+
+ + +
                                                                                                                                                                    +
+ + -- cgit v1.2.1