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

mrm_builder.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/mrm_builder.h"
+00029 #include "3d/mrm_parameters.h"
+00030 using namespace NLMISC;
+00031 using namespace std;
+00032 
+00033 
+00034 namespace NL3D 
+00035 {
+00036 
+00037 
+00038 // ***************************************************************************
+00039 // ***************************************************************************
+00040 // Tools Methods.
+00041 // ***************************************************************************
+00042 // ***************************************************************************
+00043 
+00044 
+00045 // ***************************************************************************
+00046 static bool     findElement(vector<sint>        &array, sint elt)
+00047 {
+00048         return find(array.begin(), array.end(), elt) != array.end();
+00049 }
+00050 // ***************************************************************************
+00051 static bool     deleteElement(vector<sint>      &array, sint elt)
+00052 {
+00053         bool    found=false;
+00054         vector<sint>::iterator  it=array.begin();
+00055 
+00056         while(  (it=find(array.begin(), array.end(), elt)) != array.end() )
+00057                 found=true, array.erase(it);
+00058 
+00059         return found;
+00060         // Must not use remove<> since it do not modify size ... (???)
+00061         // This seems not to work.
+00062         //return remove(array.begin(), array.end(), elt)!=array.end();
+00063 }
+00064 
+00065 
+00066 // ***************************************************************************
+00067 // ***************************************************************************
+00068 // Edge Cost methods.
+00069 // ***************************************************************************
+00070 // ***************************************************************************
+00071 
+00072 
+00073 // ***************************************************************************
+00074 bool    CMRMBuilder::vertexHasOneWedge(sint numvertex)
+00075 {
+00076         CMRMVertex      &vert= TmpVertices[numvertex];
+00077         for(sint attId=0;attId<NumAttributes;attId++)
+00078         {
+00079                 sint    numwedge=-1;
+00080                 for(sint i=0;i<(sint)vert.SharedFaces.size();i++)
+00081                 {
+00082                         sint    w= TmpFaces[vert.SharedFaces[i]].getAssociatedWedge(attId, numvertex);
+00083                         if(numwedge>=0 && numwedge!=w)  return false;
+00084                         else    numwedge=w;
+00085                 }
+00086         }
+00087         return true;
+00088 }
+00089 // ***************************************************************************
+00090 bool    CMRMBuilder::vertexHasOneMaterial(sint numvertex)
+00091 {
+00092         sint    matId=-1;
+00093         CMRMVertex      &vert= TmpVertices[numvertex];
+00094         for(sint i=0;i<(sint)vert.SharedFaces.size();i++)
+00095         {
+00096                 sint    m= TmpFaces[vert.SharedFaces[i]].MaterialId;
+00097                 if(matId>=0 && matId!=m)        return false;
+00098                 else    matId=m;
+00099         }
+00100         return true;
+00101 }
+00102 // ***************************************************************************
+00103 bool    CMRMBuilder::vertexContinue(sint numvertex)
+00104 {
+00105         return vertexHasOneWedge(numvertex) && vertexHasOneMaterial(numvertex);
+00106 }
+00107 // ***************************************************************************
+00108 bool    CMRMBuilder::vertexClosed(sint numvertex)
+00109 {
+00110         CMRMVertex      &vert= TmpVertices[numvertex];
+00111         map<CMRMEdge, sint>             EdgeShare;
+00112         // Init to 0.
+00113         sint i;
+00114         for(i=0;i<(sint)vert.SharedFaces.size();i++)
+00115         {
+00116                 CMRMFaceBuild           &f=TmpFaces[vert.SharedFaces[i]];
+00117                 EdgeShare[f.getEdge(0)]= 0;
+00118                 EdgeShare[f.getEdge(1)]= 0;
+00119                 EdgeShare[f.getEdge(2)]= 0;
+00120         }
+00121         // Inc count.
+00122         for(i=0;i<(sint)vert.SharedFaces.size();i++)
+00123         {
+00124                 CMRMFaceBuild           &f=TmpFaces[vert.SharedFaces[i]];
+00125                 EdgeShare[f.getEdge(0)]++;
+00126                 EdgeShare[f.getEdge(1)]++;
+00127                 EdgeShare[f.getEdge(2)]++;
+00128         }
+00129         // Test open edges.
+00130         for(i=0;i<(sint)vert.SharedFaces.size();i++)
+00131         {
+00132                 CMRMFaceBuild           &f=TmpFaces[vert.SharedFaces[i]];
+00133                 sint    v0= f.Corner[0].Vertex;
+00134                 sint    v1= f.Corner[1].Vertex;
+00135                 sint    v2= f.Corner[2].Vertex;
+00136                 if(EdgeShare[f.getEdge(0)]<2 && (v0==numvertex || v1==numvertex)) return false;
+00137                 if(EdgeShare[f.getEdge(1)]<2 && (v1==numvertex || v2==numvertex)) return false;
+00138                 if(EdgeShare[f.getEdge(2)]<2 && (v0==numvertex || v2==numvertex)) return false;
+00139         }
+00140         return true;
+00141 }
+00142 // ***************************************************************************
+00143 float   CMRMBuilder::getDeltaFaceNormals(sint numvertex)
+00144 {
+00145         // return a positive value of Somme(|DeltaNormals|) / NNormals.
+00146         CMRMVertex      &vert= TmpVertices[numvertex];
+00147         float   delta=0;
+00148         CVector refNormal;
+00149         sint    nfaces=vert.SharedFaces.size();
+00150         for(sint i=0;i<nfaces;i++)
+00151         {
+00152                 CVector normal;
+00153                 CVector &v0= TmpVertices[TmpFaces[i].Corner[0].Vertex].Current;
+00154                 CVector &v1= TmpVertices[TmpFaces[i].Corner[1].Vertex].Current;
+00155                 CVector &v2= TmpVertices[TmpFaces[i].Corner[2].Vertex].Current;
+00156                 normal= (v1-v0)^(v2-v0);
+00157                 normal.normalize();
+00158                 if(i==0)
+00159                         refNormal=normal;
+00160                 else
+00161                         delta+=(1-refNormal*normal);
+00162         }
+00163         if(nfaces<2)
+00164                 return 0;
+00165         else
+00166                 return delta/(nfaces-1);
+00167 }
+00168 // ***************************************************************************
+00169 bool    CMRMBuilder::edgeContinue(const CMRMEdge &edge)
+00170 {
+00171         sint v0= edge.v0;
+00172         sint v1= edge.v1;
+00173         CMRMVertex      &Vertex1=TmpVertices[v0];
+00174 
+00175         // build list sharing edge.
+00176         vector<sint>    deletedFaces;
+00177         sint i;
+00178         for(i=0;i<(sint)Vertex1.SharedFaces.size();i++)
+00179         {
+00180                 sint    numFace= Vertex1.SharedFaces[i];
+00181                 if(TmpFaces[numFace].hasVertex(v1))
+00182                         deletedFaces.push_back(numFace);
+00183         }
+00184 
+00185         sint    matId=-1;
+00186         // test if faces have same material.
+00187         for(i=0;i<(sint)deletedFaces.size();i++)
+00188         {
+00189                 sint    m;
+00190                 m= TmpFaces[deletedFaces[i]].MaterialId;
+00191                 if(matId>=0 && matId!=m)        return false;
+00192                 else    matId=m;
+00193         }
+00194 
+00195         // test if faces have same wedge (for all att).
+00196         for(sint attId=0;attId<NumAttributes;attId++)
+00197         {
+00198                 sint    numwedge1=-1,numwedge2=-1;
+00199                 for(i=0;i<(sint)deletedFaces.size();i++)
+00200                 {
+00201                         sint    w;
+00202                         w= TmpFaces[deletedFaces[i]].getAssociatedWedge(attId, v0);
+00203                         if(numwedge1>=0 && numwedge1!=w)        return false;
+00204                         else    numwedge1=w;
+00205                         w= TmpFaces[deletedFaces[i]].getAssociatedWedge(attId, v1);
+00206                         if(numwedge2>=0 && numwedge2!=w)        return false;
+00207                         else    numwedge2=w;
+00208                 }
+00209         }
+00210 
+00211         return true;
+00212 }
+00213 // ***************************************************************************
+00214 bool    CMRMBuilder::edgeNearUniqueMatFace(const CMRMEdge &edge)
+00215 {
+00216         sint v0= edge.v0;
+00217         sint v1= edge.v1;
+00218         CMRMVertex      &Vertex1=TmpVertices[v0];
+00219 
+00220         // build list sharing edge.
+00221         vector<sint>    deletedFaces;
+00222         sint i;
+00223         for(i=0;i<(sint)Vertex1.SharedFaces.size();i++)
+00224         {
+00225                 sint    numFace= Vertex1.SharedFaces[i];
+00226                 if(TmpFaces[numFace].hasVertex(v1))
+00227                         deletedFaces.push_back(numFace);
+00228         }
+00229 
+00230         // test if faces are not isolated OneMaterial faces.
+00231         for(i=0;i<(sint)deletedFaces.size();i++)
+00232         {
+00233                 CMRMFaceBuild   &f=TmpFaces[deletedFaces[i]];
+00234                 if( !edgeContinue(f.getEdge(0)) && 
+00235                         !edgeContinue(f.getEdge(1)) && 
+00236                         !edgeContinue(f.getEdge(2)))
+00237                         return true;
+00238         }
+00239 
+00240         return false;
+00241 }
+00242 
+00243 // ***************************************************************************
+00244 float   CMRMBuilder::computeEdgeCost(const CMRMEdge &edge)
+00245 {
+00246         sint    v1= edge.v0;
+00247         sint    v2= edge.v1;
+00248         // more expensive is the edge, later it will collapse.
+00249 
+00250 
+00251         // **** standard cost
+00252 
+00253         // compute size of the edge.
+00254         float   cost=(TmpVertices[v1].Current-TmpVertices[v2].Current).norm();
+00255 
+00256         // compute "curvature" of the edge.
+00257         float   faceCost= (getDeltaFaceNormals(v1)+getDeltaFaceNormals(v2));
+00258         // totally plane faces (faceCost==0) must be collapsed with respect to size (and not random if cost==0).
+00259         // else we may have Plane Mesh (like flags) that will collapse in a very ugly way.
+00260         faceCost= max(faceCost, 0.01f);
+00261 
+00262         // modulate size with curvature.
+00263         cost*= faceCost;
+00264 
+00265         // Like H.Hope, add a weight on discontinuities..
+00266         if( !vertexContinue(v1) && !vertexContinue(v2) )
+00267         {
+00268                 // Nb: don't do this on discontinuities edges, unless the unique material face will collapse (pffiou!!).
+00269                 if( edgeContinue(edge) || edgeNearUniqueMatFace(edge) )
+00270                         cost*=4;
+00271         }
+00272 
+00273         // **** Interface Sewing cost
+00274         if(_HasMeshInterfaces)
+00275         {
+00276                 // if the 2 vertices comes from the same Sewing Interface mesh (must be a real interface id)
+00277                 sint    meshSewingId= TmpVertices[v1].InterfaceLink.InterfaceId;
+00278                 if( meshSewingId>=0 && meshSewingId == TmpVertices[v2].InterfaceLink.InterfaceId)
+00279                 {
+00280                         // Then the edge is one of the sewing interface mesh. must do special things for it
+00281                         CMRMSewingMesh  &sewingMesh= _SewingMeshes[meshSewingId];
+00282                         uint    dummy;
+00283 
+00284                         // get the sewing edge id
+00285                         CMRMEdge        sewingEdge;
+00286                         sewingEdge.v0= TmpVertices[v1].InterfaceLink.InterfaceVertexId;
+00287                         sewingEdge.v1= TmpVertices[v2].InterfaceLink.InterfaceVertexId;
+00288                         // if the current sewing lod want to collapse this edge
+00289                         sint collapseId= sewingMesh.mustCollapseEdge(_CurrentLodComputed, sewingEdge, dummy);
+00290                         if(collapseId>=0)
+00291                         {
+00292                                 // Then set a negative priority (ie will collapse as soon as possible). from -N to -1.
+00293                                 // NB: sort them according to collapseId
+00294                                 cost= (float)(-sewingMesh.getNumCollapseEdge(_CurrentLodComputed) + collapseId);
+00295                         }
+00296                         else
+00297                         {
+00298                                 // This edge must not collapse at this Lod, set an infinite priority (hope will never collapse).
+00299                                 cost= FLT_MAX;
+00300                         }
+00301                 }
+00302         }
+00303 
+00304         return cost;
+00305 }
+00306 
+00307 
+00308 
+00309 
+00310 // ***************************************************************************
+00311 // ***************************************************************************
+00312 // Collapse Methods.
+00313 // ***************************************************************************
+00314 // ***************************************************************************
+00315 
+00316 
+00317 // ***************************************************************************
+00318 bool    CMRMBuilder::faceShareWedges(CMRMFaceBuild *face, sint attribId, sint numVertex1, sint numVertex2)
+00319 {
+00320         sint    numWedge1= face->getAssociatedWedge(attribId, numVertex1);
+00321         sint    numWedge2= face->getAssociatedWedge(attribId, numVertex2);
+00322         if(numWedge1<0) return false;
+00323         if(numWedge2<0) return false;
+00324 
+00325         CMRMAttribute   &w1= TmpAttributes[attribId][numWedge1];
+00326         CMRMAttribute   &w2= TmpAttributes[attribId][numWedge2];
+00327         return w1.Shared && w2.Shared && w1.NbSharedFaces>0 && w2.NbSharedFaces>0;
+00328 }
+00329 
+00330 
+00331 // ***************************************************************************
+00332 void    CMRMBuilder::insertFaceIntoEdgeList(CMRMFaceBuild &f)
+00333 {
+00334         float   len;
+00335         if(f.ValidIt0)
+00336         {
+00337                 len= computeEdgeCost(f.getEdge(0));
+00338                 f. It0= EdgeCollapses.insert( TEdgeMap::value_type( len, CMRMEdgeFace(f.getEdge(0),&f) ) );
+00339         }
+00340         if(f.ValidIt1)
+00341         {
+00342                 len= computeEdgeCost(f.getEdge(1));
+00343                 f. It1= EdgeCollapses.insert( TEdgeMap::value_type( len, CMRMEdgeFace(f.getEdge(1),&f) ) );
+00344         }
+00345         if(f.ValidIt2)
+00346         {
+00347                 len= computeEdgeCost(f.getEdge(2));
+00348                 f. It2= EdgeCollapses.insert( TEdgeMap::value_type( len, CMRMEdgeFace(f.getEdge(2),&f) ) );
+00349         }
+00350 }
+00351 // ***************************************************************************
+00352 void    CMRMBuilder::removeFaceFromEdgeList(CMRMFaceBuild &f)
+00353 {
+00354         if(f.ValidIt0)
+00355                 EdgeCollapses.erase(f.It0);
+00356         if(f.ValidIt1)
+00357                 EdgeCollapses.erase(f.It1);
+00358         if(f.ValidIt2)
+00359                 EdgeCollapses.erase(f.It2);
+00360 }
+00361 
+00362 
+00363 
+00364 // ***************************************************************************
+00365 struct          CTmpVertexWeight
+00366 {
+00367         uint32          MatrixId;
+00368         float           Weight;
+00369         // For find().
+00370         bool    operator==(const CTmpVertexWeight &o) const
+00371         {
+00372                 return MatrixId==o.MatrixId;
+00373         }
+00374         // For sort().
+00375         bool    operator<(const CTmpVertexWeight &o) const
+00376         {
+00377                 return Weight>o.Weight;
+00378         }
+00379 
+00380 };
+00381 
+00382 
+00383 // ***************************************************************************
+00384 CMesh::CSkinWeight      CMRMBuilder::collapseSkinWeight(const CMesh::CSkinWeight &sw1, const CMesh::CSkinWeight &sw2, float interValue) const
+00385 {
+00386         // If fast interpolation.
+00387         if(interValue==0)
+00388                 return sw1;
+00389         if(interValue==1)
+00390                 return sw2;
+00391 
+00392         // else, must blend a skinWeight: must identify matrix which exist in the 2 sws, and add new ones.
+00393         uint    nbMats1=0;
+00394         uint    nbMats2=0;
+00395         static vector<CTmpVertexWeight>         sws;
+00396         sws.reserve(NL3D_MESH_SKINNING_MAX_MATRIX * 2);
+00397         sws.clear();
+00398 
+00399         // For all weights of sw1.
+00400         uint i;
+00401         for(i=0; i<NL3D_MESH_SKINNING_MAX_MATRIX; i++)
+00402         {
+00403                 CTmpVertexWeight        vw;
+00404                 vw.MatrixId= sw1.MatrixId[i];
+00405                 vw.Weight= sw1.Weights[i]*(1-interValue);
+00406                 // if this weight is not null.
+00407                 if(vw.Weight>0)
+00408                 {
+00409                         // add it to the list.
+00410                         sws.push_back(vw);
+00411                 }
+00412                 // For skinning reduction.
+00413                 if(sw1.Weights[i]>0)
+00414                         nbMats1++;
+00415         }
+00416 
+00417 
+00418         // For all weights of sw1.
+00419         for(i=0; i<NL3D_MESH_SKINNING_MAX_MATRIX; i++)
+00420         {
+00421                 CTmpVertexWeight        vw;
+00422                 vw.MatrixId= sw2.MatrixId[i];
+00423                 vw.Weight= sw2.Weights[i]*(interValue);
+00424                 // if this weight is not null.
+00425                 if(vw.Weight>0)
+00426                 {
+00427                         // add it or add influence to the matrix.
+00428                         vector<CTmpVertexWeight>::iterator              it= find(sws.begin(), sws.end(), vw);
+00429                         if(it== sws.end())
+00430                                 sws.push_back(vw);
+00431                         else
+00432                                 it->Weight+= vw.Weight;
+00433                 }
+00434                 // For skinning reduction.
+00435                 if(sw2.Weights[i]>0)
+00436                         nbMats2++;
+00437         }
+00438 
+00439 
+00440         // Then keep just the best.
+00441         // sort by Weight decreasing order.
+00442         sort(sws.begin(), sws.end());
+00443 
+00444         // clamp the result to the wanted max matrix.
+00445         uint    nbMatsOut;
+00446         switch(_SkinReduction)
+00447         {
+00448         case CMRMParameters::SkinReductionMin:
+00449                 nbMatsOut= min(nbMats1, nbMats2);
+00450                 break;
+00451         case CMRMParameters::SkinReductionMax:
+00452                 nbMatsOut= max(nbMats1, nbMats2);
+00453                 break;
+00454         case CMRMParameters::SkinReductionBest:
+00455                 nbMatsOut= min( sws.size(), (uint)NL3D_MESH_SKINNING_MAX_MATRIX );
+00456                 break;
+00457         default:
+00458                 nlstop;
+00459         };
+00460         // For security.
+00461         nbMatsOut= min(nbMatsOut, sws.size());
+00462         nlassert(nbMatsOut<=NL3D_MESH_SKINNING_MAX_MATRIX);
+00463 
+00464 
+00465         // Then output the result to the skinWeight, normalizing.
+00466         float   sumWeight=0;
+00467         for(i= 0; i<nbMatsOut; i++)
+00468         {
+00469                 sumWeight+= sws[i].Weight;
+00470         }
+00471 
+00472         CMesh::CSkinWeight      ret;
+00473         // Fill only needed matrix (other are rested in CMesh::CSkinWeight ctor).
+00474         for(i= 0; i<nbMatsOut; i++)
+00475         {
+00476                 ret.MatrixId[i]= sws[i].MatrixId;
+00477                 ret.Weights[i]= sws[i].Weight / sumWeight;
+00478         }
+00479 
+00480         return ret;
+00481 }
+00482 
+00483 // ***************************************************************************
+00484 sint    CMRMBuilder::collapseEdge(const CMRMEdge &edge)
+00485 {
+00486         sint    i,j;
+00487         float   InterValue;
+00488         sint    edgeV1=edge.v0;
+00489         sint    edgeV2=edge.v1;
+00490 
+00491 
+00492         // 0. collapse the vertices.
+00493         //==========================
+00494 
+00495         // edge.Vertex1 kept, but morphed.
+00496         // edge.Vertex2 deleted, and must know on which vertex it collapse.
+00497         CMRMVertex      &Vertex1=TmpVertices[edgeV1], &Vertex2=TmpVertices[edgeV2];
+00498 
+00499         // Interpolation choice.
+00500         // Default is to interpolate vertex 0 to the middle of the edge.
+00501         InterValue=0.5;
+00502         //InterValue=1;
+00503         // **** If at least one vertex of the edge is on a mesh sewing interface, must change InterValue
+00504         if( _HasMeshInterfaces && (Vertex1.InterfaceLink.InterfaceId>=0 || Vertex2.InterfaceLink.InterfaceId>=0) )
+00505         {
+00506                 // If this is an edge of a mesh sewing interface
+00507                 if(Vertex1.InterfaceLink.InterfaceId==Vertex2.InterfaceLink.InterfaceId)
+00508                 {
+00509                         // Then the edge is one of the sewing interface mesh. must do special things for it
+00510                         CMRMSewingMesh  &sewingMesh= _SewingMeshes[Vertex1.InterfaceLink.InterfaceId];
+00511 
+00512                         // get the sewing edge id
+00513                         CMRMEdge        sewingEdge;
+00514                         sewingEdge.v0= Vertex1.InterfaceLink.InterfaceVertexId;
+00515                         sewingEdge.v1= Vertex2.InterfaceLink.InterfaceVertexId;
+00516 
+00517                         // Get the edge in the sewing mesh which is said to be collapsed
+00518                         uint    vertToCollapse;
+00519                         sint collapseId= sewingMesh.mustCollapseEdge(_CurrentLodComputed, sewingEdge, vertToCollapse);
+00520                         // if exist
+00521                         if(collapseId>=0)
+00522                         {
+00523                                 // if it is v0 which must collapse, then InterValue=1
+00524                                 if(vertToCollapse==(uint)sewingEdge.v0)
+00525                                         InterValue= 1;
+00526                                 else
+00527                                         InterValue= 0;
+00528 
+00529                         }
+00530                         else
+00531                         {
+00532                                 // This should not happens. But it is still possible if this edge don't want to collapse but if their
+00533                                 // is no more choice. Take a default value
+00534                                 InterValue= 0;
+00535                         }
+00536                 }
+00537                 else
+00538                 {
+00539                         // must collapse to the vertex on the sewing interface (as if it was open)
+00540                         if(Vertex1.InterfaceLink.InterfaceId>=0)
+00541                         {
+00542                                 // NB: it is possible that both vertices are on a different sewing interface... still collapse (must have to)
+00543                                 InterValue= 0;
+00544                         }
+00545                         else
+00546                         {
+00547                                 // Then Vertex2 is on a sewing interface, collapse to it
+00548                                 InterValue= 1;
+00549                         }
+00550                 }
+00551         }
+00552         // **** Else, on special cases, it is much more efficient to interpolate at start or at end of edge.
+00553         else
+00554         {
+00555                 // If one vertex is "open", ie his shared faces do not represent a closed Fan, then interpolate to this one, 
+00556                 // so the mesh has the same silhouette.
+00557                 bool    vc1= vertexClosed(edgeV1);
+00558                 bool    vc2= vertexClosed(edgeV2);
+00559                 if(!vc1 && vc2) InterValue=0;
+00560                 else if(vc1 && !vc2) InterValue=1;
+00561                 else
+00562                 {
+00563                         // Do the same test but with vertex continue: it is preferable to not move the boundaries 
+00564                         // of a material, or a mapping.
+00565                         bool    vc1= vertexContinue(edgeV1);
+00566                         bool    vc2= vertexContinue(edgeV2);
+00567                         if(!vc1 && vc2) InterValue=0;
+00568                         if(vc1 && !vc2) InterValue=1;
+00569                 }
+00570         }
+00571         /*BENCH_TotalCollapses++;
+00572         if(InterValue==0.5)
+00573                 BENCH_MiddleCollapses++;*/
+00574 
+00575         // Collapse the Vertex.
+00576         //========================
+00577         Vertex1.Current= Vertex1.Current*(1-InterValue) + Vertex2.Current*InterValue;
+00578         for (i = 0; i < (sint)Vertex1.BSCurrent.size(); ++i)
+00579                 Vertex1.BSCurrent[i] = Vertex1.BSCurrent[i]*(1-InterValue) + Vertex2.BSCurrent[i]*InterValue;
+00580         Vertex2.CollapsedTo= edgeV1;
+00581         if(_Skinned)
+00582                 Vertex1.CurrentSW= collapseSkinWeight(Vertex1.CurrentSW, Vertex2.CurrentSW, InterValue);
+00583         if( _HasMeshInterfaces )
+00584                 Vertex1.InterfaceLink= InterValue<0.5f? Vertex1.InterfaceLink : Vertex2.InterfaceLink;
+00585 
+00586         // \todo yoyo: TODO_BUG: Don't know why, but vertices may point on deleted faces.
+00587         // Temp: we destroy here thoses face from SharedFaces...
+00588         for(i=0;i<(sint)Vertex1.SharedFaces.size();i++)
+00589         {
+00590                 sint    numFace= Vertex1.SharedFaces[i];
+00591                 if(TmpFaces[numFace].Deleted)
+00592                         deleteElement(Vertex1.SharedFaces, numFace), i--;
+00593         }
+00594         for(i=0;i<(sint)Vertex2.SharedFaces.size();i++)
+00595         {
+00596                 sint    numFace= Vertex2.SharedFaces[i];
+00597                 if(TmpFaces[numFace].Deleted)
+00598                         deleteElement(Vertex2.SharedFaces, numFace), i--;
+00599         }
+00600 
+00601 
+00602         // Build Neighbor faces.
+00603         vector<sint>    neighboorFaces;
+00604         for(i=0;i<(sint)Vertex1.SharedFaces.size();i++)
+00605         {
+00606                 sint    numFace= Vertex1.SharedFaces[i];
+00607                 if(!findElement(neighboorFaces, numFace))
+00608                         neighboorFaces.push_back(numFace);
+00609         }
+00610         for(i=0;i<(sint)Vertex2.SharedFaces.size();i++)
+00611         {
+00612                 sint    numFace= Vertex2.SharedFaces[i];
+00613                 if(!findElement(neighboorFaces, numFace))
+00614                         neighboorFaces.push_back(numFace);
+00615         }
+00616 
+00617         // Build faces which will be destroyed (may 1 or 2, maybe more for non conventionnal meshes).
+00618         vector<sint>    deletedFaces;
+00619         for(i=0;i<(sint)Vertex1.SharedFaces.size();i++)
+00620         {
+00621                 sint    numFace= Vertex1.SharedFaces[i];
+00622                 nlassert(!TmpFaces[numFace].Deleted);
+00623                 if(TmpFaces[numFace].hasVertex(edgeV2))
+00624                         deletedFaces.push_back(numFace);
+00625         }
+00626 
+00627 
+00628         // 1. Collapse the wedges.
+00629         //========================
+00630 
+00631         // For ALL Attributes.
+00632         for(sint attId=0;attId<NumAttributes;attId++)
+00633         {
+00634                 // a/ Stock the wedge interpolation in each destroyed face.
+00635                 //------------------------------------------------------
+00636                 for(i=0;i<(sint)deletedFaces.size();i++)
+00637                 {
+00638                         CMRMFaceBuild           &face= TmpFaces[deletedFaces[i]];
+00639 
+00640                         CVectorH        &w0= TmpAttributes[attId][ face.getAssociatedWedge(attId, edgeV1) ].Current;
+00641                         CVectorH        &w1= TmpAttributes[attId][ face.getAssociatedWedge(attId, edgeV2) ].Current;
+00642 
+00643                         CVectorH        &itp= face.InterpolatedAttribute;
+00644                         itp.x= w0.x*(1-InterValue) + w1.x*InterValue;
+00645                         itp.y= w0.y*(1-InterValue) + w1.y*InterValue;
+00646                         itp.z= w0.z*(1-InterValue) + w1.z*InterValue;
+00647                         itp.w= w0.w*(1-InterValue) + w1.w*InterValue;
+00648 
+00649                         for (j = 0; j < (sint)face.BSInterpolated.size(); ++j)
+00650                         {
+00651                                 CVectorH &w0 = TmpAttributes[attId][face.getAssociatedWedge(attId, edgeV1)].BSCurrent[j];
+00652                                 CVectorH &w1 = TmpAttributes[attId][face.getAssociatedWedge(attId, edgeV2)].BSCurrent[j];
+00653                                 CVectorH &itb = face.BSInterpolated[j];
+00654                                 itb.x = w0.x*(1-InterValue) + w1.x*InterValue;
+00655                                 itb.y = w0.y*(1-InterValue) + w1.y*InterValue;
+00656                                 itb.z = w0.z*(1-InterValue) + w1.z*InterValue;
+00657                                 itb.w = w0.w*(1-InterValue) + w1.w*InterValue;
+00658                         }
+00659                 }
+00660 
+00661 
+00662                 // b/ Build wedge list to be modify.
+00663                 //----------------------------------
+00664                 vector<sint>    wedges;
+00665 
+00666                 for(i=0;i<(sint)neighboorFaces.size();i++)
+00667                 {
+00668                         CMRMFaceBuild   &face= TmpFaces[neighboorFaces[i]];
+00669                         sint    numWedge;
+00670 
+00671                         numWedge= face.getAssociatedWedge(attId, edgeV1);
+00672                         if(numWedge>=0 && !findElement(wedges, numWedge))
+00673                                 wedges.push_back(numWedge);
+00674 
+00675                         numWedge= face.getAssociatedWedge(attId, edgeV2);
+00676                         if(numWedge>=0 && !findElement(wedges, numWedge))
+00677                                 wedges.push_back(numWedge);
+00678                 }
+00679 
+00680 
+00681                 // c/ Count numFaces which point on those wedges. (- deleted faces).
+00682                 //------------------------------------------------------------------
+00683 
+00684                 for(i=0;i<(sint)wedges.size();i++)
+00685                 {
+00686                         sint                    numWedge= wedges[i];
+00687                         CMRMAttribute   &wedge= TmpAttributes[attId][numWedge];
+00688 
+00689                         wedge.NbSharedFaces=0;
+00690                         wedge.Shared=false;
+00691 
+00692                         // Count total ref count.
+00693                         for(j=0;j<(sint)neighboorFaces.size();j++)
+00694                         {
+00695                                 if(TmpFaces[neighboorFaces[j]].hasWedge(attId, numWedge))
+00696                                         wedge.NbSharedFaces++;
+00697                         }
+00698 
+00699                         // Minus deleted faces.
+00700                         for(j=0;j<(sint)deletedFaces.size();j++)
+00701                         {
+00702                                 if(TmpFaces[deletedFaces[j]].hasWedge(attId, numWedge))
+00703                                 {
+00704                                         wedge.NbSharedFaces--;
+00705                                         wedge.Shared=true;
+00706                                         wedge.InterpolatedFace=deletedFaces[j];
+00707                                 }
+00708                         }
+00709                 }
+00710 
+00711 
+00712                 // d/ Collapse wedge following 3 possibles cases.
+00713                 //-----------------------------------------------
+00714 
+00715 
+00716                 for(i=0;i<(sint)wedges.size();i++)
+00717                 {
+00718                         sint                    numWedge= wedges[i];
+00719                         CMRMAttribute   &wedge= TmpAttributes[attId][numWedge];
+00720 
+00721                         // if wedge not shared...
+00722                         if(!wedge.Shared)
+00723                         {
+00724                                 // We've got an "exterior wedge" which lost no corner => do not merge it nor delete it. 
+00725                                 // Leave it as the same value (extrapolate it may not be a good solution).
+00726                         }
+00727                         else
+00728                         {
+00729                                 // if wedge dissapears, notify.
+00730                                 if(wedge.NbSharedFaces==0)
+00731                                 {
+00732                                         wedge.CollapsedTo=-2;
+00733                                         // Do not change his value. (as specified in Hope article).
+00734                                 }
+00735                                 else
+00736                                 {
+00737                                         CMRMFaceBuild   &face= TmpFaces[wedge.InterpolatedFace];
+00738 
+00739                                         // Must interpolate it.
+00740                                         wedge.Current= face.InterpolatedAttribute;
+00741                                         wedge.BSCurrent = face.BSInterpolated;
+00742                                         
+00743                                         // Must merge the wedge of the second vertex on first
+00744                                         // ONLY IF 2 interpolated wedges are shared and NbSharedFaces!=0.
+00745                                         if(     numWedge==face.getAssociatedWedge(attId, edgeV2) && 
+00746                                                 faceShareWedges(&face, attId, edgeV1, edgeV2) )
+00747                                         {
+00748                                                 wedge.CollapsedTo= face.getAssociatedWedge(attId, edgeV1);
+00749                                         }
+00750                                 }
+00751                         }
+00752                 }
+00753 
+00754         }
+00755 
+00756         // 3. collapse faces.
+00757         //===================
+00758         
+00759         // delete face shared by edge.
+00760         for(i=0;i<(sint)deletedFaces.size();i++)
+00761         {
+00762                 sint    numFace= deletedFaces[i];
+00763                 TmpFaces[numFace].Deleted=true;
+00764 
+00765                 // release edges from list.
+00766                 removeFaceFromEdgeList(TmpFaces[numFace]);
+00767                 // ivalid all it!!
+00768                 TmpFaces[numFace].invalidAllIts(EdgeCollapses);
+00769 
+00770 
+00771                 // delete from vertex1 and 2 the deleted faces.
+00772                 deleteElement( Vertex1.SharedFaces, numFace);
+00773                 deleteElement( Vertex2.SharedFaces, numFace);
+00774         }
+00775 
+00776 
+00777         // must ref correctly the faces.
+00778         for(i=0;i<(sint)neighboorFaces.size();i++)
+00779         {
+00780                 CMRMFaceBuild           &face=TmpFaces[neighboorFaces[i]];
+00781 
+00782                 // good vertices
+00783                 if(face.Corner[0].Vertex ==edgeV2)      face.Corner[0].Vertex=edgeV1;
+00784                 if(face.Corner[1].Vertex ==edgeV2)      face.Corner[1].Vertex=edgeV1;
+00785                 if(face.Corner[2].Vertex ==edgeV2)      face.Corner[2].Vertex=edgeV1;
+00786                 // nb: doesn't matter if deletedFaces are modified...
+00787 
+00788                 // good wedges
+00789                 for(sint attId=0;attId<NumAttributes;attId++)
+00790                 {
+00791                         sint    newWedge;
+00792                         newWedge= TmpAttributes[attId][ face.Corner[0].Attributes[attId] ].CollapsedTo;
+00793                         if(newWedge>=0) face.Corner[0].Attributes[attId]= newWedge;
+00794                         newWedge= TmpAttributes[attId][ face.Corner[1].Attributes[attId] ].CollapsedTo;
+00795                         if(newWedge>=0) face.Corner[1].Attributes[attId]= newWedge;
+00796                         newWedge= TmpAttributes[attId][ face.Corner[2].Attributes[attId] ].CollapsedTo;
+00797                         if(newWedge>=0) face.Corner[2].Attributes[attId]= newWedge;
+00798                 }
+00799 
+00800                 // good edges.
+00801                 /* Those ones are updated in collapseEdges(): they are removed from the edgeCollapseList, 
+00802                         then they are re-inserted with good Vertex indices.
+00803                 */
+00804         }
+00805 
+00806 
+00807         // The vertex1 has now the shared env of vertex2.
+00808         Vertex1.SharedFaces.insert(Vertex1.SharedFaces.end(), Vertex2.SharedFaces.begin(), 
+00809                 Vertex2.SharedFaces.end());
+00810         
+00811 
+00812         return deletedFaces.size();
+00813 }
+00814 
+00815 
+00816 // ***************************************************************************
+00817 sint    CMRMBuilder::followVertex(sint i)
+00818 {
+00819         CMRMVertex      &vert=TmpVertices[i];
+00820         if(vert.CollapsedTo>=0)
+00821                 return followVertex(vert.CollapsedTo);
+00822         else
+00823                 return i;
+00824 }
+00825 // ***************************************************************************
+00826 sint    CMRMBuilder::followWedge(sint attribId, sint i)
+00827 {
+00828         CMRMAttribute   &wedge= TmpAttributes[attribId][i];
+00829         if(wedge.CollapsedTo>=0)
+00830                 return followWedge(attribId, wedge.CollapsedTo);
+00831         else
+00832                 return i;
+00833 }
+00834 
+00835 
+00836 // ***************************************************************************
+00837 // ***************************************************************************
+00838 // Mesh Level method.
+00839 // ***************************************************************************
+00840 // ***************************************************************************
+00841 
+00842 
+00843 // ***************************************************************************
+00844 CMRMBuilder::CMRMBuilder()
+00845 {
+00846         NumAttributes= 0;
+00847         _Skinned= false;
+00848         _HasMeshInterfaces= false;
+00849 }
+00850 
+00851 // ***************************************************************************
+00852 void    CMRMBuilder::init(const CMRMMesh &baseMesh)
+00853 {
+00854         sint    i, attId;
+00855 
+00856 
+00857         // First clear ALL.
+00858         TmpVertices.clear();
+00859         for(attId=0;attId<NL3D_MRM_MAX_ATTRIB;attId++)
+00860         {
+00861                 TmpAttributes[attId].clear();
+00862         }
+00863         TmpFaces.clear();
+00864         EdgeCollapses.clear();
+00865 
+00866 
+00867         // resize.
+00868         NumAttributes= baseMesh.NumAttributes;
+00869         TmpVertices.resize(baseMesh.Vertices.size());
+00870         for(attId=0;attId<NumAttributes;attId++)
+00871         {
+00872                 TmpAttributes[attId].resize(baseMesh.Attributes[attId].size());
+00873         }
+00874         TmpFaces.resize(baseMesh.Faces.size());
+00875 
+00876 
+00877         // Then copy.
+00878         for(i=0;i<(sint)baseMesh.Vertices.size();i++)
+00879         {
+00880                 TmpVertices[i].Current= TmpVertices[i].Original= baseMesh.Vertices[i];
+00881                 TmpVertices[i].BSCurrent.resize(baseMesh.BlendShapes.size());
+00882                 for(uint32 j = 0; j <baseMesh.BlendShapes.size() ;++j)
+00883                         TmpVertices[i].BSCurrent[j]= baseMesh.BlendShapes[j].Vertices[i];
+00884                 if(_Skinned)
+00885                         TmpVertices[i].CurrentSW= TmpVertices[i].OriginalSW= baseMesh.SkinWeights[i];
+00886                 if(_HasMeshInterfaces)
+00887                         TmpVertices[i].InterfaceLink= baseMesh.InterfaceLinks[i];
+00888         }
+00889         for(attId=0;attId<NumAttributes;attId++)
+00890         {
+00891                 for(i=0;i<(sint)baseMesh.Attributes[attId].size();i++)
+00892                 {
+00893                         TmpAttributes[attId][i].Current= TmpAttributes[attId][i].Original= 
+00894                         baseMesh.Attributes[attId][i];
+00895                         TmpAttributes[attId][i].BSCurrent.resize(baseMesh.BlendShapes.size());
+00896                         for(uint32 j = 0; j <baseMesh.BlendShapes.size() ;++j)
+00897                                 TmpAttributes[attId][i].BSCurrent[j]= baseMesh.BlendShapes[j].Attributes[attId][i];
+00898                 }
+00899         }
+00900         for(i=0;i<(sint)baseMesh.Faces.size();i++)
+00901         {
+00902                 TmpFaces[i]= baseMesh.Faces[i];
+00903                 TmpFaces[i].BSInterpolated.resize(baseMesh.BlendShapes.size());
+00904         }
+00905 
+00906 
+00907         // Create vertices sharedFaces.
+00908         for(i=0;i<(sint)TmpFaces.size();i++)
+00909         {
+00910                 CMRMFaceBuild           &face= TmpFaces[i];
+00911 
+00912                 TmpVertices[face.Corner[0].Vertex].SharedFaces.push_back(i);
+00913                 TmpVertices[face.Corner[1].Vertex].SharedFaces.push_back(i);
+00914                 TmpVertices[face.Corner[2].Vertex].SharedFaces.push_back(i);
+00915         }
+00916 
+00917 
+00918         // Compute EdgeCost.
+00919         for(i=0;i<(sint)TmpFaces.size();i++)
+00920         {
+00921                 CMRMFaceBuild           &f= TmpFaces[i];
+00922                 // At start, valid all edges.
+00923                 f. ValidIt0= true;
+00924                 f. ValidIt1= true;
+00925                 f. ValidIt2= true;
+00926                 insertFaceIntoEdgeList(f);
+00927         }
+00928 }
+00929 // ***************************************************************************
+00930 void    CMRMBuilder::collapseEdges(sint nWantedFaces)
+00931 {
+00932         ItEdgeMap               EdgeIt;
+00933 
+00934         sint    nCurrentFaces=TmpFaces.size();
+00935         sint    bug0=0,bug2=0,bug3=0;
+00936 
+00937         while(nCurrentFaces>nWantedFaces)
+00938         {
+00939                 bug0++;
+00940                 EdgeIt= EdgeCollapses.begin();
+00941 
+00942                 if(EdgeIt== EdgeCollapses.end())
+00943                         break;
+00944 
+00945                 // 0. Look if edge already deleted
+00946                 //================================
+00947                 CMRMEdge        edge=(*EdgeIt).second;
+00948 
+00949                 // Is it valid?? (ie his vertices exist yet??).
+00950                 if(TmpVertices[ edge.v0 ].CollapsedTo>=0
+00951                         || TmpVertices[ edge.v1 ].CollapsedTo>=0)
+00952                 {
+00953                         // \todo yoyo: TODO_BUG: potential bug here...
+00954                         CMRMFaceBuild           &f= *(EdgeIt->second.Face);
+00955                         nlassert(f.validEdgeIt(EdgeIt->second));
+00956                         f.invalidEdgeIt(EdgeIt->second, EdgeCollapses);
+00957                         EdgeCollapses.erase(EdgeIt);
+00958                         bug2++;
+00959                         continue;
+00960                 }
+00961                 // \todo yoyo: TODO_BUG: potential bug here...
+00962                 // If a mesh is "open" it will crash if a "hole collapse"...
+00963                 if(edge.v0==edge.v1)
+00964                 {
+00965                         CMRMFaceBuild           &f= *(EdgeIt->second.Face);
+00966                         nlassert(f.validEdgeIt(EdgeIt->second));
+00967                         f.invalidEdgeIt(EdgeIt->second, EdgeCollapses);
+00968                         EdgeCollapses.erase(EdgeIt);
+00969                         bug3++;
+00970                         continue;
+00971                 }
+00972 
+00973 
+00974                 // 1. else, OK, collapse it!!
+00975                 //===========================
+00976                 sint    vertexCollapsed= edge.v0;
+00977                 nCurrentFaces-= collapseEdge(edge);
+00978 
+00979 
+00980                 // 2. Must reorder all his neighborhood.
+00981                 //======================================
+00982                 CMRMVertex      &vert=TmpVertices[vertexCollapsed];
+00983                 sint    i;
+00984                 // we delete from list modified edges, and we re-add them with their new value.
+00985                 for(i=0;i<(sint)vert.SharedFaces.size();i++)
+00986                 {
+00987                         CMRMFaceBuild           &f= TmpFaces[vert.SharedFaces[i]];
+00988                         removeFaceFromEdgeList(f);
+00989                         insertFaceIntoEdgeList(f);
+00990                 }
+00991 
+00992         }
+00993 }
+00994 // ***************************************************************************
+00995 void    CMRMBuilder::saveCoarserMesh(CMRMMesh &coarserMesh)
+00996 {
+00997         sint    i,attId,index;
+00998         // First clear ALL.
+00999         coarserMesh.Vertices.clear();
+01000         coarserMesh.SkinWeights.clear();
+01001         coarserMesh.InterfaceLinks.clear();
+01002         for(attId=0;attId<NL3D_MRM_MAX_ATTRIB;attId++)
+01003         {
+01004                 coarserMesh.Attributes[attId].clear();
+01005         }
+01006         coarserMesh.Faces.clear();
+01007         coarserMesh.NumAttributes= NumAttributes;
+01008 
+01009         // Vertices.
+01010         //==========
+01011         index=0;
+01012         for(i=0;i<(sint)TmpVertices.size();i++)
+01013         {
+01014                 CMRMVertex      &vert=TmpVertices[i];
+01015                 if(vert.CollapsedTo==-1)        // if exist yet.
+01016                 {
+01017                         vert.CoarserIndex=index;
+01018                         coarserMesh.Vertices.push_back(vert.Current);
+01019                         if(_Skinned)
+01020                                 coarserMesh.SkinWeights.push_back(vert.CurrentSW);
+01021                         if(_HasMeshInterfaces)
+01022                                 coarserMesh.InterfaceLinks.push_back(vert.InterfaceLink);
+01023 
+01024                         index++;
+01025                 }
+01026                 else
+01027                         vert.CoarserIndex=-1;   // indicate that this vertex no more exist and is to be geomorphed to an other.
+01028         }
+01029 
+01030 
+01031         // Attributes.
+01032         //============
+01033         for(attId=0;attId<NumAttributes;attId++)
+01034         {
+01035                 index=0;
+01036                 for(i=0;i<(sint)TmpAttributes[attId].size();i++)
+01037                 {
+01038                         CMRMAttribute   &wedge= TmpAttributes[attId][i];
+01039                         if(wedge.CollapsedTo==-1)       // if exist yet.
+01040                         {
+01041                                 wedge.CoarserIndex=index;
+01042                                 coarserMesh.Attributes[attId].push_back(wedge.Current);
+01043                                 index++;
+01044                         }
+01045                         else if(wedge.CollapsedTo==-2)  // else if totaly destroyed.
+01046                         {
+01047                                 // Insert this wedge in the coarser mesh.
+01048                                 // NB: the coarser mesh faces do not use it anymore, but FinerMesh use it
+01049                                 // for geomorph (LODMesh.CoarserFaces may point to it).
+01050                                 // NB: look at buildFinalMRM(), it works fine for all cases.
+01051                                 wedge.CoarserIndex=index;
+01052                                 coarserMesh.Attributes[attId].push_back(wedge.Current);
+01053                                 index++;
+01054                         }
+01055                         else
+01056                                 wedge.CoarserIndex=-1;  // indicate that this wedge no more exist and is to be geomorphed to an other.
+01057                 }
+01058         }
+01059 
+01060         // Faces.
+01061         //=======
+01062         for(i=0;i<(sint)TmpFaces.size();i++)
+01063         {
+01064                 CMRMFaceBuild   &face=TmpFaces[i];
+01065                 if(!face.Deleted)
+01066                 {
+01067                         CMRMFace        newFace;
+01068                         // Material.
+01069                         newFace.MaterialId= face.MaterialId;
+01070                         for(sint j=0;j<3;j++)
+01071                         {
+01072                                 // Vertex.
+01073                                 newFace.Corner[j].Vertex= TmpVertices[face.Corner[j].Vertex].CoarserIndex;
+01074                                 nlassert(newFace.Corner[j].Vertex>=0);
+01075                                 // Attributes.
+01076                                 for(attId=0;attId<NumAttributes;attId++)
+01077                                 {
+01078                                         sint    oldidx= face.Corner[j].Attributes[attId];
+01079                                         newFace.Corner[j].Attributes[attId]= TmpAttributes[attId][oldidx].CoarserIndex;
+01080                                         nlassert(newFace.Corner[j].Attributes[attId]>=0);
+01081                                 }
+01082 
+01083                         }
+01084 
+01085                         coarserMesh.Faces.push_back(newFace);
+01086                 }
+01087         }
+01088 
+01089 }
+01090 
+01091 
+01092 // ***************************************************************************
+01093 void    CMRMBuilder::makeLODMesh(CMRMMeshGeom &lodMesh)
+01094 {
+01095         sint    i,j,attId,index,coidx;
+01096 
+01097         // for all faces of this mesh, find target in the coarser mesh.
+01098         for(i=0;i<(sint)lodMesh.CoarserFaces.size();i++)
+01099         {
+01100                 CMRMFace        &face= lodMesh.CoarserFaces[i];
+01101 
+01102                 // For 3 corners.
+01103                 for(j=0;j<3;j++)
+01104                 {
+01105                         // Vertex.
+01106                         // The index is yet the index in the finer mesh.
+01107                         index= face.Corner[j].Vertex;
+01108                         // the index in the coarser mesh is vert.CoarserIndex.
+01109                         coidx= TmpVertices[index].CoarserIndex;
+01110                         // but if this vertex is collapsed, must find the good index (yet in the finer mesh)
+01111                         if(coidx==-1)
+01112                         {
+01113                                 // find to which we must collapse.
+01114                                 index= followVertex(index);
+01115                                 // and so we have the coarser index. this one must be valid.
+01116                                 coidx= TmpVertices[index].CoarserIndex;
+01117                                 nlassert(coidx>=0);
+01118                         }
+01119                         // update corner of CoarserFace.
+01120                         face.Corner[j].Vertex= coidx;
+01121 
+01122 
+01123                         // Do exactly same thing for all attributes.
+01124                         for(attId=0;attId<NumAttributes;attId++)
+01125                         {
+01126                                 index= face.Corner[j].Attributes[attId];
+01127                                 coidx= TmpAttributes[attId][index].CoarserIndex;
+01128                                 if(coidx==-1)
+01129                                 {
+01130                                         index= followWedge(attId, index);
+01131                                         coidx= TmpAttributes[attId][index].CoarserIndex;
+01132                                         nlassert(coidx>=0);
+01133                                 }
+01134                                 face.Corner[j].Attributes[attId]= coidx;
+01135                         }
+01136                 }
+01137         }
+01138 
+01139 }
+01140 
+01141 // ***************************************************************************
+01142 // Transform source blend shapes to source blend shapes modified (just calculate new vertex/attr position)
+01143 /*void  CMRMBuilder::computeBsVerticesAttributes(vector<CMRMMesh> &srcBsMeshs, vector<CMRMMesh> &bsMeshsMod)
+01144 {
+01145         sint    i, j, k, attId;
+01146 
+01147         bsMeshsMod.resize (srcBsMeshs.size());
+01148         for (k = 0; k < (sint)srcBsMeshs.size(); ++k)
+01149         {
+01150                 CMRMMesh &rBsMesh = srcBsMeshs[k];
+01151                 CMRMMesh &rBsMeshMod = bsMeshsMod[k];
+01152 
+01153                 // Calculate modified vertices with the linear equation back tracking help
+01154                 rBsMeshMod.Vertices.resize (rBsMesh.Vertices.size());
+01155                 for (i = 0; i < (sint)rBsMesh.Vertices.size(); ++i)
+01156                 {
+01157                         CLinearEquation &LinEq = TmpVertices[i].CurrentLinEq;
+01158                         rBsMeshMod.Vertices[i] = CVector(0.0f, 0.0f, 0.0f);
+01159                         for (j = 0; j < (sint)LinEq.Elts.size(); ++j)
+01160                         {
+01161                                 rBsMeshMod.Vertices[i] += LinEq.Elts[j].factor * rBsMesh.Vertices[LinEq.Elts[j].index];
+01162                         }
+01163                 }
+01164 
+01165                 // All attributes
+01166                 rBsMeshMod.NumAttributes = NumAttributes;
+01167                 for (attId = 0; attId < NumAttributes; attId++)
+01168                 {
+01169                         rBsMeshMod.Attributes[attId].resize (rBsMesh.Attributes[attId].size());
+01170                         for (i = 0; i < (sint)rBsMesh.Attributes[attId].size(); ++i)
+01171                         {
+01172                                 CLinearEquation &LinEq = TmpAttributes[attId][i].CurrentLinEq;
+01173                                 rBsMeshMod.Attributes[attId][i] = CVectorH(0.0f, 0.0f, 0.0f, 0.0f);
+01174                                 for (j = 0; j < (sint)LinEq.Elts.size(); ++j)
+01175                                 {
+01176                                         rBsMeshMod.Attributes[attId][i].x += LinEq.Elts[j].factor * rBsMesh.Attributes[attId][LinEq.Elts[j].index].x;
+01177                                         rBsMeshMod.Attributes[attId][i].y += LinEq.Elts[j].factor * rBsMesh.Attributes[attId][LinEq.Elts[j].index].y;
+01178                                         rBsMeshMod.Attributes[attId][i].z += LinEq.Elts[j].factor * rBsMesh.Attributes[attId][LinEq.Elts[j].index].z;
+01179                                         rBsMeshMod.Attributes[attId][i].w += LinEq.Elts[j].factor * rBsMesh.Attributes[attId][LinEq.Elts[j].index].w;
+01180                                 }
+01181                         }
+01182                 }
+01183         }
+01184 }*/
+01185 
+01186 // ***************************************************************************
+01187 // Transform source Blend Shape Meshes Modified into coarser blend shape mesh (compact vertices)
+01188 void    CMRMBuilder::makeCoarserBS (vector<CMRMBlendShape> &csBsMeshs)
+01189 {
+01190         uint32 i, k;
+01191         sint32 nSizeVert, nSizeAttr, attId;
+01192 
+01193         // Calculate size of vertices array
+01194         nSizeVert = 0;
+01195         for (i = 0; i < TmpVertices.size(); ++i)
+01196                 if(TmpVertices[i].CoarserIndex > nSizeVert)
+01197                         nSizeVert = TmpVertices[i].CoarserIndex;
+01198         ++nSizeVert;
+01199 
+01200         for (k = 0; k < csBsMeshs.size(); ++k)
+01201         {
+01202                 CMRMBlendShape &rBsCoarserMesh = csBsMeshs[k];
+01203 
+01204                 rBsCoarserMesh.Vertices.resize (nSizeVert);
+01205                 rBsCoarserMesh.NumAttributes = NumAttributes;
+01206 
+01207                 // Vertices
+01208                 for(i = 0; i < TmpVertices.size(); ++i)
+01209                 {
+01210                         CMRMVertex &vert = TmpVertices[i];
+01211                         if (vert.CoarserIndex != -1)
+01212                         {
+01213                                 rBsCoarserMesh.Vertices[vert.CoarserIndex] = vert.BSCurrent[k];
+01214                         }
+01215                 }
+01216 
+01217                 for (attId = 0; attId < NumAttributes; attId++)
+01218                 {
+01219                         // Calculate size of attribute attId array
+01220                         nSizeAttr = 0;
+01221                         for(i = 0; i < TmpAttributes[attId].size(); i++)
+01222                                 if (TmpAttributes[attId][i].CoarserIndex > nSizeAttr)
+01223                                         nSizeAttr = TmpAttributes[attId][i].CoarserIndex;
+01224                         ++nSizeAttr;
+01225 
+01226                         rBsCoarserMesh.Attributes[attId].resize (nSizeAttr);
+01227 
+01228                         for (i = 0; i < TmpAttributes[attId].size(); i++)
+01229                         {
+01230                                 CMRMAttribute &wedge = TmpAttributes[attId][i];
+01231                                 if (wedge.CoarserIndex != -1)
+01232                                 {
+01233                                         rBsCoarserMesh.Attributes[attId][wedge.CoarserIndex] = wedge.BSCurrent[k];
+01234                                 }
+01235                         }
+01236                 }
+01237         }
+01238 }
+01239 
+01240 // ***************************************************************************
+01241 void    CMRMBuilder::makeFromMesh(const CMRMMesh &baseMesh, CMRMMeshGeom &lodMesh, CMRMMesh &coarserMesh, sint nWantedFaces)
+01242 {
+01243         // Init Tmp values in MRM builder.
+01244         init(baseMesh);
+01245 
+01246         // compute MRM too next tgt face.
+01247         collapseEdges(nWantedFaces);
+01248 
+01249         // save the coarser mesh.
+01250         saveCoarserMesh(coarserMesh);
+01251         // Build coarser BlendShapes.
+01252         coarserMesh.BlendShapes.resize(baseMesh.BlendShapes.size());
+01253         makeCoarserBS(coarserMesh.BlendShapes);
+01254 
+01255         // build the lodMesh (baseMesh, with vertex/Attributes collapse infos).
+01256         lodMesh= baseMesh;
+01257         makeLODMesh(lodMesh);
+01258 
+01259         // end for this level.
+01260 }
+01261 
+01262 
+01263 
+01264 // ***************************************************************************
+01265 // ***************************************************************************
+01266 // Global MRM Level method.
+01267 // ***************************************************************************
+01268 // ***************************************************************************
+01269 
+01270 
+01271 // ***************************************************************************
+01272 void    CMRMBuilder::buildAllLods(const CMRMMesh &baseMesh, std::vector<CMRMMeshGeom> &lodMeshs, 
+01273                                                                   uint nWantedLods, uint divisor)
+01274 {
+01275         sint    nFaces= baseMesh.Faces.size();
+01276         sint    nBaseFaces;
+01277         sint    i;
+01278         CMRMMesh srcMesh = baseMesh;
+01279 
+01280         // coarsest LOD will have those number of faces.
+01281         nBaseFaces=nFaces/divisor;
+01282         nBaseFaces=max(nBaseFaces,4);
+01283 
+01284         // must have at least 2 LOD to be really intersting. But the rest of the process work too with only one Lod!!
+01285         nlassert(nWantedLods>=1);
+01286         lodMeshs.resize(nWantedLods);
+01287 
+01288         // If only one lod asked, must init some Tmp Global values (like NumAttributes)
+01289         if(nWantedLods==1)
+01290         {
+01291                 _CurrentLodComputed= 0;
+01292                 init(baseMesh);
+01293         }
+01294 
+01295         // must fill all LODs, from end to start. do not proces last lod since it will be the coarsest mesh.
+01296         for(i=nWantedLods-1;i>0;i--)
+01297         {
+01298                 sint    nbWantedFaces;
+01299 
+01300                 // for sewing computing
+01301                 _CurrentLodComputed= i;
+01302 
+01303                 // Linear.
+01304                 nbWantedFaces= nBaseFaces + (nFaces-nBaseFaces) * (i-1)/(nWantedLods-1);
+01305                 nbWantedFaces=max(nbWantedFaces,4);
+01306 
+01307                 // Build this LOD.
+01308                 CMRMMesh        csMesh;
+01309                 // The mesh
+01310                 makeFromMesh(srcMesh, lodMeshs[i], csMesh, nbWantedFaces);
+01311 
+01312                 // next mesh to process is csMesh.
+01313                 srcMesh = csMesh;
+01314         }
+01315         // the first lodMedsh gets the coarsest mesh.
+01316         lodMeshs[0]= srcMesh;
+01317 }
+01318 
+01319 
+01320 // ***************************************************************************
+01321 void    CMRMBuilder::buildFinalMRM(std::vector<CMRMMeshGeom> &lodMeshs, CMRMMeshFinal &finalMRM)
+01322 {
+01323         sint    i,j;
+01324         sint    lodId, attId;
+01325         sint    nLods= lodMeshs.size();
+01326 
+01327         // Init.
+01328         // ===============
+01329         finalMRM.reset();
+01330         finalMRM.NumAttributes= NumAttributes;
+01331         finalMRM.Skinned= _Skinned;
+01332         CMRMMeshFinal::CWedge::NumAttributesToCompare= NumAttributes;
+01333         CMRMMeshFinal::CWedge::CompareSkinning= _Skinned;
+01334         finalMRM.Lods.resize(nLods);
+01335 
+01336 
+01337         // Build Wedges, and faces index.
+01338         // ===============
+01339         // for all lods.
+01340         for(lodId=0; lodId<nLods; lodId++)
+01341         {
+01342                 CMRMMeshGeom    &lodMesh= lodMeshs[lodId];
+01343                 CMRMMeshGeom    &lodMeshPrec= lodMeshs[lodId==0?0:lodId-1];
+01344                 // for all face corner.
+01345                 for(i=0; i<(sint)lodMesh.Faces.size();i++)
+01346                 {
+01347                         // The current face.
+01348                         CMRMFace        &face= lodMesh.Faces[i];
+01349                         // the current face, but which points to the prec LOD vertices/attributes.
+01350                         CMRMFace        &faceCoarser= lodMesh.CoarserFaces[i];
+01351                         // for 3 corners.
+01352                         for(j=0;j<3;j++)
+01353                         {
+01354                                 CMRMCorner      &corner= face.Corner[j];
+01355                                 CMRMCorner      &cornerCoarser= faceCoarser.Corner[j];
+01356                                 // start and end wedge (geomorph), maybe same.
+01357                                 CMRMMeshFinal::CWedge           wedgeStart;
+01358                                 CMRMMeshFinal::CWedge           wedgeEnd;
+01359 
+01360                                 // fill wedgeStart with values from lodMesh.
+01361                                 wedgeStart.Vertex= lodMesh.Vertices[corner.Vertex];
+01362                                 if(_Skinned)
+01363                                         wedgeStart.VertexSkin= lodMesh.SkinWeights[corner.Vertex];
+01364                                 for(attId=0; attId<NumAttributes; attId++)
+01365                                 {
+01366                                         wedgeStart.Attributes[attId]= lodMesh.Attributes[attId][corner.Attributes[attId]];
+01367                                 }
+01368 
+01369                                 // if geomorph possible (ie not lod 0).
+01370                                 if(lodId>0)
+01371                                 {
+01372                                         // fill wedgeEnd with values from coarser lodMesh.
+01373                                         wedgeEnd.Vertex= lodMeshPrec.Vertices[cornerCoarser.Vertex];
+01374                                         if(_Skinned)
+01375                                                 wedgeEnd.VertexSkin= lodMeshPrec.SkinWeights[cornerCoarser.Vertex];
+01376                                         for(attId=0; attId<NumAttributes; attId++)
+01377                                         {
+01378                                                 wedgeEnd.Attributes[attId]= lodMeshPrec.Attributes[attId][cornerCoarser.Attributes[attId]];
+01379                                         }
+01380                                 }
+01381                                 else
+01382                                 {
+01383                                         // no geomorph.
+01384                                         wedgeEnd= wedgeStart;
+01385                                 }
+01386 
+01387                                 // find/insert wedge, and get Ids. NB: if start/end same, same indices.
+01388                                 sint    wedgeStartId= finalMRM.findInsertWedge(wedgeStart);
+01389                                 sint    wedgeEndId= finalMRM.findInsertWedge(wedgeEnd);
+01390 
+01391                                 // store in TmpCorner.
+01392                                 corner.WedgeStartId= wedgeStartId;
+01393                                 corner.WedgeEndId= wedgeEndId;
+01394                         }
+01395                 }
+01396 
+01397                 // Here, the number of wedge indicate the max number of wedge this LOD needs.
+01398                 finalMRM.Lods[lodId].NWedges= finalMRM.Wedges.size();
+01399         }
+01400 
+01401 
+01402         // Count NBWedges necessary for geomorph, and compute Dest geomorph wedges ids.
+01403         // ===============
+01404         // the number of geomorph required for one LOD.
+01405         sint    sglmGeom;
+01406         // the number of geomorph required for all LOD (max of sglmGeom).
+01407         sint    sglmGeomMax= 0;
+01408 
+01409         // Do not process lod 0, since no geomorph.
+01410         for(lodId=1; lodId<nLods; lodId++)
+01411         {
+01412                 CMRMMeshGeom    &lodMesh= lodMeshs[lodId];
+01413 
+01414                 // reset the GeomMap, the one which indicate if we have already inserted a geomorph.
+01415                 _GeomMap.clear();
+01416                 sglmGeom= 0;
+01417 
+01418                 // for all face corner.
+01419                 for(i=0; i<(sint)lodMesh.Faces.size();i++)
+01420                 {
+01421                         // The current face.
+01422                         CMRMFace        &face= lodMesh.Faces[i];
+01423                         // for 3 corners.
+01424                         for(j=0;j<3;j++)
+01425                         {
+01426                                 CMRMCorner      &corner= face.Corner[j];
+01427 
+01428                                 // if not same wedge Ids, this is a geomorphed wedge.
+01429                                 if(corner.WedgeStartId != corner.WedgeEndId)
+01430                                 {
+01431                                         // search if it exist yet in the set.
+01432                                         CMRMWedgeGeom   geom;
+01433                                         geom.Start= corner.WedgeStartId;
+01434                                         geom.End= corner.WedgeEndId;
+01435                                         sint    geomDest= sglmGeom;
+01436                                         // if don't find this geom in the set, then it is a new one.
+01437                                         TGeomMap::const_iterator        it= _GeomMap.find(geom);
+01438                                         if(it == _GeomMap.end())
+01439                                         {
+01440                                                 _GeomMap.insert( make_pair(geom, geomDest) );
+01441                                                 sglmGeom++;
+01442                                         }
+01443                                         else
+01444                                                 geomDest= it->second;
+01445 
+01446                                         // store this Geom Id in the corner.
+01447                                         corner.WedgeGeomId= geomDest;
+01448                                 }
+01449                         }
+01450                 }
+01451 
+01452                 // take the max.
+01453                 sglmGeomMax= max(sglmGeomMax, sglmGeom);
+01454         }
+01455 
+01456         
+01457         // inform the finalMRM.
+01458         finalMRM.NGeomSpace= sglmGeomMax;
+01459 
+01460 
+01461         // decal all wedges/ face index.
+01462         // ===============
+01463         // insert an empty space for dest geomorph.
+01464         finalMRM.Wedges.insert(finalMRM.Wedges.begin(), sglmGeomMax, CMRMMeshFinal::CWedge());
+01465 
+01466         // Parse all faces corner of All lods, and decal Start/End Wedge index.
+01467         for(lodId=0; lodId<nLods; lodId++)
+01468         {
+01469                 CMRMMeshGeom    &lodMesh= lodMeshs[lodId];
+01470 
+01471                 // for all face corner.
+01472                 for(i=0; i<(sint)lodMesh.Faces.size();i++)
+01473                 {
+01474                         // The current face.
+01475                         CMRMFace        &face= lodMesh.Faces[i];
+01476                         // for 3 corners.
+01477                         for(j=0;j<3;j++)
+01478                         {
+01479                                 CMRMCorner      &corner= face.Corner[j];
+01480 
+01481                                 // decal indices.
+01482                                 corner.WedgeStartId+= sglmGeomMax;
+01483                                 corner.WedgeEndId+= sglmGeomMax;
+01484                         }
+01485                 }
+01486 
+01487                 // increment too the number of wedge required for this Lod.
+01488                 finalMRM.Lods[lodId].NWedges+= sglmGeomMax;
+01489         }
+01490 
+01491 
+01492         // fill faces.
+01493         // ===============
+01494         // Parse all faces corner of All lods, and build Faces/Geomorphs..
+01495         for(lodId=0; lodId<nLods; lodId++)
+01496         {
+01497                 CMRMMeshGeom                    &lodMesh= lodMeshs[lodId];
+01498                 CMRMMeshFinal::CLod             &lodDest= finalMRM.Lods[lodId];
+01499 
+01500                 // alloc final faces of this LOD.
+01501                 lodDest.Faces.resize(lodMesh.Faces.size());
+01502 
+01503                 // reset the GeomMap, the one which indicate if we have already inserted a geomorph.
+01504                 _GeomMap.clear();
+01505 
+01506                 // for all face corner.
+01507                 for(i=0; i<(sint)lodMesh.Faces.size();i++)
+01508                 {
+01509                         // The current face.
+01510                         CMRMFace        &face= lodMesh.Faces[i];
+01511                         // The dest face.
+01512                         CMRMMeshFinal::CFace            &faceDest= lodDest.Faces[i];
+01513                         // fill good material.
+01514                         faceDest.MaterialId= face.MaterialId;
+01515 
+01516                         // for 3 corners.
+01517                         for(j=0;j<3;j++)
+01518                         {
+01519                                 CMRMCorner      &corner= face.Corner[j];
+01520 
+01521                                 // if not same wedge Ids, this is a geomorphed wedge.
+01522                                 if(corner.WedgeStartId != corner.WedgeEndId)
+01523                                 {
+01524                                         // geomorph, so point to geomorphed wedge.
+01525                                         faceDest.WedgeId[j]= corner.WedgeGeomId;
+01526 
+01527                                         // Build the geomorph, add it to the list (if not yet inserted).
+01528                                         CMRMWedgeGeom   geom;
+01529                                         geom.Start= corner.WedgeStartId;
+01530                                         geom.End=       corner.WedgeEndId;
+01531                                         // if don't find this geom in the set, then it is a new one.
+01532                                         TGeomMap::const_iterator        it= _GeomMap.find(geom);
+01533                                         if(it == _GeomMap.end())
+01534                                         {
+01535                                                 // mark it as inserted.
+01536                                                 _GeomMap.insert( make_pair(geom, corner.WedgeGeomId) );
+01537                                                 // and we must insert this geom in the array.
+01538                                                 nlassert( corner.WedgeGeomId==(sint)lodDest.Geomorphs.size() );
+01539                                                 lodDest.Geomorphs.push_back(geom);
+01540                                         }
+01541                                 }
+01542                                 else
+01543                                 {
+01544                                         // no geomorph, so just point to good wedge.
+01545                                         faceDest.WedgeId[j]= corner.WedgeStartId;
+01546                                 }
+01547                         }
+01548                 }
+01549         }
+01550 
+01551 
+01552         // process all wedges, and compute NSkinMatUsed, skipping geomorphs.
+01553         // ===============
+01554         // NB: this works because weights are sorted from biggest to lowest.
+01555         if(_Skinned)
+01556         {
+01557                 for(i=finalMRM.NGeomSpace; i<(sint)finalMRM.Wedges.size();i++)
+01558                 {
+01559                         CMRMMeshFinal::CWedge   &wedge= finalMRM.Wedges[i];
+01560                         for(j=0; j<NL3D_MESH_SKINNING_MAX_MATRIX; j++)
+01561                         {
+01562                                 if(wedge.VertexSkin.Weights[j]==0)
+01563                                         break;
+01564                         }
+01565                         nlassert(j>0);
+01566                         wedge.NSkinMatUsed= j;
+01567                 }
+01568         }
+01569 
+01570         // Blend Shape Stuff
+01571         finalMRM.MRMBlendShapesFinals.resize (lodMeshs[0].BlendShapes.size());
+01572         for (lodId = 0; lodId < nLods; ++lodId)
+01573         {
+01574                 CMRMMeshGeom &lodMesh= lodMeshs[lodId];
+01575                 CMRMMeshGeom &lodMeshPrec= lodMeshs[lodId==0?0:lodId-1];
+01576 
+01577                 // for all face corner.
+01578                 for (i = 0; i < (sint)lodMesh.Faces.size(); ++i)
+01579                 {
+01580                         // The current face.
+01581                         CMRMFace &face = lodMesh.Faces[i];
+01582                         // the current face, but which points to the prec LOD vertices/attributes.
+01583                         CMRMFace &faceCoarser = lodMesh.CoarserFaces[i];
+01584                         // for 3 corners.
+01585                         for (j = 0; j < 3; ++j)
+01586                         {
+01587                                 CMRMCorner &corner = face.Corner[j];
+01588                                 CMRMCorner &cornerCoarser = faceCoarser.Corner[j];
+01589 
+01590                                 sint startDestIndex = corner.WedgeStartId;
+01591 
+01592                                 for (sint k = 0; k < (sint)finalMRM.MRMBlendShapesFinals.size(); ++k)
+01593                                 {
+01594                                         CMRMMeshFinal::CMRMBlendShapeFinal &rBSFinal = finalMRM.MRMBlendShapesFinals[k];
+01595 
+01596                                         rBSFinal.Wedges.resize (finalMRM.Wedges.size());
+01597                                         // Fill WedgeStart used by this corner.
+01598                                         rBSFinal.Wedges[startDestIndex].Vertex = lodMesh.BlendShapes[k].Vertices[corner.Vertex];
+01599                                         for (attId = 0; attId < NumAttributes; ++attId)
+01600                                         {
+01601                                                 rBSFinal.Wedges[startDestIndex].Attributes[attId] = lodMesh.BlendShapes[k].Attributes[attId][corner.Attributes[attId]];
+01602                                         }
+01603 
+01604                                         // If geomorph, must fill the end too
+01605                                         if(lodId>0 && corner.WedgeStartId != corner.WedgeEndId)
+01606                                         {
+01607                                                 sint endDestIndex = corner.WedgeEndId;
+01608 
+01609                                                 rBSFinal.Wedges[endDestIndex].Vertex = lodMeshPrec.BlendShapes[k].Vertices[cornerCoarser.Vertex];
+01610                                                 for (attId = 0; attId < NumAttributes; ++attId)
+01611                                                 {
+01612                                                         rBSFinal.Wedges[endDestIndex].Attributes[attId] = lodMeshPrec.BlendShapes[k].Attributes[attId][cornerCoarser.Attributes[attId]];
+01613                                                 }
+01614                                         }
+01615                                 }
+01616 
+01617                         }
+01618                 }
+01619         }
+01620 }
+01621 
+01622 
+01623 
+01624 // ***************************************************************************
+01625 // ***************************************************************************
+01626 // Interface to MeshBuild Part.
+01627 // ***************************************************************************
+01628 // ***************************************************************************
+01629 
+01630 
+01631 
+01632 // ***************************************************************************
+01633 sint                    CMRMBuilder::findInsertAttributeInBaseMesh(CMRMMesh &baseMesh, sint attId, sint vertexId, const CVectorH &att)
+01634 {
+01635         // find this attribute in the map.
+01636         CAttributeKey   key;
+01637         key.VertexId= vertexId;
+01638         key.Attribute= att;
+01639         TAttributeMap::iterator         it= _AttributeMap[attId].find(key);
+01640 
+01641         // if attribute not found in the map, then insert a new one.
+01642         if(it==_AttributeMap[attId].end())
+01643         {
+01644                 sint    idx= baseMesh.Attributes[attId].size();
+01645                 // insert into the array.
+01646                 baseMesh.Attributes[attId].push_back(att);
+01647                 // insert into the map.
+01648                 _AttributeMap[attId].insert(make_pair(key, idx));
+01649                 return idx;
+01650         }
+01651         else
+01652         {
+01653                 // return the one found.
+01654                 return it->second;
+01655         }
+01656 }
+01657 
+01658 
+01659 // ***************************************************************************
+01660 sint                    CMRMBuilder::findInsertNormalInBaseMesh(CMRMMesh &baseMesh, sint attId, sint vertexId, const CVector &normal)
+01661 {
+01662         CVectorH        att;
+01663         att= normal;
+01664         att.w= 0;
+01665         return findInsertAttributeInBaseMesh(baseMesh, attId, vertexId, att);
+01666 }
+01667 
+01668 
+01669 // ***************************************************************************
+01670 sint                    CMRMBuilder::findInsertColorInBaseMesh(CMRMMesh &baseMesh, sint attId, sint vertexId, CRGBA col)
+01671 {
+01672         CVectorH        att;
+01673         att.x= col.R;
+01674         att.y= col.G;
+01675         att.z= col.B;
+01676         att.w= col.A;
+01677         return findInsertAttributeInBaseMesh(baseMesh, attId, vertexId, att);
+01678 }
+01679 
+01680 
+01681 // ***************************************************************************
+01682 sint                    CMRMBuilder::findInsertUvwInBaseMesh(CMRMMesh &baseMesh, sint attId, sint vertexId, const NLMISC::CUVW &uvw)
+01683 {
+01684         CVectorH        att;
+01685         att.x= uvw.U;
+01686         att.y= uvw.V;
+01687         att.z= uvw.W;
+01688         att.w= 0;
+01689         return findInsertAttributeInBaseMesh(baseMesh, attId, vertexId, att);
+01690 }
+01691 
+01692 
+01693 // ***************************************************************************
+01694 CRGBA                   CMRMBuilder::attToColor(const CVectorH &att) const
+01695 {
+01696         CRGBA   ret;
+01697         float   tmp;
+01698         tmp= att.x; clamp(tmp, 0, 255);
+01699         ret.R= (uint8)(uint)tmp;
+01700         tmp= att.y; clamp(tmp, 0, 255);
+01701         ret.G= (uint8)(uint)tmp;
+01702         tmp= att.z; clamp(tmp, 0, 255);
+01703         ret.B= (uint8)(uint)tmp;
+01704         tmp= att.w; clamp(tmp, 0, 255);
+01705         ret.A= (uint8)(uint)tmp;
+01706 
+01707         return ret;
+01708 }
+01709 
+01710 
+01711 // ***************************************************************************
+01712 NLMISC::CUVW                    CMRMBuilder::attToUvw(const CVectorH &att) const
+01713 {
+01714         return CUVW(att.x, att.y, att.z);
+01715 }
+01716 
+01717 
+01718 // ***************************************************************************
+01719 uint32                  CMRMBuilder::buildMrmBaseMesh(const CMesh::CMeshBuild &mbuild, CMRMMesh &baseMesh)
+01720 {
+01721         sint            i,j,k;
+01722         sint            nFaces;
+01723         sint            attId;
+01724         // build the supported VertexFormat.
+01725         uint32          retVbFlags= CVertexBuffer::PositionFlag;
+01726 
+01727 
+01728         // reset the baseMesh.
+01729         baseMesh= CMRMMesh();
+01730         // reset Tmp.
+01731         for(attId=0; attId<NL3D_MRM_MAX_ATTRIB;attId++)
+01732                 _AttributeMap[attId].clear();
+01733 
+01734 
+01735         // Compute number of attributes used by the MeshBuild.
+01736         // ========================
+01737         // Compute too 
+01738         if(mbuild.VertexFlags & CVertexBuffer::NormalFlag)
+01739         {
+01740                 baseMesh.NumAttributes++;
+01741                 retVbFlags|= CVertexBuffer::NormalFlag;
+01742         }
+01743         if(mbuild.VertexFlags & CVertexBuffer::PrimaryColorFlag)
+01744         {
+01745                 baseMesh.NumAttributes++;
+01746                 retVbFlags|= CVertexBuffer::PrimaryColorFlag;
+01747         }
+01748         if(mbuild.VertexFlags & CVertexBuffer::SecondaryColorFlag)
+01749         {
+01750                 baseMesh.NumAttributes++;
+01751                 retVbFlags|= CVertexBuffer::SecondaryColorFlag;
+01752         }
+01753         for(k=0; k<CVertexBuffer::MaxStage;k++)
+01754         {
+01755                 uint flag=CVertexBuffer::TexCoord0Flag<<k;
+01756                 if(mbuild.VertexFlags & flag)
+01757                 {
+01758                         baseMesh.NumAttributes++;
+01759                         retVbFlags|=flag;
+01760                 }
+01761         }
+01762         nlassert(baseMesh.NumAttributes<=NL3D_MRM_MAX_ATTRIB);
+01763 
+01764 
+01765         // Fill basics: Vertices and Faces materials / index to vertices.
+01766         // ========================
+01767         // Just copy vertices.
+01768         baseMesh.Vertices= mbuild.Vertices;
+01769         // Just copy SkinWeights.
+01770         if(_Skinned)
+01771                 baseMesh.SkinWeights= mbuild.SkinWeights;
+01772         // Just copy InterfaceLinks
+01773         if(_HasMeshInterfaces)
+01774                 baseMesh.InterfaceLinks= mbuild.InterfaceLinks;
+01775         // Resize faces.
+01776         nFaces= mbuild.Faces.size();
+01777         baseMesh.Faces.resize(nFaces);
+01778         for(i=0; i<nFaces; i++)
+01779         {
+01780                 // copy material Id.
+01781                 baseMesh.Faces[i].MaterialId= mbuild.Faces[i].MaterialId;
+01782                 // Copy Vertex index.
+01783                 for(j=0; j<3; j++)
+01784                 {
+01785                         baseMesh.Faces[i].Corner[j].Vertex= mbuild.Faces[i].Corner[j].Vertex;
+01786                 }
+01787         }
+01788 
+01789         // Resolve attributes discontinuities and Fill attributes of the baseMesh.
+01790         // ========================
+01791         // For all corners.
+01792         for(i=0; i<nFaces; i++)
+01793         {
+01794                 for(j=0; j<3; j++)
+01795                 {
+01796                         const CMesh::CCorner    &srcCorner= mbuild.Faces[i].Corner[j];
+01797                         CMRMCorner                              &destCorner= baseMesh.Faces[i].Corner[j];
+01798                         attId= 0;
+01799 
+01800                         // For all activated attributes in mbuild, find/insert the attribute in the baseMesh.
+01801                         // NB: 2 attributes are said to be different if they have not the same value OR if they don't lie 
+01802                         // on the same vertex. This is very important for MRM computing.
+01803                         if(mbuild.VertexFlags & CVertexBuffer::NormalFlag)
+01804                         {
+01805                                 destCorner.Attributes[attId]= findInsertNormalInBaseMesh(baseMesh, attId, destCorner.Vertex, srcCorner.Normal);
+01806                                 attId++;
+01807                         }
+01808                         if(mbuild.VertexFlags & CVertexBuffer::PrimaryColorFlag)
+01809                         {
+01810                                 destCorner.Attributes[attId]= findInsertColorInBaseMesh(baseMesh, attId, destCorner.Vertex, srcCorner.Color);
+01811                                 attId++;
+01812                         }
+01813                         if(mbuild.VertexFlags & CVertexBuffer::SecondaryColorFlag)
+01814                         {
+01815                                 destCorner.Attributes[attId]= findInsertColorInBaseMesh(baseMesh, attId, destCorner.Vertex, srcCorner.Specular);
+01816                                 attId++;
+01817                         }
+01818                         for(k=0; k<CVertexBuffer::MaxStage;k++)
+01819                         {
+01820                                 if(mbuild.VertexFlags & (CVertexBuffer::TexCoord0Flag<<k))
+01821                                 {
+01822                                         destCorner.Attributes[attId]= findInsertUvwInBaseMesh(baseMesh, attId, destCorner.Vertex, srcCorner.Uvws[k]);
+01823                                         attId++;
+01824                                 }
+01825                         }
+01826                 }
+01827         }
+01828 
+01829 
+01830 
+01831         // End. clear Tmp infos.
+01832         // ========================
+01833         // reset Tmp.
+01834         for(attId=0; attId<NL3D_MRM_MAX_ATTRIB;attId++)
+01835                 _AttributeMap[attId].clear();
+01836 
+01837         return  retVbFlags;
+01838 }
+01839 
+01840 
+01841 
+01842 // ***************************************************************************
+01843 CMesh::CSkinWeight      CMRMBuilder::normalizeSkinWeight(const CMesh::CSkinWeight &sw) const
+01844 {
+01845         uint    nbMats= 0;
+01846         static vector<CTmpVertexWeight>         sws;
+01847         sws.reserve(NL3D_MESH_SKINNING_MAX_MATRIX);
+01848         sws.clear();
+01849 
+01850         // For all weights of sw1.
+01851         uint i;
+01852         for(i=0; i<NL3D_MESH_SKINNING_MAX_MATRIX; i++)
+01853         {
+01854                 CTmpVertexWeight        vw;
+01855                 vw.MatrixId= sw.MatrixId[i];
+01856                 vw.Weight= sw.Weights[i];
+01857                 // if this weight is not null.
+01858                 if(vw.Weight>0)
+01859                 {
+01860                         // add it to the list.
+01861                         sws.push_back(vw);
+01862                         nbMats++;
+01863                 }
+01864         }
+01865 
+01866         // sort by Weight decreasing order.
+01867         sort(sws.begin(), sws.end());
+01868 
+01869 
+01870         // Then output the result to the skinWeight, normalizing.
+01871         float   sumWeight=0;
+01872         for(i= 0; i<nbMats; i++)
+01873         {
+01874                 sumWeight+= sws[i].Weight;
+01875         }
+01876 
+01877         CMesh::CSkinWeight      ret;
+01878         // Fill only needed matrix (other are rested in CMesh::CSkinWeight ctor).
+01879         for(i= 0; i<nbMats; i++)
+01880         {
+01881                 ret.MatrixId[i]= sws[i].MatrixId;
+01882                 ret.Weights[i]= sws[i].Weight / sumWeight;
+01883         }
+01884 
+01885         return ret;
+01886 }
+01887 
+01888 
+01889 // ***************************************************************************
+01890 void                    CMRMBuilder::normalizeBaseMeshSkin(CMRMMesh &baseMesh) const
+01891 {
+01892         nlassert(_Skinned);
+01893 
+01894         for(uint i=0; i<baseMesh.SkinWeights.size(); i++)
+01895         {
+01896                 baseMesh.SkinWeights[i]= normalizeSkinWeight(baseMesh.SkinWeights[i]);
+01897         }
+01898 }
+01899 
+01900 
+01901 
+01902 // ***************************************************************************
+01903 void                    CMRMBuilder::buildMeshBuildMrm(const CMRMMeshFinal &finalMRM, CMeshMRMGeom::CMeshBuildMRM &mbuild, uint32 vbFlags, uint32 nbMats, const CMesh::CMeshBuild &mb)
+01904 {
+01905         sint    i,j,k;
+01906         sint    attId;
+01907 
+01908         // reset the mbuild.
+01909         mbuild= CMeshMRMGeom::CMeshBuildMRM();
+01910         // Setup VB.
+01911 
+01912         bool useFormatExt = false;
+01913         // Check wether there are texture coordinates with more than 2 compnents, which force us to use an extended vertex format
+01914         for (k = 0; k < CVertexBuffer::MaxStage; ++k)
+01915         {
+01916                 if (
+01917                         (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
+01918                         && mb.NumCoords[k] != 2)
+01919                 {
+01920                         useFormatExt = true;
+01921                         break;
+01922                 }
+01923         }
+01924 
+01925         uint numTexCoordUsed = 0;
+01926 
+01927 
+01928         for (k = 0; k < CVertexBuffer::MaxStage; ++k)
+01929         {
+01930                 if (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
+01931                 {
+01932                         numTexCoordUsed = k;
+01933                 }
+01934         }
+01935 
+01936         if (!useFormatExt)
+01937         {
+01938                 // setup standard format
+01939                 mbuild.VBuffer.setVertexFormat(vbFlags);
+01940         }
+01941         else // setup extended format
+01942         {
+01943                 mbuild.VBuffer.clearValueEx();
+01944                 if (vbFlags & CVertexBuffer::PositionFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::Position, CVertexBuffer::Float3);
+01945                 if (vbFlags & CVertexBuffer::NormalFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::Normal, CVertexBuffer::Float3);
+01946                 if (vbFlags & CVertexBuffer::PrimaryColorFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::PrimaryColor, CVertexBuffer::UChar4);
+01947                 if (vbFlags & CVertexBuffer::SecondaryColorFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::SecondaryColor, CVertexBuffer::UChar4);
+01948                 if (vbFlags & CVertexBuffer::WeightFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::Weight, CVertexBuffer::Float4);
+01949                 if (vbFlags & CVertexBuffer::PaletteSkinFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::PaletteSkin, CVertexBuffer::UChar4);
+01950                 if (vbFlags & CVertexBuffer::FogFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::Fog, CVertexBuffer::Float1);
+01951 
+01952                 for (k = 0; k < CVertexBuffer::MaxStage; ++k)
+01953                 {
+01954                         if (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
+01955                         {
+01956                                 switch(mb.NumCoords[k])
+01957                                 {       
+01958                                         case 2:
+01959                                                 mbuild.VBuffer.addValueEx((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), CVertexBuffer::Float2);
+01960                                         break;
+01961                                         case 3:
+01962                                                 mbuild.VBuffer.addValueEx((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), CVertexBuffer::Float3);
+01963                                         break;
+01964                                         default:
+01965                                                 nlassert(0);
+01966                                         break;
+01967                                 }
+01968                         }
+01969                 }
+01970                 mbuild.VBuffer.initEx();
+01971         }
+01972 
+01973         
+01974 
+01975 
+01976         // Setup the VertexBuffer.
+01977         // ========================
+01978         // resize the VB.
+01979         mbuild.VBuffer.setNumVertices(finalMRM.Wedges.size());
+01980         // Setup SkinWeights.
+01981         if(_Skinned)
+01982                 mbuild.SkinWeights.resize(finalMRM.Wedges.size());
+01983 
+01984         // fill the VB.
+01985         for(i=0; i<(sint)finalMRM.Wedges.size(); i++)
+01986         {
+01987                 const CMRMMeshFinal::CWedge     &wedge= finalMRM.Wedges[i];
+01988 
+01989                 // setup Vertex.
+01990                 mbuild.VBuffer.setVertexCoord(i, wedge.Vertex);
+01991 
+01992                 // seutp attributes.
+01993                 attId= 0;
+01994 
+01995                 // For all activated attributes in mbuild, retriev the attribute from the finalMRM.
+01996                 if(vbFlags & CVertexBuffer::NormalFlag)
+01997                 {
+01998                         mbuild.VBuffer.setNormalCoord(i, wedge.Attributes[attId] );
+01999                         attId++;
+02000                 }
+02001                 if(vbFlags & CVertexBuffer::PrimaryColorFlag)
+02002                 {
+02003                         mbuild.VBuffer.setColor(i, attToColor(wedge.Attributes[attId]) );
+02004                         attId++;
+02005                 }
+02006                 if(vbFlags & CVertexBuffer::SecondaryColorFlag)
+02007                 {
+02008                         mbuild.VBuffer.setSpecular(i, attToColor(wedge.Attributes[attId]) );
+02009                         attId++;
+02010                 }
+02011                 for(k=0; k<CVertexBuffer::MaxStage;k++)
+02012                 {
+02013                         if(vbFlags & (CVertexBuffer::TexCoord0Flag<<k))
+02014                         {
+02015                                 switch(mb.NumCoords[k])
+02016                                 {
+02017                                         case 2:                         
+02018                                                 mbuild.VBuffer.setTexCoord(i, k, (CUV) attToUvw(wedge.Attributes[attId]) );
+02019                                         break;
+02020                                         case 3:
+02021                                         {
+02022                                                 CUVW uvw = attToUvw(wedge.Attributes[attId]);
+02023                                                 mbuild.VBuffer.setValueFloat3Ex((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), i, uvw.U, uvw.V, uvw.W);
+02024                                         }
+02025                                         break;
+02026                                         default:
+02027                                                 nlassert(0);
+02028                                         break;
+02029                                 }
+02030                                 attId++;
+02031                         }
+02032                 }
+02033 
+02034                 // Setup SkinWeights.
+02035                 if(_Skinned)
+02036                 {
+02037                         mbuild.SkinWeights[i]= wedge.VertexSkin;
+02038                 }
+02039         }
+02040 
+02041 
+02042         // Build Lods.
+02043         // ========================
+02044         // resize
+02045         mbuild.Lods.resize(finalMRM.Lods.size());
+02046         // fill.
+02047         for(i=0; i<(sint)finalMRM.Lods.size(); i++)
+02048         {
+02049                 const CMRMMeshFinal::CLod       &srcLod= finalMRM.Lods[i];
+02050                 CMeshMRMGeom::CLod                      &destLod= mbuild.Lods[i];
+02051 
+02052                 // Basic.
+02053                 //---------
+02054 
+02055                 // Copy NWedges infos.
+02056                 destLod.NWedges= srcLod.NWedges;
+02057                 // Copy Geomorphs infos.
+02058                 destLod.Geomorphs= srcLod.Geomorphs;
+02059 
+02060 
+02061                 // Reorder faces by rdrpass.
+02062                 //---------
+02063 
+02064                 // First count the number of faces used by this LOD for each material 
+02065                 vector<sint>    matCount;
+02066                 // resize, and reset to 0.
+02067                 matCount.clear();
+02068                 matCount.resize(nbMats, 0);
+02069                 // For each face of this Lods, incr the mat face counter.
+02070                 for(j= 0; j<(sint)srcLod.Faces.size(); j++)
+02071                 {
+02072                         sint    matId= srcLod.Faces[j].MaterialId;
+02073                         nlassert(matId>=0);
+02074                         nlassert(matId<(sint)nbMats);
+02075                         // increment the refcount of this material by this LOD.
+02076                         matCount[matId]++;
+02077                 }
+02078 
+02079                 // Then for each material not empty, create a rdrPass, and ref it for this material.
+02080                 vector<sint>    rdrPassIndex;   // material to rdrPass map.
+02081                 rdrPassIndex.resize(nbMats);
+02082                 for(j=0; j<(sint)nbMats; j++)
+02083                 {
+02084                         if(matCount[j]==0)
+02085                                 rdrPassIndex[j]= -1;
+02086                         else
+02087                         {
+02088                                 // map material to rdrPass.
+02089                                 sint    idRdrPass= destLod.RdrPass.size();
+02090                                 rdrPassIndex[j]= idRdrPass;
+02091                                 // create a rdrPass.
+02092                                 destLod.RdrPass.push_back(CMeshMRMGeom::CRdrPass());
+02093                                 // assign the good materialId to this rdrPass.
+02094                                 destLod.RdrPass[idRdrPass].MaterialId= j;
+02095                                 // reserve the array of faces of this rdrPass.
+02096                                 destLod.RdrPass[idRdrPass].PBlock.reserveTri(matCount[j]);
+02097                         }
+02098                 }
+02099 
+02100                 // Then for each face, add it to the good rdrPass of this Lod.
+02101                 for(j= 0; j<(sint)srcLod.Faces.size(); j++)
+02102                 {
+02103                         sint    matId= srcLod.Faces[j].MaterialId;
+02104                         sint    idRdrPass= rdrPassIndex[matId];
+02105                         // add this face to the good rdrPass.
+02106                         sint    w0= srcLod.Faces[j].WedgeId[0];
+02107                         sint    w1= srcLod.Faces[j].WedgeId[1];
+02108                         sint    w2= srcLod.Faces[j].WedgeId[2];
+02109                         destLod.RdrPass[idRdrPass].PBlock.addTri(w0, w1, w2);
+02110                 }
+02111 
+02112 
+02113                 // Build skin info for this Lod.
+02114                 //---------
+02115                 for(j=0; j<NL3D_MESH_SKINNING_MAX_MATRIX; j++)
+02116                 {
+02117                         destLod.InfluencedVertices[j].clear();
+02118                 }
+02119                 destLod.MatrixInfluences.clear();
+02120                 if(_Skinned)
+02121                 {
+02122                         // This is the set which tell what wedge has already been inserted.
+02123                         set<uint>       wedgeInfSet;
+02124 
+02125                         // First, build the list of vertices influenced by this Lod.
+02126                         for(j= 0; j<(sint)srcLod.Faces.size(); j++)
+02127                         {
+02128                                 for(k=0; k<3; k++)
+02129                                 {
+02130                                         sint    wedgeId= srcLod.Faces[j].WedgeId[k];
+02131                                         // If it is a geomorph
+02132                                         if(wedgeId<finalMRM.NGeomSpace)
+02133                                         {
+02134                                                 // add the start and end to the list (if not here). NB: wedgeId is both the id 
+02135                                                 // of the dest wedge, and the id of the geomorph.
+02136                                                 sint    wedgeStartId= destLod.Geomorphs[wedgeId].Start;
+02137                                                 sint    wedgeEndId= destLod.Geomorphs[wedgeId].End;
+02138                                                 uint    nMatUsedStart= finalMRM.Wedges[wedgeStartId].NSkinMatUsed;
+02139                                                 uint    nMatUsedEnd= finalMRM.Wedges[wedgeEndId].NSkinMatUsed;
+02140 
+02141                                                 // if insertion in the set work, add to the good array.
+02142                                                 if( wedgeInfSet.insert(wedgeStartId).second )
+02143                                                         destLod.InfluencedVertices[nMatUsedStart-1].push_back(wedgeStartId);
+02144                                                 if( wedgeInfSet.insert(wedgeEndId).second )
+02145                                                         destLod.InfluencedVertices[nMatUsedEnd-1].push_back(wedgeEndId);
+02146                                         }
+02147                                         else
+02148                                         {
+02149                                                 uint    nMatUsed= finalMRM.Wedges[wedgeId].NSkinMatUsed;
+02150 
+02151                                                 // just add this wedge to the list (if not here).
+02152                                                 // if insertion in the set work, add to the array.
+02153                                                 if( wedgeInfSet.insert(wedgeId).second )
+02154                                                         destLod.InfluencedVertices[nMatUsed-1].push_back(wedgeId);
+02155                                         }
+02156                                 }
+02157                         }
+02158 
+02159                         // Optimisation: for better cache, sort the destLod.InfluencedVertices in increasing order.
+02160                         for(j=0; j<NL3D_MESH_SKINNING_MAX_MATRIX; j++)
+02161                         {
+02162                                 sort(destLod.InfluencedVertices[j].begin(), destLod.InfluencedVertices[j].end());
+02163                         }
+02164 
+02165 
+02166                         // Then Build the MatrixInfluences array, for all thoses Influenced Vertices only.
+02167                         // This is the map MatrixId -> MatrixInfId.
+02168                         map<uint, uint>         matrixInfMap;
+02169 
+02170                         // For all influenced vertices, flags matrix they use.
+02171                         uint    iSkinMat;
+02172                         for(iSkinMat= 0; iSkinMat<NL3D_MESH_SKINNING_MAX_MATRIX; iSkinMat++)
+02173                         {
+02174                                 for(j= 0; j<(sint)destLod.InfluencedVertices[iSkinMat].size(); j++)
+02175                                 {
+02176                                         uint    wedgeId= destLod.InfluencedVertices[iSkinMat][j];
+02177 
+02178                                         // take the original wedge.
+02179                                         const CMRMMeshFinal::CWedge     &wedge= finalMRM.Wedges[wedgeId];
+02180                                         // For all matrix with not null influence...
+02181                                         for(k= 0; k<NL3D_MESH_SKINNING_MAX_MATRIX; k++)
+02182                                         {
+02183                                                 float   matWeight= wedge.VertexSkin.Weights[k];
+02184 
+02185                                                 // This check the validity of skin weights sort. If false, problem before in the algo.
+02186                                                 if((uint)k<iSkinMat+1)
+02187                                                 {
+02188                                                         nlassert( matWeight>0 );
+02189                                                 }
+02190                                                 else
+02191                                                 {
+02192                                                         nlassert( matWeight==0 );
+02193                                                 }
+02194                                                 // if not null influence.
+02195                                                 if(matWeight>0)
+02196                                                 {
+02197                                                         uint    matId= wedge.VertexSkin.MatrixId[k];
+02198 
+02199                                                         // search/insert the matrixInfId.
+02200                                                         map<uint, uint>::iterator       it= matrixInfMap.find(matId);
+02201                                                         if( it==matrixInfMap.end() )
+02202                                                         {
+02203                                                                 uint matInfId= destLod.MatrixInfluences.size();
+02204                                                                 matrixInfMap.insert( make_pair(matId, matInfId) );
+02205                                                                 // create the new MatrixInfluence.
+02206                                                                 destLod.MatrixInfluences.push_back(matId);
+02207                                                         }
+02208                                                 }
+02209                                         }
+02210                                 }
+02211                         }
+02212 
+02213                 }
+02214 
+02215         }
+02216 
+02217         // Indicate Skinning.
+02218         mbuild.Skinned= _Skinned;
+02219 
+02220 
+02221 
+02222         bool useTgSpace = mb.MeshVertexProgram != NULL ? mb.MeshVertexProgram->needTangentSpace() : false;
+02223 
+02224         // Construct Blend Shapes
+02226         mbuild.BlendShapes.resize (finalMRM.MRMBlendShapesFinals.size());
+02227         for (k = 0; k < (sint)mbuild.BlendShapes.size(); ++k)
+02228         {
+02229                 CBlendShape &rBS = mbuild.BlendShapes[k];
+02230                 sint32 nNbVertVB = finalMRM.Wedges.size();
+02231                 bool bIsDeltaPos = false;
+02232                 rBS.deltaPos.resize (nNbVertVB, CVector(0.0f,0.0f,0.0f));
+02233                 bool bIsDeltaNorm = false;
+02234                 rBS.deltaNorm.resize (nNbVertVB, CVector(0.0f,0.0f,0.0f));
+02235                 bool bIsDeltaUV = false;
+02236                 rBS.deltaUV.resize (nNbVertVB, CUV(0.0f,0.0f));
+02237                 bool bIsDeltaCol = false;
+02238                 rBS.deltaCol.resize (nNbVertVB, CRGBAF(0.0f,0.0f,0.0f,0.0f));
+02239                 bool bIsDeltaTgSpace = false;
+02240                 if (useTgSpace)
+02241                 {
+02242                         rBS.deltaTgSpace.resize(nNbVertVB, CVector::Null);
+02243                 }
+02244 
+02245                 rBS.VertRefs.resize (nNbVertVB, 0xffffffff);
+02246 
+02247                 for (i = 0; i < nNbVertVB; i++)
+02248                 {
+02249                         const CMRMMeshFinal::CWedge     &rWedgeRef = finalMRM.Wedges[i];
+02250                         const CMRMMeshFinal::CWedge     &rWedgeTar = finalMRM.MRMBlendShapesFinals[k].Wedges[i];
+02251 
+02252                         CVector delta = rWedgeTar.Vertex - rWedgeRef.Vertex;
+02253                         CVectorH attr;
+02254 
+02255                         if (delta.norm() > 0.001f)
+02256                         {
+02257                                 rBS.deltaPos[i] = delta;
+02258                                 rBS.VertRefs[i] = i;
+02259                                 bIsDeltaPos = true;
+02260                         }
+02261 
+02262                         attId = 0;
+02263                         if (vbFlags & CVertexBuffer::NormalFlag)
+02264                         {
+02265                                 attr = rWedgeRef.Attributes[attId];
+02266                                 CVector NormRef = CVector(attr.x, attr.y, attr.z);
+02267                                 attr = rWedgeTar.Attributes[attId];
+02268                                 CVector NormTar = CVector(attr.x, attr.y, attr.z);
+02269                                 delta = NormTar - NormRef;
+02270                                 if (delta.norm() > 0.001f)
+02271                                 {
+02272                                         rBS.deltaNorm[i] = delta;
+02273                                         rBS.VertRefs[i] = i;
+02274                                         bIsDeltaNorm = true;
+02275                                 }
+02276                                 attId++;
+02277                         }               
+02278 
+02279                         if (vbFlags & CVertexBuffer::PrimaryColorFlag)
+02280                         {
+02281                                 attr = rWedgeRef.Attributes[attId];
+02282                                 CRGBAF RGBARef = CRGBAF(attr.x/255.0f, attr.y/255.0f, attr.z/255.0f, attr.w/255.0f);
+02283                                 attr = rWedgeTar.Attributes[attId];
+02284                                 CRGBAF RGBATar = CRGBAF(attr.x/255.0f, attr.y/255.0f, attr.z/255.0f, attr.w/255.0f);
+02285                                 CRGBAF deltaRGBA = RGBATar - RGBARef;
+02286                                 if ((deltaRGBA.R*deltaRGBA.R + deltaRGBA.G*deltaRGBA.G +
+02287                                         deltaRGBA.B*deltaRGBA.B + deltaRGBA.A*deltaRGBA.A) > 0.0001f)
+02288                                 {
+02289                                         rBS.deltaCol[i] = deltaRGBA;
+02290                                         rBS.VertRefs[i] = i;
+02291                                         bIsDeltaCol = true;
+02292                                 }
+02293                                 attId++;
+02294                         }
+02295 
+02296                         if (vbFlags & CVertexBuffer::SecondaryColorFlag)
+02297                         {       // Nothing to do !
+02298                                 attId++;
+02299                         }
+02300 
+02301                         // Do that only for the UV0
+02302                         if (vbFlags & CVertexBuffer::TexCoord0Flag)
+02303                         {
+02304                                 attr = rWedgeRef.Attributes[attId];
+02305                                 CUV UVRef = CUV(attr.x, attr.y);
+02306                                 attr = rWedgeTar.Attributes[attId];
+02307                                 CUV UVTar = CUV(attr.x, attr.y);
+02308                                 CUV deltaUV = UVTar - UVRef;
+02309                                 if ((deltaUV.U*deltaUV.U + deltaUV.V*deltaUV.V) > 0.0001f)
+02310                                 {
+02311                                         rBS.deltaUV[i] = deltaUV;
+02312                                         rBS.VertRefs[i] = i;
+02313                                         bIsDeltaUV = true;
+02314                                 }
+02315                                 attId++;
+02316                         }
+02317 
+02318                         if (useTgSpace)
+02319                         {
+02320                                 attr = rWedgeRef.Attributes[attId];
+02321                                 CVector TgSpaceRef = CVector(attr.x, attr.y, attr.z);
+02322                                 attr = rWedgeTar.Attributes[attId];
+02323                                 CVector TgSpaceTar = CVector(attr.x, attr.y, attr.z);
+02324                                 delta = TgSpaceTar - TgSpaceRef;
+02325                                 if (delta.norm() > 0.001f)
+02326                                 {
+02327                                         rBS.deltaTgSpace[i] = delta;
+02328                                         rBS.VertRefs[i] = i;
+02329                                         bIsDeltaTgSpace = true;
+02330                                 }
+02331                                 attId++;
+02332                         }
+02333                         
+02334                 } // End of all vertices added in blend shape
+02335 
+02336                 // Delete unused items and calculate the number of vertex used (blended)
+02337 
+02338                 sint32 nNbVertUsed = nNbVertVB;
+02339                 sint32 nDstPos = 0;
+02340                 for (j = 0; j < nNbVertVB; ++j)
+02341                 {
+02342                         if (rBS.VertRefs[j] == 0xffffffff) // Is vertex UNused
+02343                         {
+02344                                 --nNbVertUsed;
+02345                         }
+02346                         else // Vertex used
+02347                         {
+02348                                 if (nDstPos != j)
+02349                                 {
+02350                                         rBS.VertRefs[nDstPos]   = rBS.VertRefs[j];
+02351                                         rBS.deltaPos[nDstPos]   = rBS.deltaPos[j];
+02352                                         rBS.deltaNorm[nDstPos]  = rBS.deltaNorm[j];
+02353                                         rBS.deltaUV[nDstPos]    = rBS.deltaUV[j];
+02354                                         rBS.deltaCol[nDstPos]   = rBS.deltaCol[j];
+02355                                         if (useTgSpace)
+02356                                         {
+02357                                                 rBS.deltaTgSpace[nDstPos]       = rBS.deltaTgSpace[j];
+02358                                         }
+02359                                 }
+02360                                 ++nDstPos;
+02361                         }
+02362                 }
+02363 
+02364                 if (bIsDeltaPos)
+02365                         rBS.deltaPos.resize (nNbVertUsed);
+02366                 else
+02367                         rBS.deltaPos.resize (0);
+02368 
+02369                 if (bIsDeltaNorm)
+02370                         rBS.deltaNorm.resize (nNbVertUsed);
+02371                 else
+02372                         rBS.deltaNorm.resize (0);
+02373 
+02374                 if (bIsDeltaUV)
+02375                         rBS.deltaUV.resize (nNbVertUsed);
+02376                 else
+02377                         rBS.deltaUV.resize (0);
+02378 
+02379                 if (bIsDeltaCol)
+02380                         rBS.deltaCol.resize (nNbVertUsed);
+02381                 else
+02382                         rBS.deltaCol.resize (0);
+02383 
+02384                 if (bIsDeltaTgSpace)
+02385                         rBS.deltaTgSpace.resize (nNbVertUsed);
+02386                 else
+02387                         rBS.deltaTgSpace.resize (0);
+02388 
+02389 
+02390                 rBS.VertRefs.resize (nNbVertUsed);
+02391 
+02392         }
+02393 }
+02394 
+02395 // ***************************************************************************
+02396 void CMRMBuilder::buildBlendShapes (CMRMMesh& baseMesh, 
+02397                                                                         std::vector<CMesh::CMeshBuild*> &bsList, uint32 VertexFlags)
+02398 {
+02399         uint32 i, j, k, m, destIndex;
+02400         uint32 attId;
+02401         CVectorH vh;
+02402         vector<CMRMBlendShape>  &bsMeshes= baseMesh.BlendShapes;
+02403 
+02404         bsMeshes.resize (bsList.size());
+02405 
+02406         for (i = 0; i < bsList.size(); ++i)
+02407         {
+02408                 // Construct a blend shape like a mrm mesh
+02409                 nlassert (baseMesh.Vertices.size() == bsList[i]->Vertices.size());
+02410                 bsMeshes[i].Vertices.resize (baseMesh.Vertices.size());
+02411                 bsMeshes[i].Vertices = bsList[i]->Vertices;
+02412 
+02413                 bsMeshes[i].NumAttributes = baseMesh.NumAttributes;
+02414                 for (j = 0; j < (uint32)bsMeshes[i].NumAttributes; ++j)
+02415                         bsMeshes[i].Attributes[j].resize(baseMesh.Attributes[j].size());
+02416 
+02417                 // For all corners parse the faces (given by the baseMesh) and construct blend shape mrm meshes
+02418                 for (j = 0; j < baseMesh.Faces.size(); ++j)
+02419                 for (k = 0; k < 3; ++k)
+02420                 {
+02421                         const CMesh::CCorner &srcCorner = bsList[i]->Faces[j].Corner[k];
+02422                         CMRMCorner      &neutralCorner = baseMesh.Faces[j].Corner[k];
+02423                         
+02424                         attId= 0;
+02425 
+02426                         if (VertexFlags & CVertexBuffer::NormalFlag)
+02427                         {
+02428                                 destIndex = neutralCorner.Attributes[attId];
+02429                                 vh.x = srcCorner.Normal.x;
+02430                                 vh.y = srcCorner.Normal.y;
+02431                                 vh.z = srcCorner.Normal.z;
+02432                                 vh.w = 0.0f;
+02433                                 bsMeshes[i].Attributes[attId].operator[](destIndex) = vh;
+02434                                 attId++;
+02435                         }
+02436                         if (VertexFlags & CVertexBuffer::PrimaryColorFlag)
+02437                         {
+02438                                 destIndex = neutralCorner.Attributes[attId];
+02439                                 vh.x = srcCorner.Color.R;
+02440                                 vh.y = srcCorner.Color.G;
+02441                                 vh.z = srcCorner.Color.B;
+02442                                 vh.w = srcCorner.Color.A;
+02443                                 bsMeshes[i].Attributes[attId].operator[](destIndex) = vh;
+02444                                 attId++;
+02445                         }
+02446                         if (VertexFlags & CVertexBuffer::SecondaryColorFlag)
+02447                         {
+02448                                 destIndex = neutralCorner.Attributes[attId];
+02449                                 vh.x = srcCorner.Specular.R;
+02450                                 vh.y = srcCorner.Specular.G;
+02451                                 vh.z = srcCorner.Specular.B;
+02452                                 vh.w = srcCorner.Specular.A;
+02453                                 bsMeshes[i].Attributes[attId].operator[](destIndex) = vh;
+02454                                 attId++;
+02455                         }
+02456                         for (m = 0; m < CVertexBuffer::MaxStage; ++m)
+02457                         {
+02458                                 if (VertexFlags & (CVertexBuffer::TexCoord0Flag<<m))
+02459                                 {
+02460                                         destIndex = neutralCorner.Attributes[attId];
+02461                                         vh.x = srcCorner.Uvws[m].U;
+02462                                         vh.y = srcCorner.Uvws[m].V;
+02463                                         vh.z = srcCorner.Uvws[m].W;
+02464                                         vh.w = 0.0f;
+02465                                         bsMeshes[i].Attributes[attId].operator[](destIndex) = vh;
+02466                                         attId++;
+02467                                 }
+02468                         }
+02469                 }
+02470         }
+02471 }
+02472 
+02473 
+02474 // ***************************************************************************
+02475 void    CMRMBuilder::compileMRM(const CMesh::CMeshBuild &mbuild, std::vector<CMesh::CMeshBuild*> &bsList,
+02476                                                                 const CMRMParameters &params, CMeshMRMGeom::CMeshBuildMRM &mrmMesh, 
+02477                                                                 uint numMaxMaterial)
+02478 {
+02479         // Temp data.
+02480         CMRMMesh                                                baseMesh;
+02481         vector<CMRMMeshGeom>                    lodMeshs;
+02482         CMRMMeshFinal                                   finalMRM;
+02483         vector<CMRMMeshFinal>                   finalBsMRM;
+02484         uint32  vbFlags;
+02485 
+02486 
+02487         nlassert(params.DistanceFinest>=0);
+02488         nlassert(params.DistanceMiddle > params.DistanceFinest);
+02489         nlassert(params.DistanceCoarsest > params.DistanceMiddle);
+02490 
+02491 
+02492         // Copy some parameters.
+02493         _SkinReduction= params.SkinReduction;
+02494 
+02495         // Skinning??
+02496         _Skinned= ((mbuild.VertexFlags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag);
+02497         // Skinning is OK only if SkinWeights are of same size as vertices.
+02498         _Skinned= _Skinned && ( mbuild.Vertices.size()==mbuild.SkinWeights.size() );
+02499         
+02500         // MeshInterface setuped ?
+02501         _HasMeshInterfaces= buildMRMSewingMeshes(mbuild, params.NLods, params.Divisor);
+02502 
+02503         // from mbuild, build an internal MRM mesh representation.
+02504         // vbFlags returned is the VBuffer format supported by CMRMBuilder.
+02505         // NB: skinning is removed because skinning is made in software in CMeshMRMGeom.
+02506         vbFlags= buildMrmBaseMesh(mbuild, baseMesh);
+02507 
+02508         // Construct all blend shapes in the same way we have constructed the basemesh mrm
+02509         buildBlendShapes (baseMesh, bsList, vbFlags);
+02510 
+02511         // If skinned, must ensure that skin weights have weights in ascending order.
+02512         if(_Skinned)
+02513         {
+02514                 normalizeBaseMeshSkin(baseMesh);
+02515         }
+02516 
+02517         // from this baseMesh, builds all LODs of the MRM, with geomorph info. NB: vertices/wedges are duplicated.
+02518         buildAllLods (  baseMesh, lodMeshs, params.NLods, params.Divisor );
+02519 
+02520         // From this array of LOD, build a finalMRM, by regrouping identical vertices/wedges, and compute index geomorphs.
+02521         buildFinalMRM(lodMeshs, finalMRM);
+02522 
+02523         // From this finalMRM, build output: a CMeshBuildMRM.
+02524         buildMeshBuildMrm(finalMRM, mrmMesh, vbFlags, numMaxMaterial, mbuild);
+02525 
+02526         // Copy degradation control params.
+02527         mrmMesh.DistanceFinest= params.DistanceFinest;
+02528         mrmMesh.DistanceMiddle= params.DistanceMiddle;
+02529         mrmMesh.DistanceCoarsest= params.DistanceCoarsest;
+02530 }
+02531 
+02532 
+02533 // ***************************************************************************
+02534 // ***************************************************************************
+02535 // MRM Interface system
+02536 // ***************************************************************************
+02537 // ***************************************************************************
+02538 
+02539 // ***************************************************************************
+02540 bool    CMRMBuilder::buildMRMSewingMeshes(const CMesh::CMeshBuild &mbuild, uint nWantedLods, uint divisor)
+02541 {
+02542         nlassert(nWantedLods>=1);
+02543         nlassert(divisor>=1);
+02544         if(mbuild.Interfaces.size()==0)
+02545                 return false;
+02546         // must have same size
+02547         if(mbuild.InterfaceLinks.size()!=mbuild.Vertices.size())
+02548                 return false;
+02549 
+02550         // **** For each interface, MRM-ize it and store.
+02551         _SewingMeshes.resize(mbuild.Interfaces.size());
+02552         for(uint i=0;i<mbuild.Interfaces.size();i++)
+02553         {
+02554                 _SewingMeshes[i].build(mbuild.Interfaces[i], nWantedLods, divisor);
+02555         }
+02556 
+02557 
+02558         return true;
+02559 }
+02560 
+02561 
+02562 } // NL3D
+
+ + +
                                                                                                                                                                    +
+ + -- cgit v1.2.1