# 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