# 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