Show bonus/malus timer text if available
[ryzomcore.git] / nel / src / 3d / mrm_builder.cpp
blobb035cae88a5cb6b63a249bf9773b179e9b06240d
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
19 #include "nel/3d/mrm_builder.h"
20 #include "nel/3d/mrm_parameters.h"
22 using namespace NLMISC;
23 using namespace std;
25 #ifdef DEBUG_NEW
26 #define new DEBUG_NEW
27 #endif
29 namespace NL3D
33 // ***************************************************************************
34 // ***************************************************************************
35 // Tools Methods.
36 // ***************************************************************************
37 // ***************************************************************************
40 // ***************************************************************************
41 static bool findElement(vector<sint> &array, sint elt)
43 return find(array.begin(), array.end(), elt) != array.end();
45 // ***************************************************************************
46 static bool deleteElement(vector<sint> &array, sint elt)
48 bool found=false;
49 vector<sint>::iterator it=array.begin();
51 while( (it=find(array.begin(), array.end(), elt)) != array.end() )
52 found=true, array.erase(it);
54 return found;
55 // Do not use remove<> since it desn't modify size ... (???)
56 // This doesn't seem to work.
57 //return remove(array.begin(), array.end(), elt)!=array.end();
61 // ***************************************************************************
62 // ***************************************************************************
63 // Edge Cost methods.
64 // ***************************************************************************
65 // ***************************************************************************
68 // ***************************************************************************
69 bool CMRMBuilder::vertexHasOneWedge(sint numvertex)
71 CMRMVertex &vert= TmpVertices[numvertex];
72 for(sint attId=0;attId<NumAttributes;attId++)
74 sint numwedge=-1;
75 for(sint i=0;i<(sint)vert.SharedFaces.size();i++)
77 sint w= TmpFaces[vert.SharedFaces[i]].getAssociatedWedge(attId, numvertex);
78 if(numwedge>=0 && numwedge!=w) return false;
79 else numwedge=w;
82 return true;
84 // ***************************************************************************
85 bool CMRMBuilder::vertexHasOneMaterial(sint numvertex)
87 sint matId=-1;
88 CMRMVertex &vert= TmpVertices[numvertex];
89 for(sint i=0;i<(sint)vert.SharedFaces.size();i++)
91 sint m= TmpFaces[vert.SharedFaces[i]].MaterialId;
92 if(matId>=0 && matId!=m) return false;
93 else matId=m;
95 return true;
97 // ***************************************************************************
98 bool CMRMBuilder::vertexContinue(sint numvertex)
100 return vertexHasOneWedge(numvertex) && vertexHasOneMaterial(numvertex);
102 // ***************************************************************************
103 bool CMRMBuilder::vertexClosed(sint numvertex)
105 CMRMVertex &vert= TmpVertices[numvertex];
106 map<CMRMEdge, sint> EdgeShare;
107 // Init to 0.
108 sint i;
109 for(i=0;i<(sint)vert.SharedFaces.size();i++)
111 CMRMFaceBuild &f=TmpFaces[vert.SharedFaces[i]];
112 EdgeShare[f.getEdge(0)]= 0;
113 EdgeShare[f.getEdge(1)]= 0;
114 EdgeShare[f.getEdge(2)]= 0;
116 // Inc count.
117 for(i=0;i<(sint)vert.SharedFaces.size();i++)
119 CMRMFaceBuild &f=TmpFaces[vert.SharedFaces[i]];
120 EdgeShare[f.getEdge(0)]++;
121 EdgeShare[f.getEdge(1)]++;
122 EdgeShare[f.getEdge(2)]++;
124 // Test open edges.
125 for(i=0;i<(sint)vert.SharedFaces.size();i++)
127 CMRMFaceBuild &f=TmpFaces[vert.SharedFaces[i]];
128 sint v0= f.Corner[0].Vertex;
129 sint v1= f.Corner[1].Vertex;
130 sint v2= f.Corner[2].Vertex;
131 if(EdgeShare[f.getEdge(0)]<2 && (v0==numvertex || v1==numvertex)) return false;
132 if(EdgeShare[f.getEdge(1)]<2 && (v1==numvertex || v2==numvertex)) return false;
133 if(EdgeShare[f.getEdge(2)]<2 && (v0==numvertex || v2==numvertex)) return false;
135 return true;
137 // ***************************************************************************
138 float CMRMBuilder::getDeltaFaceNormals(sint numvertex)
140 // return a positive value of Somme(|DeltaNormals|) / NNormals.
141 CMRMVertex &vert= TmpVertices[numvertex];
142 float delta=0;
143 CVector refNormal(0.f, 0.f, 0.f);
144 sint nfaces=(sint)vert.SharedFaces.size();
145 for(sint i=0;i<nfaces;i++)
147 CVector normal;
148 CVector &v0= TmpVertices[TmpFaces[i].Corner[0].Vertex].Current;
149 CVector &v1= TmpVertices[TmpFaces[i].Corner[1].Vertex].Current;
150 CVector &v2= TmpVertices[TmpFaces[i].Corner[2].Vertex].Current;
151 normal= (v1-v0)^(v2-v0);
152 normal.normalize();
153 if(i==0)
154 refNormal=normal;
155 else
156 delta+=(1-refNormal*normal);
158 if(nfaces<2)
159 return 0;
160 else
161 return delta/(nfaces-1);
163 // ***************************************************************************
164 bool CMRMBuilder::edgeContinue(const CMRMEdge &edge)
166 sint v0= edge.v0;
167 sint v1= edge.v1;
168 CMRMVertex &Vertex1=TmpVertices[v0];
170 // build list sharing edge.
171 vector<sint> deletedFaces;
172 sint i;
173 for(i=0;i<(sint)Vertex1.SharedFaces.size();i++)
175 sint numFace= Vertex1.SharedFaces[i];
176 if(TmpFaces[numFace].hasVertex(v1))
177 deletedFaces.push_back(numFace);
180 sint matId=-1;
181 // test if faces have same material.
182 for(i=0;i<(sint)deletedFaces.size();i++)
184 sint m;
185 m= TmpFaces[deletedFaces[i]].MaterialId;
186 if(matId>=0 && matId!=m) return false;
187 else matId=m;
190 // test if faces have same wedge (for all att).
191 for(sint attId=0;attId<NumAttributes;attId++)
193 sint numwedge1=-1,numwedge2=-1;
194 for(i=0;i<(sint)deletedFaces.size();i++)
196 sint w;
197 w= TmpFaces[deletedFaces[i]].getAssociatedWedge(attId, v0);
198 if(numwedge1>=0 && numwedge1!=w) return false;
199 else numwedge1=w;
200 w= TmpFaces[deletedFaces[i]].getAssociatedWedge(attId, v1);
201 if(numwedge2>=0 && numwedge2!=w) return false;
202 else numwedge2=w;
206 return true;
208 // ***************************************************************************
209 bool CMRMBuilder::edgeNearUniqueMatFace(const CMRMEdge &edge)
211 sint v0= edge.v0;
212 sint v1= edge.v1;
213 CMRMVertex &Vertex1=TmpVertices[v0];
215 // build list sharing edge.
216 vector<sint> deletedFaces;
217 sint i;
218 for(i=0;i<(sint)Vertex1.SharedFaces.size();i++)
220 sint numFace= Vertex1.SharedFaces[i];
221 if(TmpFaces[numFace].hasVertex(v1))
222 deletedFaces.push_back(numFace);
225 // test if faces are not isolated OneMaterial faces.
226 for(i=0;i<(sint)deletedFaces.size();i++)
228 CMRMFaceBuild &f=TmpFaces[deletedFaces[i]];
229 if( !edgeContinue(f.getEdge(0)) &&
230 !edgeContinue(f.getEdge(1)) &&
231 !edgeContinue(f.getEdge(2)))
232 return true;
235 return false;
238 // ***************************************************************************
239 float CMRMBuilder::computeEdgeCost(const CMRMEdge &edge)
241 sint v1= edge.v0;
242 sint v2= edge.v1;
243 // more expensive is the edge, later it will collapse.
246 // **** standard cost
248 // compute size of the edge.
249 float cost=(TmpVertices[v1].Current-TmpVertices[v2].Current).norm();
251 // compute "curvature" of the edge.
252 float faceCost= (getDeltaFaceNormals(v1)+getDeltaFaceNormals(v2));
253 // totally plane faces (faceCost==0) must be collapsed with respect to size (and not random if cost==0).
254 // else we may have Plane Mesh (like flags) that will collapse in a very ugly way.
255 faceCost= max(faceCost, 0.01f);
257 // modulate size with curvature.
258 cost*= faceCost;
260 // Like H.Hope, add a weight on discontinuities..
261 if( !vertexContinue(v1) && !vertexContinue(v2) )
263 // Nb: don't do this on discontinuities edges, unless the unique material face will collapse (pffiou!!).
264 if( edgeContinue(edge) || edgeNearUniqueMatFace(edge) )
265 cost*=4;
268 // **** Interface Sewing cost
269 if(_HasMeshInterfaces)
271 // if the 2 vertices come from a Sewing Interface mesh (must be a real interface id)
272 sint meshSewingId= TmpVertices[v1].InterfaceLink.InterfaceId;
273 if( meshSewingId>=0 && TmpVertices[v2].InterfaceLink.InterfaceId>=0 )
275 // if the 2 vertices come from the same Sewing Interface mesh
276 if( meshSewingId == TmpVertices[v2].InterfaceLink.InterfaceId )
278 // Then the edge is one of the sewing interface mesh. must do special things for it
279 CMRMSewingMesh &sewingMesh= _SewingMeshes[meshSewingId];
280 uint dummy;
282 // get the sewing edge id
283 CMRMEdge sewingEdge;
284 sewingEdge.v0= TmpVertices[v1].InterfaceLink.InterfaceVertexId;
285 sewingEdge.v1= TmpVertices[v2].InterfaceLink.InterfaceVertexId;
286 // if the current sewing lod want to collapse this edge
287 sint collapseId= sewingMesh.mustCollapseEdge(_CurrentLodComputed, sewingEdge, dummy);
288 if(collapseId>=0)
290 // Then set a negative priority (ie will collapse as soon as possible). from -N to -1.
291 // NB: sort them according to collapseId
292 cost= (float)(-sewingMesh.getNumCollapseEdge(_CurrentLodComputed) + collapseId);
294 else
296 // This edge must not collapse at this Lod, set an infinite priority (hope will never collapse).
297 cost= FLT_MAX;
300 else
302 /* The edge is between 2 interfaces but not the same. If we collide it we'll have holes!
303 This problem arise if space beetween interfaces is small. eg: if we setup an interface beetween
304 hair and head, and another one beetween head and torso, then we'll have this problem in the
305 back of the neck.
306 The solution is to make a big big cost to hope we'll never collide them (else Holes...)!!
307 Don't use FLT_MAX to still have a correct order if we don't have choice...
309 cost*= 10000;
314 return cost;
320 // ***************************************************************************
321 // ***************************************************************************
322 // Collapse Methods.
323 // ***************************************************************************
324 // ***************************************************************************
327 // ***************************************************************************
328 bool CMRMBuilder::faceShareWedges(CMRMFaceBuild *face, sint attribId, sint numVertex1, sint numVertex2)
330 sint numWedge1= face->getAssociatedWedge(attribId, numVertex1);
331 sint numWedge2= face->getAssociatedWedge(attribId, numVertex2);
332 if(numWedge1<0) return false;
333 if(numWedge2<0) return false;
335 CMRMAttribute &w1= TmpAttributes[attribId][numWedge1];
336 CMRMAttribute &w2= TmpAttributes[attribId][numWedge2];
337 return w1.Shared && w2.Shared && w1.NbSharedFaces>0 && w2.NbSharedFaces>0;
341 // ***************************************************************************
342 void CMRMBuilder::insertFaceIntoEdgeList(CMRMFaceBuild &f)
344 float len;
345 if(f.ValidIt0)
347 len= computeEdgeCost(f.getEdge(0));
348 f. It0= EdgeCollapses.insert( TEdgeMap::value_type( len, CMRMEdgeFace(f.getEdge(0),&f) ) );
350 if(f.ValidIt1)
352 len= computeEdgeCost(f.getEdge(1));
353 f. It1= EdgeCollapses.insert( TEdgeMap::value_type( len, CMRMEdgeFace(f.getEdge(1),&f) ) );
355 if(f.ValidIt2)
357 len= computeEdgeCost(f.getEdge(2));
358 f. It2= EdgeCollapses.insert( TEdgeMap::value_type( len, CMRMEdgeFace(f.getEdge(2),&f) ) );
361 // ***************************************************************************
362 void CMRMBuilder::removeFaceFromEdgeList(CMRMFaceBuild &f)
364 if(f.ValidIt0)
365 EdgeCollapses.erase(f.It0);
366 if(f.ValidIt1)
367 EdgeCollapses.erase(f.It1);
368 if(f.ValidIt2)
369 EdgeCollapses.erase(f.It2);
374 // ***************************************************************************
375 struct CTmpVertexWeight
377 uint32 MatrixId;
378 float Weight;
379 // For find().
380 bool operator==(const CTmpVertexWeight &o) const
382 return MatrixId==o.MatrixId;
384 // For sort().
385 bool operator<(const CTmpVertexWeight &o) const
387 return Weight>o.Weight;
393 // ***************************************************************************
394 CMesh::CSkinWeight CMRMBuilder::collapseSkinWeight(const CMesh::CSkinWeight &sw1, const CMesh::CSkinWeight &sw2, float interValue) const
396 // If fast interpolation.
397 if(interValue==0)
398 return sw1;
399 if(interValue==1)
400 return sw2;
402 // else, must blend a skinWeight: must identify matrix which exist in the 2 sws, and add new ones.
403 uint nbMats1=0;
404 uint nbMats2=0;
405 static vector<CTmpVertexWeight> sws;
406 sws.reserve(NL3D_MESH_SKINNING_MAX_MATRIX * 2);
407 sws.clear();
409 // For all weights of sw1.
410 uint i;
411 for(i=0; i<NL3D_MESH_SKINNING_MAX_MATRIX; i++)
413 CTmpVertexWeight vw;
414 vw.MatrixId= sw1.MatrixId[i];
415 vw.Weight= sw1.Weights[i]*(1-interValue);
416 // if this weight is not null.
417 if(vw.Weight>0)
419 // add it to the list.
420 sws.push_back(vw);
422 // For skinning reduction.
423 if(sw1.Weights[i]>0)
424 nbMats1++;
428 // For all weights of sw1.
429 for(i=0; i<NL3D_MESH_SKINNING_MAX_MATRIX; i++)
431 CTmpVertexWeight vw;
432 vw.MatrixId= sw2.MatrixId[i];
433 vw.Weight= sw2.Weights[i]*(interValue);
434 // if this weight is not null.
435 if(vw.Weight>0)
437 // add it or add influence to the matrix.
438 vector<CTmpVertexWeight>::iterator it= find(sws.begin(), sws.end(), vw);
439 if(it== sws.end())
440 sws.push_back(vw);
441 else
442 it->Weight+= vw.Weight;
444 // For skinning reduction.
445 if(sw2.Weights[i]>0)
446 nbMats2++;
450 // Then keep just the best.
451 // sort by Weight decreasing order.
452 sort(sws.begin(), sws.end());
454 // clamp the result to the wanted max matrix.
455 uint nbMatsOut = 0;
456 switch(_SkinReduction)
458 case CMRMParameters::SkinReductionMin:
459 nbMatsOut= min(nbMats1, nbMats2);
460 break;
461 case CMRMParameters::SkinReductionMax:
462 nbMatsOut= max(nbMats1, nbMats2);
463 break;
464 case CMRMParameters::SkinReductionBest:
465 nbMatsOut= min( (uint)sws.size(), (uint)NL3D_MESH_SKINNING_MAX_MATRIX );
466 break;
467 default:
468 nlstop;
470 // For security.
471 nbMatsOut= min(nbMatsOut, (uint)sws.size());
472 nlassert(nbMatsOut<=NL3D_MESH_SKINNING_MAX_MATRIX);
475 // Then output the result to the skinWeight, normalizing.
476 float sumWeight=0;
477 for(i= 0; i<nbMatsOut; i++)
479 sumWeight+= sws[i].Weight;
482 CMesh::CSkinWeight ret;
483 // Fill only needed matrix (other are rested in CMesh::CSkinWeight ctor).
484 for(i= 0; i<nbMatsOut; i++)
486 ret.MatrixId[i]= sws[i].MatrixId;
487 ret.Weights[i]= sws[i].Weight / sumWeight;
490 return ret;
493 // ***************************************************************************
494 sint CMRMBuilder::collapseEdge(const CMRMEdge &edge)
496 sint i,j;
497 float InterValue;
498 sint edgeV1=edge.v0;
499 sint edgeV2=edge.v1;
502 // 0. collapse the vertices.
503 //==========================
505 // edge.Vertex1 kept, but morphed.
506 // edge.Vertex2 deleted, and must know on which vertex it collapse.
507 CMRMVertex &Vertex1=TmpVertices[edgeV1], &Vertex2=TmpVertices[edgeV2];
509 // Interpolation choice.
510 // Default is to interpolate vertex 0 to the middle of the edge.
511 InterValue=0.5;
512 //InterValue=1;
513 // **** If at least one vertex of the edge is on a mesh sewing interface, must change InterValue
514 if( _HasMeshInterfaces && (Vertex1.InterfaceLink.InterfaceId>=0 || Vertex2.InterfaceLink.InterfaceId>=0) )
516 // If this is an edge of a mesh sewing interface
517 if(Vertex1.InterfaceLink.InterfaceId==Vertex2.InterfaceLink.InterfaceId)
519 // Then the edge is one of the sewing interface mesh. must do special things for it
520 CMRMSewingMesh &sewingMesh= _SewingMeshes[Vertex1.InterfaceLink.InterfaceId];
522 // get the sewing edge id
523 CMRMEdge sewingEdge;
524 sewingEdge.v0= Vertex1.InterfaceLink.InterfaceVertexId;
525 sewingEdge.v1= Vertex2.InterfaceLink.InterfaceVertexId;
527 // Get the edge in the sewing mesh which is said to be collapsed
528 uint vertToCollapse;
529 sint collapseId= sewingMesh.mustCollapseEdge(_CurrentLodComputed, sewingEdge, vertToCollapse);
530 // if exist
531 if(collapseId>=0)
533 // if it is v0 which must collapse, then InterValue=1
534 if(vertToCollapse==(uint)sewingEdge.v0)
535 InterValue= 1;
536 else
537 InterValue= 0;
540 else
542 // This should not happens. But it is still possible if this edge don't want to collapse but if their
543 // is no more choice. Take a default value
544 InterValue= 0;
547 else
549 // must collapse to the vertex on the sewing interface (as if it was open)
550 if(Vertex1.InterfaceLink.InterfaceId>=0)
552 // NB: it is possible that both vertices are on a different sewing interface... still collapse (must have to)
553 InterValue= 0;
555 else
557 // Then Vertex2 is on a sewing interface, collapse to it
558 InterValue= 1;
562 // **** Else, on special cases, it is much more efficient to interpolate at start or at end of edge.
563 else
565 // If one vertex is "open", ie his shared faces do not represent a closed Fan, then interpolate to this one,
566 // so the mesh has the same silhouette.
567 bool vc1= vertexClosed(edgeV1);
568 bool vc2= vertexClosed(edgeV2);
569 if(!vc1 && vc2) InterValue=0;
570 else if(vc1 && !vc2) InterValue=1;
571 else
573 // Do the same test but with vertex continue: it is preferable to not move the boundaries
574 // of a material, or a mapping.
575 bool vc1= vertexContinue(edgeV1);
576 bool vc2= vertexContinue(edgeV2);
577 if(!vc1 && vc2) InterValue=0;
578 if(vc1 && !vc2) InterValue=1;
581 /*BENCH_TotalCollapses++;
582 if(InterValue==0.5)
583 BENCH_MiddleCollapses++;*/
585 // Collapse the Vertex.
586 //========================
587 Vertex1.Current= Vertex1.Current*(1-InterValue) + Vertex2.Current*InterValue;
588 for (i = 0; i < (sint)Vertex1.BSCurrent.size(); ++i)
589 Vertex1.BSCurrent[i] = Vertex1.BSCurrent[i]*(1-InterValue) + Vertex2.BSCurrent[i]*InterValue;
590 Vertex2.CollapsedTo= edgeV1;
591 if(_Skinned)
592 Vertex1.CurrentSW= collapseSkinWeight(Vertex1.CurrentSW, Vertex2.CurrentSW, InterValue);
593 if( _HasMeshInterfaces )
594 Vertex1.InterfaceLink= InterValue<0.5f? Vertex1.InterfaceLink : Vertex2.InterfaceLink;
596 // \todo yoyo: TODO_BUG: Don't know why, but vertices may point on deleted faces.
597 // Temp: we destroy here thoses face from SharedFaces...
598 for(i=0;i<(sint)Vertex1.SharedFaces.size();i++)
600 sint numFace= Vertex1.SharedFaces[i];
601 if(TmpFaces[numFace].Deleted)
602 deleteElement(Vertex1.SharedFaces, numFace), i--;
604 for(i=0;i<(sint)Vertex2.SharedFaces.size();i++)
606 sint numFace= Vertex2.SharedFaces[i];
607 if(TmpFaces[numFace].Deleted)
608 deleteElement(Vertex2.SharedFaces, numFace), i--;
612 // Build Neighbor faces.
613 vector<sint> neighboorFaces;
614 for(i=0;i<(sint)Vertex1.SharedFaces.size();i++)
616 sint numFace= Vertex1.SharedFaces[i];
617 if(!findElement(neighboorFaces, numFace))
618 neighboorFaces.push_back(numFace);
620 for(i=0;i<(sint)Vertex2.SharedFaces.size();i++)
622 sint numFace= Vertex2.SharedFaces[i];
623 if(!findElement(neighboorFaces, numFace))
624 neighboorFaces.push_back(numFace);
627 // Build faces which will be destroyed (may 1 or 2, maybe more for non conventionnal meshes).
628 vector<sint> deletedFaces;
629 for(i=0;i<(sint)Vertex1.SharedFaces.size();i++)
631 sint numFace= Vertex1.SharedFaces[i];
632 nlassert(!TmpFaces[numFace].Deleted);
633 if(TmpFaces[numFace].hasVertex(edgeV2))
634 deletedFaces.push_back(numFace);
638 // 1. Collapse the wedges.
639 //========================
641 // For ALL Attributes.
642 for(sint attId=0;attId<NumAttributes;attId++)
644 // a/ Stock the wedge interpolation in each destroyed face.
645 //------------------------------------------------------
646 for(i=0;i<(sint)deletedFaces.size();i++)
648 CMRMFaceBuild &face= TmpFaces[deletedFaces[i]];
650 CVectorH &w0= TmpAttributes[attId][ face.getAssociatedWedge(attId, edgeV1) ].Current;
651 CVectorH &w1= TmpAttributes[attId][ face.getAssociatedWedge(attId, edgeV2) ].Current;
653 CVectorH &itp= face.InterpolatedAttribute;
654 itp.x= w0.x*(1-InterValue) + w1.x*InterValue;
655 itp.y= w0.y*(1-InterValue) + w1.y*InterValue;
656 itp.z= w0.z*(1-InterValue) + w1.z*InterValue;
657 itp.w= w0.w*(1-InterValue) + w1.w*InterValue;
659 for (j = 0; j < (sint)face.BSInterpolated.size(); ++j)
661 CVectorH &w0 = TmpAttributes[attId][face.getAssociatedWedge(attId, edgeV1)].BSCurrent[j];
662 CVectorH &w1 = TmpAttributes[attId][face.getAssociatedWedge(attId, edgeV2)].BSCurrent[j];
663 CVectorH &itb = face.BSInterpolated[j];
664 itb.x = w0.x*(1-InterValue) + w1.x*InterValue;
665 itb.y = w0.y*(1-InterValue) + w1.y*InterValue;
666 itb.z = w0.z*(1-InterValue) + w1.z*InterValue;
667 itb.w = w0.w*(1-InterValue) + w1.w*InterValue;
672 // b/ Build wedge list to be modify.
673 //----------------------------------
674 vector<sint> wedges;
676 for(i=0;i<(sint)neighboorFaces.size();i++)
678 CMRMFaceBuild &face= TmpFaces[neighboorFaces[i]];
679 sint numWedge;
681 numWedge= face.getAssociatedWedge(attId, edgeV1);
682 if(numWedge>=0 && !findElement(wedges, numWedge))
683 wedges.push_back(numWedge);
685 numWedge= face.getAssociatedWedge(attId, edgeV2);
686 if(numWedge>=0 && !findElement(wedges, numWedge))
687 wedges.push_back(numWedge);
691 // c/ Count numFaces which point on those wedges. (- deleted faces).
692 //------------------------------------------------------------------
694 for(i=0;i<(sint)wedges.size();i++)
696 sint numWedge= wedges[i];
697 CMRMAttribute &wedge= TmpAttributes[attId][numWedge];
699 wedge.NbSharedFaces=0;
700 wedge.Shared=false;
702 // Count total ref count.
703 for(j=0;j<(sint)neighboorFaces.size();j++)
705 if(TmpFaces[neighboorFaces[j]].hasWedge(attId, numWedge))
706 wedge.NbSharedFaces++;
709 // Minus deleted faces.
710 for(j=0;j<(sint)deletedFaces.size();j++)
712 if(TmpFaces[deletedFaces[j]].hasWedge(attId, numWedge))
714 wedge.NbSharedFaces--;
715 wedge.Shared=true;
716 wedge.InterpolatedFace=deletedFaces[j];
722 // d/ Collapse wedge following 3 possibles cases.
723 //-----------------------------------------------
726 for(i=0;i<(sint)wedges.size();i++)
728 sint numWedge= wedges[i];
729 CMRMAttribute &wedge= TmpAttributes[attId][numWedge];
731 // if wedge not shared...
732 if(!wedge.Shared)
734 // We've got an "exterior wedge" which lost no corner => do not merge it nor delete it.
735 // Leave it as the same value (extrapolate it may not be a good solution).
737 else
739 // if wedge dissapears, notify.
740 if(wedge.NbSharedFaces==0)
742 wedge.CollapsedTo=-2;
743 // Do not change his value. (as specified in Hope article).
745 else
747 CMRMFaceBuild &face= TmpFaces[wedge.InterpolatedFace];
749 // Must interpolate it.
750 wedge.Current= face.InterpolatedAttribute;
751 wedge.BSCurrent = face.BSInterpolated;
753 // Must merge the wedge of the second vertex on first
754 // ONLY IF 2 interpolated wedges are shared and NbSharedFaces!=0.
755 if( numWedge==face.getAssociatedWedge(attId, edgeV2) &&
756 faceShareWedges(&face, attId, edgeV1, edgeV2) )
758 wedge.CollapsedTo= face.getAssociatedWedge(attId, edgeV1);
766 // 3. collapse faces.
767 //===================
769 // delete face shared by edge.
770 for(i=0;i<(sint)deletedFaces.size();i++)
772 sint numFace= deletedFaces[i];
773 TmpFaces[numFace].Deleted=true;
775 // release edges from list.
776 removeFaceFromEdgeList(TmpFaces[numFace]);
777 // invalid all it!!
778 TmpFaces[numFace].invalidAllIts(EdgeCollapses);
781 // delete from vertex1 and 2 the deleted faces.
782 deleteElement( Vertex1.SharedFaces, numFace);
783 deleteElement( Vertex2.SharedFaces, numFace);
787 // must ref correctly the faces.
788 for(i=0;i<(sint)neighboorFaces.size();i++)
790 CMRMFaceBuild &face=TmpFaces[neighboorFaces[i]];
792 // good vertices
793 if(face.Corner[0].Vertex ==edgeV2) face.Corner[0].Vertex=edgeV1;
794 if(face.Corner[1].Vertex ==edgeV2) face.Corner[1].Vertex=edgeV1;
795 if(face.Corner[2].Vertex ==edgeV2) face.Corner[2].Vertex=edgeV1;
796 // nb: doesn't matter if deletedFaces are modified...
798 // good wedges
799 for(sint attId=0;attId<NumAttributes;attId++)
801 sint newWedge;
802 newWedge= TmpAttributes[attId][ face.Corner[0].Attributes[attId] ].CollapsedTo;
803 if(newWedge>=0) face.Corner[0].Attributes[attId]= newWedge;
804 newWedge= TmpAttributes[attId][ face.Corner[1].Attributes[attId] ].CollapsedTo;
805 if(newWedge>=0) face.Corner[1].Attributes[attId]= newWedge;
806 newWedge= TmpAttributes[attId][ face.Corner[2].Attributes[attId] ].CollapsedTo;
807 if(newWedge>=0) face.Corner[2].Attributes[attId]= newWedge;
810 // good edges.
811 /* Those ones are updated in collapseEdges(): they are removed from the edgeCollapseList,
812 then they are re-inserted with good Vertex indices.
817 // The vertex1 has now the shared env of vertex2.
818 Vertex1.SharedFaces.insert(Vertex1.SharedFaces.end(), Vertex2.SharedFaces.begin(),
819 Vertex2.SharedFaces.end());
822 return (sint)deletedFaces.size();
826 // ***************************************************************************
827 sint CMRMBuilder::followVertex(sint i)
829 CMRMVertex &vert=TmpVertices[i];
830 if(vert.CollapsedTo>=0)
831 return followVertex(vert.CollapsedTo);
832 else
833 return i;
835 // ***************************************************************************
836 sint CMRMBuilder::followWedge(sint attribId, sint i)
838 CMRMAttribute &wedge= TmpAttributes[attribId][i];
839 if(wedge.CollapsedTo>=0)
840 return followWedge(attribId, wedge.CollapsedTo);
841 else
842 return i;
846 // ***************************************************************************
847 // ***************************************************************************
848 // Mesh Level method.
849 // ***************************************************************************
850 // ***************************************************************************
853 // ***************************************************************************
854 CMRMBuilder::CMRMBuilder()
856 NumAttributes= 0;
857 _Skinned= false;
858 _HasMeshInterfaces= false;
861 // ***************************************************************************
862 void CMRMBuilder::init(const CMRMMesh &baseMesh)
864 sint i, attId;
867 // First clear ALL.
868 TmpVertices.clear();
869 for(attId=0;attId<NL3D_MRM_MAX_ATTRIB;attId++)
871 TmpAttributes[attId].clear();
873 TmpFaces.clear();
874 EdgeCollapses.clear();
877 // resize.
878 NumAttributes= baseMesh.NumAttributes;
879 TmpVertices.resize(baseMesh.Vertices.size());
880 for(attId=0;attId<NumAttributes;attId++)
882 TmpAttributes[attId].resize(baseMesh.Attributes[attId].size());
884 TmpFaces.resize(baseMesh.Faces.size());
887 // Then copy.
888 for(i=0;i<(sint)baseMesh.Vertices.size();i++)
890 TmpVertices[i].Current= TmpVertices[i].Original= baseMesh.Vertices[i];
891 TmpVertices[i].BSCurrent.resize(baseMesh.BlendShapes.size());
892 for(uint32 j = 0; j <baseMesh.BlendShapes.size() ;++j)
893 TmpVertices[i].BSCurrent[j]= baseMesh.BlendShapes[j].Vertices[i];
894 if(_Skinned)
895 TmpVertices[i].CurrentSW= TmpVertices[i].OriginalSW= baseMesh.SkinWeights[i];
896 if(_HasMeshInterfaces)
897 TmpVertices[i].InterfaceLink= baseMesh.InterfaceLinks[i];
899 for(attId=0;attId<NumAttributes;attId++)
901 for(i=0;i<(sint)baseMesh.Attributes[attId].size();i++)
903 TmpAttributes[attId][i].Current= TmpAttributes[attId][i].Original=
904 baseMesh.Attributes[attId][i];
905 TmpAttributes[attId][i].BSCurrent.resize(baseMesh.BlendShapes.size());
906 for(uint32 j = 0; j <baseMesh.BlendShapes.size() ;++j)
907 TmpAttributes[attId][i].BSCurrent[j]= baseMesh.BlendShapes[j].Attributes[attId][i];
910 for(i=0;i<(sint)baseMesh.Faces.size();i++)
912 TmpFaces[i]= baseMesh.Faces[i];
913 TmpFaces[i].BSInterpolated.resize(baseMesh.BlendShapes.size());
917 // Create vertices sharedFaces.
918 for(i=0;i<(sint)TmpFaces.size();i++)
920 CMRMFaceBuild &face= TmpFaces[i];
922 TmpVertices[face.Corner[0].Vertex].SharedFaces.push_back(i);
923 TmpVertices[face.Corner[1].Vertex].SharedFaces.push_back(i);
924 TmpVertices[face.Corner[2].Vertex].SharedFaces.push_back(i);
928 // Compute EdgeCost.
929 for(i=0;i<(sint)TmpFaces.size();i++)
931 CMRMFaceBuild &f= TmpFaces[i];
932 // At start, valid all edges.
933 f. ValidIt0= true;
934 f. ValidIt1= true;
935 f. ValidIt2= true;
936 insertFaceIntoEdgeList(f);
939 // ***************************************************************************
940 void CMRMBuilder::collapseEdges(sint nWantedFaces)
942 ItEdgeMap EdgeIt;
944 sint nCurrentFaces=(sint)TmpFaces.size();
945 sint bug0=0,bug2=0,bug3=0;
947 while(nCurrentFaces>nWantedFaces)
949 bug0++;
950 EdgeIt= EdgeCollapses.begin();
952 if(EdgeIt== EdgeCollapses.end())
953 break;
955 // 0. Look if edge already deleted
956 //================================
957 CMRMEdge edge=(*EdgeIt).second;
959 // Is it valid?? (ie his vertices exist yet??).
960 if(TmpVertices[ edge.v0 ].CollapsedTo>=0
961 || TmpVertices[ edge.v1 ].CollapsedTo>=0)
963 // \todo yoyo: TODO_BUG: potential bug here...
964 CMRMFaceBuild &f= *(EdgeIt->second.Face);
965 nlassert(f.validEdgeIt(EdgeIt->second));
966 f.invalidEdgeIt(EdgeIt->second, EdgeCollapses);
967 EdgeCollapses.erase(EdgeIt);
968 bug2++;
969 continue;
971 // \todo yoyo: TODO_BUG: potential bug here...
972 // If a mesh is "open" it will crash if a "hole collapse"...
973 if(edge.v0==edge.v1)
975 CMRMFaceBuild &f= *(EdgeIt->second.Face);
976 nlassert(f.validEdgeIt(EdgeIt->second));
977 f.invalidEdgeIt(EdgeIt->second, EdgeCollapses);
978 EdgeCollapses.erase(EdgeIt);
979 bug3++;
980 continue;
984 // 1. else, OK, collapse it!!
985 //===========================
986 sint vertexCollapsed= edge.v0;
987 nCurrentFaces-= collapseEdge(edge);
990 // 2. Must reorder all his neighborhood.
991 //======================================
992 CMRMVertex &vert=TmpVertices[vertexCollapsed];
993 sint i;
994 // we delete from list modified edges, and we re-add them with their new value.
995 for(i=0;i<(sint)vert.SharedFaces.size();i++)
997 CMRMFaceBuild &f= TmpFaces[vert.SharedFaces[i]];
998 removeFaceFromEdgeList(f);
999 insertFaceIntoEdgeList(f);
1004 // ***************************************************************************
1005 void CMRMBuilder::saveCoarserMesh(CMRMMesh &coarserMesh)
1007 sint i,attId,index;
1008 // First clear ALL.
1009 coarserMesh.Vertices.clear();
1010 coarserMesh.SkinWeights.clear();
1011 coarserMesh.InterfaceLinks.clear();
1012 for(attId=0;attId<NL3D_MRM_MAX_ATTRIB;attId++)
1014 coarserMesh.Attributes[attId].clear();
1016 coarserMesh.Faces.clear();
1017 coarserMesh.NumAttributes= NumAttributes;
1019 // Vertices.
1020 //==========
1021 index=0;
1022 for(i=0;i<(sint)TmpVertices.size();i++)
1024 CMRMVertex &vert=TmpVertices[i];
1025 if(vert.CollapsedTo==-1) // if exist yet.
1027 vert.CoarserIndex=index;
1028 coarserMesh.Vertices.push_back(vert.Current);
1029 if(_Skinned)
1030 coarserMesh.SkinWeights.push_back(vert.CurrentSW);
1031 if(_HasMeshInterfaces)
1032 coarserMesh.InterfaceLinks.push_back(vert.InterfaceLink);
1034 index++;
1036 else
1037 vert.CoarserIndex=-1; // indicate that this vertex no more exist and is to be geomorphed to another.
1041 // Attributes.
1042 //============
1043 for(attId=0;attId<NumAttributes;attId++)
1045 index=0;
1046 for(i=0;i<(sint)TmpAttributes[attId].size();i++)
1048 CMRMAttribute &wedge= TmpAttributes[attId][i];
1049 if(wedge.CollapsedTo==-1) // if exist yet.
1051 wedge.CoarserIndex=index;
1052 coarserMesh.Attributes[attId].push_back(wedge.Current);
1053 index++;
1055 else if(wedge.CollapsedTo==-2) // else if totaly destroyed.
1057 // Insert this wedge in the coarser mesh.
1058 // NB: the coarser mesh faces do not use it anymore, but FinerMesh use it
1059 // for geomorph (LODMesh.CoarserFaces may point to it).
1060 // NB: look at buildFinalMRM(), it works fine for all cases.
1061 wedge.CoarserIndex=index;
1062 coarserMesh.Attributes[attId].push_back(wedge.Current);
1063 index++;
1065 else
1066 wedge.CoarserIndex=-1; // indicate that this wedge no more exist and is to be geomorphed to another.
1070 // Faces.
1071 //=======
1072 for(i=0;i<(sint)TmpFaces.size();i++)
1074 CMRMFaceBuild &face=TmpFaces[i];
1075 if(!face.Deleted)
1077 CMRMFace newFace;
1078 // Material.
1079 newFace.MaterialId= face.MaterialId;
1080 for(sint j=0;j<3;j++)
1082 // Vertex.
1083 newFace.Corner[j].Vertex= TmpVertices[face.Corner[j].Vertex].CoarserIndex;
1084 nlassert(newFace.Corner[j].Vertex>=0);
1085 // Attributes.
1086 for(attId=0;attId<NumAttributes;attId++)
1088 sint oldidx= face.Corner[j].Attributes[attId];
1089 newFace.Corner[j].Attributes[attId]= TmpAttributes[attId][oldidx].CoarserIndex;
1090 nlassert(newFace.Corner[j].Attributes[attId]>=0);
1095 coarserMesh.Faces.push_back(newFace);
1102 // ***************************************************************************
1103 void CMRMBuilder::makeLODMesh(CMRMMeshGeom &lodMesh)
1105 sint i,j,attId,index,coidx;
1107 // for all faces of this mesh, find target in the coarser mesh.
1108 for(i=0;i<(sint)lodMesh.CoarserFaces.size();i++)
1110 CMRMFace &face= lodMesh.CoarserFaces[i];
1112 // For 3 corners.
1113 for(j=0;j<3;j++)
1115 // Vertex.
1116 // The index is yet the index in the finer mesh.
1117 index= face.Corner[j].Vertex;
1118 // the index in the coarser mesh is vert.CoarserIndex.
1119 coidx= TmpVertices[index].CoarserIndex;
1120 // but if this vertex is collapsed, must find the good index (yet in the finer mesh)
1121 if(coidx==-1)
1123 // find to which we must collapse.
1124 index= followVertex(index);
1125 // and so we have the coarser index. this one must be valid.
1126 coidx= TmpVertices[index].CoarserIndex;
1127 nlassert(coidx>=0);
1129 // update corner of CoarserFace.
1130 face.Corner[j].Vertex= coidx;
1133 // Do exactly same thing for all attributes.
1134 for(attId=0;attId<NumAttributes;attId++)
1136 index= face.Corner[j].Attributes[attId];
1137 coidx= TmpAttributes[attId][index].CoarserIndex;
1138 if(coidx==-1)
1140 index= followWedge(attId, index);
1141 coidx= TmpAttributes[attId][index].CoarserIndex;
1142 nlassert(coidx>=0);
1144 face.Corner[j].Attributes[attId]= coidx;
1151 // ***************************************************************************
1152 // Transform source blend shapes to source blend shapes modified (just calculate new vertex/attr position)
1153 /*void CMRMBuilder::computeBsVerticesAttributes(vector<CMRMMesh> &srcBsMeshs, vector<CMRMMesh> &bsMeshsMod)
1155 sint i, j, k, attId;
1157 bsMeshsMod.resize (srcBsMeshs.size());
1158 for (k = 0; k < (sint)srcBsMeshs.size(); ++k)
1160 CMRMMesh &rBsMesh = srcBsMeshs[k];
1161 CMRMMesh &rBsMeshMod = bsMeshsMod[k];
1163 // Calculate modified vertices with the linear equation back tracking help
1164 rBsMeshMod.Vertices.resize (rBsMesh.Vertices.size());
1165 for (i = 0; i < (sint)rBsMesh.Vertices.size(); ++i)
1167 CLinearEquation &LinEq = TmpVertices[i].CurrentLinEq;
1168 rBsMeshMod.Vertices[i] = CVector(0.0f, 0.0f, 0.0f);
1169 for (j = 0; j < (sint)LinEq.Elts.size(); ++j)
1171 rBsMeshMod.Vertices[i] += LinEq.Elts[j].factor * rBsMesh.Vertices[LinEq.Elts[j].index];
1175 // All attributes
1176 rBsMeshMod.NumAttributes = NumAttributes;
1177 for (attId = 0; attId < NumAttributes; attId++)
1179 rBsMeshMod.Attributes[attId].resize (rBsMesh.Attributes[attId].size());
1180 for (i = 0; i < (sint)rBsMesh.Attributes[attId].size(); ++i)
1182 CLinearEquation &LinEq = TmpAttributes[attId][i].CurrentLinEq;
1183 rBsMeshMod.Attributes[attId][i] = CVectorH(0.0f, 0.0f, 0.0f, 0.0f);
1184 for (j = 0; j < (sint)LinEq.Elts.size(); ++j)
1186 rBsMeshMod.Attributes[attId][i].x += LinEq.Elts[j].factor * rBsMesh.Attributes[attId][LinEq.Elts[j].index].x;
1187 rBsMeshMod.Attributes[attId][i].y += LinEq.Elts[j].factor * rBsMesh.Attributes[attId][LinEq.Elts[j].index].y;
1188 rBsMeshMod.Attributes[attId][i].z += LinEq.Elts[j].factor * rBsMesh.Attributes[attId][LinEq.Elts[j].index].z;
1189 rBsMeshMod.Attributes[attId][i].w += LinEq.Elts[j].factor * rBsMesh.Attributes[attId][LinEq.Elts[j].index].w;
1196 // ***************************************************************************
1197 // Transform source Blend Shape Meshes Modified into coarser blend shape mesh (compact vertices)
1198 void CMRMBuilder::makeCoarserBS (vector<CMRMBlendShape> &csBsMeshs)
1200 uint32 i, k;
1201 sint32 nSizeVert, nSizeAttr, attId;
1203 // Calculate size of vertices array
1204 nSizeVert = 0;
1205 for (i = 0; i < TmpVertices.size(); ++i)
1206 if(TmpVertices[i].CoarserIndex > nSizeVert)
1207 nSizeVert = TmpVertices[i].CoarserIndex;
1208 ++nSizeVert;
1210 for (k = 0; k < csBsMeshs.size(); ++k)
1212 CMRMBlendShape &rBsCoarserMesh = csBsMeshs[k];
1214 rBsCoarserMesh.Vertices.resize (nSizeVert);
1215 rBsCoarserMesh.NumAttributes = NumAttributes;
1217 // Vertices
1218 for(i = 0; i < TmpVertices.size(); ++i)
1220 CMRMVertex &vert = TmpVertices[i];
1221 if (vert.CoarserIndex != -1)
1223 rBsCoarserMesh.Vertices[vert.CoarserIndex] = vert.BSCurrent[k];
1227 for (attId = 0; attId < NumAttributes; attId++)
1229 // Calculate size of attribute attId array
1230 nSizeAttr = 0;
1231 for(i = 0; i < TmpAttributes[attId].size(); i++)
1232 if (TmpAttributes[attId][i].CoarserIndex > nSizeAttr)
1233 nSizeAttr = TmpAttributes[attId][i].CoarserIndex;
1234 ++nSizeAttr;
1236 rBsCoarserMesh.Attributes[attId].resize (nSizeAttr);
1238 for (i = 0; i < TmpAttributes[attId].size(); i++)
1240 CMRMAttribute &wedge = TmpAttributes[attId][i];
1241 if (wedge.CoarserIndex != -1)
1243 rBsCoarserMesh.Attributes[attId][wedge.CoarserIndex] = wedge.BSCurrent[k];
1250 // ***************************************************************************
1251 void CMRMBuilder::makeFromMesh(const CMRMMesh &baseMesh, CMRMMeshGeom &lodMesh, CMRMMesh &coarserMesh, sint nWantedFaces)
1253 // Init Tmp values in MRM builder.
1254 init(baseMesh);
1256 // compute MRM too next tgt face.
1257 collapseEdges(nWantedFaces);
1259 // save the coarser mesh.
1260 saveCoarserMesh(coarserMesh);
1261 // Build coarser BlendShapes.
1262 coarserMesh.BlendShapes.resize(baseMesh.BlendShapes.size());
1263 makeCoarserBS(coarserMesh.BlendShapes);
1265 // build the lodMesh (baseMesh, with vertex/Attributes collapse infos).
1266 lodMesh= baseMesh;
1267 makeLODMesh(lodMesh);
1269 // end for this level.
1274 // ***************************************************************************
1275 // ***************************************************************************
1276 // Global MRM Level method.
1277 // ***************************************************************************
1278 // ***************************************************************************
1281 // ***************************************************************************
1282 void CMRMBuilder::buildAllLods(const CMRMMesh &baseMesh, std::vector<CMRMMeshGeom> &lodMeshs,
1283 uint nWantedLods, uint divisor)
1285 sint nFaces= (sint)baseMesh.Faces.size();
1286 sint nBaseFaces;
1287 sint i;
1288 CMRMMesh srcMesh = baseMesh;
1290 // coarsest LOD will have those number of faces.
1291 nBaseFaces=nFaces/divisor;
1292 nBaseFaces=max(nBaseFaces,4);
1294 // must have at least 2 LOD to be really intersting. But the rest of the process work too with only one Lod!!
1295 nlassert(nWantedLods>=1);
1296 lodMeshs.resize(nWantedLods);
1298 // If only one lod asked, must init some Tmp Global values (like NumAttributes)
1299 if(nWantedLods==1)
1301 _CurrentLodComputed= 0;
1302 init(baseMesh);
1305 // must fill all LODs, from end to start. do not proces last lod since it will be the coarsest mesh.
1306 for(i=nWantedLods-1;i>0;i--)
1308 sint nbWantedFaces;
1310 // for sewing computing
1311 _CurrentLodComputed= i;
1313 // Linear.
1314 nbWantedFaces= nBaseFaces + (nFaces-nBaseFaces) * (i-1)/(nWantedLods-1);
1315 nbWantedFaces=max(nbWantedFaces,4);
1317 // Build this LOD.
1318 CMRMMesh csMesh;
1319 // The mesh
1320 makeFromMesh(srcMesh, lodMeshs[i], csMesh, nbWantedFaces);
1322 // next mesh to process is csMesh.
1323 srcMesh = csMesh;
1325 // the first lodMedsh gets the coarsest mesh.
1326 lodMeshs[0]= srcMesh;
1330 // ***************************************************************************
1331 void CMRMBuilder::buildFinalMRM(std::vector<CMRMMeshGeom> &lodMeshs, CMRMMeshFinal &finalMRM)
1333 sint i,j;
1334 sint lodId, attId;
1335 sint nLods= (sint)lodMeshs.size();
1337 // Init.
1338 // ===============
1339 finalMRM.reset();
1340 finalMRM.NumAttributes= NumAttributes;
1341 finalMRM.Skinned= _Skinned;
1342 CMRMMeshFinal::CWedge::NumAttributesToCompare= NumAttributes;
1343 CMRMMeshFinal::CWedge::CompareSkinning= _Skinned;
1344 finalMRM.Lods.resize(nLods);
1347 // Build Wedges, and faces index.
1348 // ===============
1349 // for all lods.
1350 for(lodId=0; lodId<nLods; lodId++)
1352 CMRMMeshGeom &lodMesh= lodMeshs[lodId];
1353 CMRMMeshGeom &lodMeshPrec= lodMeshs[lodId==0?0:lodId-1];
1354 // for all face corner.
1355 for(i=0; i<(sint)lodMesh.Faces.size();i++)
1357 // The current face.
1358 CMRMFace &face= lodMesh.Faces[i];
1359 // the current face, but which points to the prec LOD vertices/attributes.
1360 CMRMFace &faceCoarser= lodMesh.CoarserFaces[i];
1361 // for 3 corners.
1362 for(j=0;j<3;j++)
1364 CMRMCorner &corner= face.Corner[j];
1365 CMRMCorner &cornerCoarser= faceCoarser.Corner[j];
1366 // start and end wedge (geomorph), maybe same.
1367 CMRMMeshFinal::CWedge wedgeStart;
1368 CMRMMeshFinal::CWedge wedgeEnd;
1370 // fill wedgeStart with values from lodMesh.
1371 wedgeStart.Vertex= lodMesh.Vertices[corner.Vertex];
1372 if(_Skinned)
1373 wedgeStart.VertexSkin= lodMesh.SkinWeights[corner.Vertex];
1374 for(attId=0; attId<NumAttributes; attId++)
1376 wedgeStart.Attributes[attId]= lodMesh.Attributes[attId][corner.Attributes[attId]];
1379 // if geomorph possible (ie not lod 0).
1380 if(lodId>0)
1382 // fill wedgeEnd with values from coarser lodMesh.
1383 wedgeEnd.Vertex= lodMeshPrec.Vertices[cornerCoarser.Vertex];
1384 if(_Skinned)
1385 wedgeEnd.VertexSkin= lodMeshPrec.SkinWeights[cornerCoarser.Vertex];
1386 for(attId=0; attId<NumAttributes; attId++)
1388 wedgeEnd.Attributes[attId]= lodMeshPrec.Attributes[attId][cornerCoarser.Attributes[attId]];
1391 else
1393 // no geomorph.
1394 wedgeEnd= wedgeStart;
1397 // find/insert wedge, and get Ids. NB: if start/end same, same indices.
1398 sint wedgeStartId= finalMRM.findInsertWedge(wedgeStart);
1399 sint wedgeEndId= finalMRM.findInsertWedge(wedgeEnd);
1401 // store in TmpCorner.
1402 corner.WedgeStartId= wedgeStartId;
1403 corner.WedgeEndId= wedgeEndId;
1407 // Here, the number of wedge indicate the max number of wedge this LOD needs.
1408 finalMRM.Lods[lodId].NWedges= (sint)finalMRM.Wedges.size();
1412 // Count NBWedges necessary for geomorph, and compute Dest geomorph wedges ids.
1413 // ===============
1414 // the number of geomorph required for one LOD.
1415 sint sglmGeom;
1416 // the number of geomorph required for all LOD (max of sglmGeom).
1417 sint sglmGeomMax= 0;
1419 // Do not process lod 0, since no geomorph.
1420 for(lodId=1; lodId<nLods; lodId++)
1422 CMRMMeshGeom &lodMesh= lodMeshs[lodId];
1424 // reset the GeomMap, the one which indicate if we have already inserted a geomorph.
1425 _GeomMap.clear();
1426 sglmGeom= 0;
1428 // for all face corner.
1429 for(i=0; i<(sint)lodMesh.Faces.size();i++)
1431 // The current face.
1432 CMRMFace &face= lodMesh.Faces[i];
1433 // for 3 corners.
1434 for(j=0;j<3;j++)
1436 CMRMCorner &corner= face.Corner[j];
1438 // if not same wedge Ids, this is a geomorphed wedge.
1439 if(corner.WedgeStartId != corner.WedgeEndId)
1441 // search if it exist yet in the set.
1442 CMRMWedgeGeom geom;
1443 geom.Start= corner.WedgeStartId;
1444 geom.End= corner.WedgeEndId;
1445 sint geomDest= sglmGeom;
1446 // if don't find this geom in the set, then it is a new one.
1447 TGeomMap::const_iterator it= _GeomMap.find(geom);
1448 if(it == _GeomMap.end())
1450 _GeomMap.insert( make_pair(geom, geomDest) );
1451 sglmGeom++;
1453 else
1454 geomDest= it->second;
1456 // store this Geom Id in the corner.
1457 corner.WedgeGeomId= geomDest;
1462 // take the max.
1463 sglmGeomMax= max(sglmGeomMax, sglmGeom);
1467 // inform the finalMRM.
1468 finalMRM.NGeomSpace= sglmGeomMax;
1471 // decal all wedges/ face index.
1472 // ===============
1473 // insert an empty space for dest geomorph.
1474 finalMRM.Wedges.insert(finalMRM.Wedges.begin(), sglmGeomMax, CMRMMeshFinal::CWedge());
1476 // Parse all faces corner of All lods, and decal Start/End Wedge index.
1477 for(lodId=0; lodId<nLods; lodId++)
1479 CMRMMeshGeom &lodMesh= lodMeshs[lodId];
1481 // for all face corner.
1482 for(i=0; i<(sint)lodMesh.Faces.size();i++)
1484 // The current face.
1485 CMRMFace &face= lodMesh.Faces[i];
1486 // for 3 corners.
1487 for(j=0;j<3;j++)
1489 CMRMCorner &corner= face.Corner[j];
1491 // decal indices.
1492 corner.WedgeStartId+= sglmGeomMax;
1493 corner.WedgeEndId+= sglmGeomMax;
1497 // increment too the number of wedge required for this Lod.
1498 finalMRM.Lods[lodId].NWedges+= sglmGeomMax;
1502 // fill faces.
1503 // ===============
1504 // Parse all faces corner of All lods, and build Faces/Geomorphs..
1505 for(lodId=0; lodId<nLods; lodId++)
1507 CMRMMeshGeom &lodMesh= lodMeshs[lodId];
1508 CMRMMeshFinal::CLod &lodDest= finalMRM.Lods[lodId];
1510 // alloc final faces of this LOD.
1511 lodDest.Faces.resize(lodMesh.Faces.size());
1513 // reset the GeomMap, the one which indicate if we have already inserted a geomorph.
1514 _GeomMap.clear();
1516 // for all face corner.
1517 for(i=0; i<(sint)lodMesh.Faces.size();i++)
1519 // The current face.
1520 CMRMFace &face= lodMesh.Faces[i];
1521 // The dest face.
1522 CMRMMeshFinal::CFace &faceDest= lodDest.Faces[i];
1523 // fill good material.
1524 faceDest.MaterialId= face.MaterialId;
1526 // for 3 corners.
1527 for(j=0;j<3;j++)
1529 CMRMCorner &corner= face.Corner[j];
1531 // if not same wedge Ids, this is a geomorphed wedge.
1532 if(corner.WedgeStartId != corner.WedgeEndId)
1534 // geomorph, so point to geomorphed wedge.
1535 faceDest.WedgeId[j]= corner.WedgeGeomId;
1537 // Build the geomorph, add it to the list (if not yet inserted).
1538 CMRMWedgeGeom geom;
1539 geom.Start= corner.WedgeStartId;
1540 geom.End= corner.WedgeEndId;
1541 // if don't find this geom in the set, then it is a new one.
1542 TGeomMap::const_iterator it= _GeomMap.find(geom);
1543 if(it == _GeomMap.end())
1545 // mark it as inserted.
1546 _GeomMap.insert( make_pair(geom, corner.WedgeGeomId) );
1547 // and we must insert this geom in the array.
1548 nlassert( corner.WedgeGeomId==(sint)lodDest.Geomorphs.size() );
1549 lodDest.Geomorphs.push_back(geom);
1552 else
1554 // no geomorph, so just point to good wedge.
1555 faceDest.WedgeId[j]= corner.WedgeStartId;
1562 // process all wedges, and compute NSkinMatUsed, skipping geomorphs.
1563 // ===============
1564 // NB: this works because weights are sorted from biggest to lowest.
1565 if(_Skinned)
1567 for(i=finalMRM.NGeomSpace; i<(sint)finalMRM.Wedges.size();i++)
1569 CMRMMeshFinal::CWedge &wedge= finalMRM.Wedges[i];
1570 for(j=0; j<NL3D_MESH_SKINNING_MAX_MATRIX; j++)
1572 if(wedge.VertexSkin.Weights[j]==0)
1573 break;
1575 nlassert(j>0);
1576 wedge.NSkinMatUsed= j;
1580 // Blend Shape Stuff
1581 finalMRM.MRMBlendShapesFinals.resize (lodMeshs[0].BlendShapes.size());
1582 for (lodId = 0; lodId < nLods; ++lodId)
1584 CMRMMeshGeom &lodMesh= lodMeshs[lodId];
1585 CMRMMeshGeom &lodMeshPrec= lodMeshs[lodId==0?0:lodId-1];
1587 // for all face corner.
1588 for (i = 0; i < (sint)lodMesh.Faces.size(); ++i)
1590 // The current face.
1591 CMRMFace &face = lodMesh.Faces[i];
1592 // the current face, but which points to the prec LOD vertices/attributes.
1593 CMRMFace &faceCoarser = lodMesh.CoarserFaces[i];
1594 // for 3 corners.
1595 for (j = 0; j < 3; ++j)
1597 CMRMCorner &corner = face.Corner[j];
1598 CMRMCorner &cornerCoarser = faceCoarser.Corner[j];
1600 sint startDestIndex = corner.WedgeStartId;
1602 for (sint k = 0; k < (sint)finalMRM.MRMBlendShapesFinals.size(); ++k)
1604 CMRMMeshFinal::CMRMBlendShapeFinal &rBSFinal = finalMRM.MRMBlendShapesFinals[k];
1606 rBSFinal.Wedges.resize (finalMRM.Wedges.size());
1607 // Fill WedgeStart used by this corner.
1608 rBSFinal.Wedges[startDestIndex].Vertex = lodMesh.BlendShapes[k].Vertices[corner.Vertex];
1609 for (attId = 0; attId < NumAttributes; ++attId)
1611 rBSFinal.Wedges[startDestIndex].Attributes[attId] = lodMesh.BlendShapes[k].Attributes[attId][corner.Attributes[attId]];
1614 // If geomorph, must fill the end too
1615 if(lodId>0 && corner.WedgeStartId != corner.WedgeEndId)
1617 sint endDestIndex = corner.WedgeEndId;
1619 rBSFinal.Wedges[endDestIndex].Vertex = lodMeshPrec.BlendShapes[k].Vertices[cornerCoarser.Vertex];
1620 for (attId = 0; attId < NumAttributes; ++attId)
1622 rBSFinal.Wedges[endDestIndex].Attributes[attId] = lodMeshPrec.BlendShapes[k].Attributes[attId][cornerCoarser.Attributes[attId]];
1634 // ***************************************************************************
1635 // ***************************************************************************
1636 // Interface to MeshBuild Part.
1637 // ***************************************************************************
1638 // ***************************************************************************
1642 // ***************************************************************************
1643 sint CMRMBuilder::findInsertAttributeInBaseMesh(CMRMMesh &baseMesh, sint attId, sint vertexId, const CVectorH &att)
1645 // find this attribute in the map.
1646 CAttributeKey key;
1647 key.VertexId= vertexId;
1648 key.Attribute= att;
1649 TAttributeMap::iterator it= _AttributeMap[attId].find(key);
1651 // if attribute not found in the map, then insert a new one.
1652 if(it==_AttributeMap[attId].end())
1654 sint idx= (sint)baseMesh.Attributes[attId].size();
1655 // insert into the array.
1656 baseMesh.Attributes[attId].push_back(att);
1657 // insert into the map.
1658 _AttributeMap[attId].insert(make_pair(key, idx));
1659 return idx;
1661 else
1663 // return the one found.
1664 return it->second;
1669 // ***************************************************************************
1670 sint CMRMBuilder::findInsertNormalInBaseMesh(CMRMMesh &baseMesh, sint attId, sint vertexId, const CVector &normal)
1672 CVectorH att;
1673 att= normal;
1674 att.w= 0;
1675 return findInsertAttributeInBaseMesh(baseMesh, attId, vertexId, att);
1679 // ***************************************************************************
1680 sint CMRMBuilder::findInsertColorInBaseMesh(CMRMMesh &baseMesh, sint attId, sint vertexId, CRGBA col)
1682 CVectorH att;
1683 att.x= col.R;
1684 att.y= col.G;
1685 att.z= col.B;
1686 att.w= col.A;
1687 return findInsertAttributeInBaseMesh(baseMesh, attId, vertexId, att);
1691 // ***************************************************************************
1692 sint CMRMBuilder::findInsertUvwInBaseMesh(CMRMMesh &baseMesh, sint attId, sint vertexId, const NLMISC::CUVW &uvw)
1694 CVectorH att;
1695 att.x= uvw.U;
1696 att.y= uvw.V;
1697 att.z= uvw.W;
1698 att.w= 0;
1699 return findInsertAttributeInBaseMesh(baseMesh, attId, vertexId, att);
1703 // ***************************************************************************
1704 CRGBA CMRMBuilder::attToColor(const CVectorH &att) const
1706 CRGBA ret;
1707 float tmp;
1708 tmp= att.x; clamp(tmp, 0, 255);
1709 ret.R= (uint8)(uint)tmp;
1710 tmp= att.y; clamp(tmp, 0, 255);
1711 ret.G= (uint8)(uint)tmp;
1712 tmp= att.z; clamp(tmp, 0, 255);
1713 ret.B= (uint8)(uint)tmp;
1714 tmp= att.w; clamp(tmp, 0, 255);
1715 ret.A= (uint8)(uint)tmp;
1717 return ret;
1721 // ***************************************************************************
1722 NLMISC::CUVW CMRMBuilder::attToUvw(const CVectorH &att) const
1724 return CUVW(att.x, att.y, att.z);
1728 // ***************************************************************************
1729 uint32 CMRMBuilder::buildMrmBaseMesh(const CMesh::CMeshBuild &mbuild, CMRMMesh &baseMesh)
1731 sint i,j,k;
1732 sint nFaces;
1733 sint attId;
1734 // build the supported VertexFormat.
1735 uint32 retVbFlags= CVertexBuffer::PositionFlag;
1738 // reset the baseMesh.
1739 baseMesh= CMRMMesh();
1740 // reset Tmp.
1741 for(attId=0; attId<NL3D_MRM_MAX_ATTRIB;attId++)
1742 _AttributeMap[attId].clear();
1745 // Compute number of attributes used by the MeshBuild.
1746 // ========================
1747 // Compute too
1748 if(mbuild.VertexFlags & CVertexBuffer::NormalFlag)
1750 baseMesh.NumAttributes++;
1751 retVbFlags|= CVertexBuffer::NormalFlag;
1753 if(mbuild.VertexFlags & CVertexBuffer::PrimaryColorFlag)
1755 baseMesh.NumAttributes++;
1756 retVbFlags|= CVertexBuffer::PrimaryColorFlag;
1758 if(mbuild.VertexFlags & CVertexBuffer::SecondaryColorFlag)
1760 baseMesh.NumAttributes++;
1761 retVbFlags|= CVertexBuffer::SecondaryColorFlag;
1763 for(k=0; k<CVertexBuffer::MaxStage;k++)
1765 uint flag=CVertexBuffer::TexCoord0Flag<<k;
1766 if(mbuild.VertexFlags & flag)
1768 baseMesh.NumAttributes++;
1769 retVbFlags|=flag;
1772 nlassert(baseMesh.NumAttributes<=NL3D_MRM_MAX_ATTRIB);
1775 // Fill basics: Vertices and Faces materials / index to vertices.
1776 // ========================
1777 // Just copy vertices.
1778 baseMesh.Vertices= mbuild.Vertices;
1779 // Just copy SkinWeights.
1780 if(_Skinned)
1781 baseMesh.SkinWeights= mbuild.SkinWeights;
1782 // Just copy InterfaceLinks
1783 if(_HasMeshInterfaces)
1784 baseMesh.InterfaceLinks= mbuild.InterfaceLinks;
1785 // Resize faces.
1786 nFaces= (sint)mbuild.Faces.size();
1787 baseMesh.Faces.resize(nFaces);
1788 for(i=0; i<nFaces; i++)
1790 // copy material Id.
1791 baseMesh.Faces[i].MaterialId= mbuild.Faces[i].MaterialId;
1792 // Copy Vertex index.
1793 for(j=0; j<3; j++)
1795 baseMesh.Faces[i].Corner[j].Vertex= mbuild.Faces[i].Corner[j].Vertex;
1799 // Resolve attributes discontinuities and Fill attributes of the baseMesh.
1800 // ========================
1801 // For all corners.
1802 for(i=0; i<nFaces; i++)
1804 for(j=0; j<3; j++)
1806 const CMesh::CCorner &srcCorner= mbuild.Faces[i].Corner[j];
1807 CMRMCorner &destCorner= baseMesh.Faces[i].Corner[j];
1808 attId= 0;
1810 // For all activated attributes in mbuild, find/insert the attribute in the baseMesh.
1811 // NB: 2 attributes are said to be different if they have not the same value OR if they don't lie
1812 // on the same vertex. This is very important for MRM computing.
1813 if(mbuild.VertexFlags & CVertexBuffer::NormalFlag)
1815 destCorner.Attributes[attId]= findInsertNormalInBaseMesh(baseMesh, attId, destCorner.Vertex, srcCorner.Normal);
1816 attId++;
1818 if(mbuild.VertexFlags & CVertexBuffer::PrimaryColorFlag)
1820 destCorner.Attributes[attId]= findInsertColorInBaseMesh(baseMesh, attId, destCorner.Vertex, srcCorner.Color);
1821 attId++;
1823 if(mbuild.VertexFlags & CVertexBuffer::SecondaryColorFlag)
1825 destCorner.Attributes[attId]= findInsertColorInBaseMesh(baseMesh, attId, destCorner.Vertex, srcCorner.Specular);
1826 attId++;
1828 for(k=0; k<CVertexBuffer::MaxStage;k++)
1830 if(mbuild.VertexFlags & (CVertexBuffer::TexCoord0Flag<<k))
1832 destCorner.Attributes[attId]= findInsertUvwInBaseMesh(baseMesh, attId, destCorner.Vertex, srcCorner.Uvws[k]);
1833 attId++;
1841 // End. clear Tmp infos.
1842 // ========================
1843 // reset Tmp.
1844 for(attId=0; attId<NL3D_MRM_MAX_ATTRIB;attId++)
1845 _AttributeMap[attId].clear();
1847 return retVbFlags;
1852 // ***************************************************************************
1853 CMesh::CSkinWeight CMRMBuilder::normalizeSkinWeight(const CMesh::CSkinWeight &sw) const
1855 uint nbMats= 0;
1856 static vector<CTmpVertexWeight> sws;
1857 sws.reserve(NL3D_MESH_SKINNING_MAX_MATRIX);
1858 sws.clear();
1860 // For all weights of sw1.
1861 uint i;
1862 for(i=0; i<NL3D_MESH_SKINNING_MAX_MATRIX; i++)
1864 CTmpVertexWeight vw;
1865 vw.MatrixId= sw.MatrixId[i];
1866 vw.Weight= sw.Weights[i];
1867 // if this weight is not null.
1868 if(vw.Weight>0)
1870 // add it to the list.
1871 sws.push_back(vw);
1872 nbMats++;
1876 // sort by Weight decreasing order.
1877 sort(sws.begin(), sws.end());
1880 // Then output the result to the skinWeight, normalizing.
1881 float sumWeight=0;
1882 for(i= 0; i<nbMats; i++)
1884 sumWeight+= sws[i].Weight;
1887 CMesh::CSkinWeight ret;
1888 // Fill only needed matrix (other are rested in CMesh::CSkinWeight ctor).
1889 for(i= 0; i<nbMats; i++)
1891 ret.MatrixId[i]= sws[i].MatrixId;
1892 ret.Weights[i]= sws[i].Weight / sumWeight;
1895 return ret;
1899 // ***************************************************************************
1900 void CMRMBuilder::normalizeBaseMeshSkin(CMRMMesh &baseMesh) const
1902 nlassert(_Skinned);
1904 for(uint i=0; i<baseMesh.SkinWeights.size(); i++)
1906 baseMesh.SkinWeights[i]= normalizeSkinWeight(baseMesh.SkinWeights[i]);
1912 // ***************************************************************************
1913 void CMRMBuilder::buildMeshBuildMrm(const CMRMMeshFinal &finalMRM, CMeshMRMGeom::CMeshBuildMRM &mbuild, uint32 vbFlags, uint32 nbMats, const CMesh::CMeshBuild &mb)
1915 sint i,j,k;
1916 sint attId;
1918 // reset the mbuild.
1919 mbuild= CMeshMRMGeom::CMeshBuildMRM();
1920 // Setup VB.
1922 bool useFormatExt = false;
1923 // Check whether there are texture coordinates with more than 2 compnents, which force us to use an extended vertex format
1924 for (k = 0; k < CVertexBuffer::MaxStage; ++k)
1926 if (
1927 (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
1928 && mb.NumCoords[k] != 2)
1930 useFormatExt = true;
1931 break;
1935 uint numTexCoordUsed = 0;
1938 for (k = 0; k < CVertexBuffer::MaxStage; ++k)
1940 if (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
1942 numTexCoordUsed = k;
1946 if (!useFormatExt)
1948 // setup standard format
1949 mbuild.VBuffer.setVertexFormat(vbFlags);
1951 else // setup extended format
1953 mbuild.VBuffer.clearValueEx();
1954 if (vbFlags & CVertexBuffer::PositionFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::Position, CVertexBuffer::Float3);
1955 if (vbFlags & CVertexBuffer::NormalFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::Normal, CVertexBuffer::Float3);
1956 if (vbFlags & CVertexBuffer::PrimaryColorFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::PrimaryColor, CVertexBuffer::UChar4);
1957 if (vbFlags & CVertexBuffer::SecondaryColorFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::SecondaryColor, CVertexBuffer::UChar4);
1958 if (vbFlags & CVertexBuffer::WeightFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::Weight, CVertexBuffer::Float4);
1959 if (vbFlags & CVertexBuffer::PaletteSkinFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::PaletteSkin, CVertexBuffer::UChar4);
1960 if (vbFlags & CVertexBuffer::FogFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::Fog, CVertexBuffer::Float1);
1962 for (k = 0; k < CVertexBuffer::MaxStage; ++k)
1964 if (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
1966 switch(mb.NumCoords[k])
1968 case 2:
1969 mbuild.VBuffer.addValueEx((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), CVertexBuffer::Float2);
1970 break;
1971 case 3:
1972 mbuild.VBuffer.addValueEx((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), CVertexBuffer::Float3);
1973 break;
1974 default:
1975 nlassert(0);
1976 break;
1980 mbuild.VBuffer.initEx();
1983 // Copy the UVRouting
1984 for (i=0; i<CVertexBuffer::MaxStage; i++)
1986 mbuild.VBuffer.setUVRouting (i, mb.UVRouting[i]);
1989 // Setup the VertexBuffer.
1990 // ========================
1991 // resize the VB.
1992 mbuild.VBuffer.setNumVertices((uint32)finalMRM.Wedges.size());
1993 // Setup SkinWeights.
1994 if(_Skinned)
1995 mbuild.SkinWeights.resize(finalMRM.Wedges.size());
1997 CVertexBufferReadWrite vba;
1998 mbuild.VBuffer.lock (vba);
2000 // fill the VB.
2001 for(i=0; i<(sint)finalMRM.Wedges.size(); i++)
2003 const CMRMMeshFinal::CWedge &wedge= finalMRM.Wedges[i];
2005 // setup Vertex.
2006 vba.setVertexCoord(i, wedge.Vertex);
2008 // seutp attributes.
2009 attId= 0;
2011 // For all activated attributes in mbuild, retriev the attribute from the finalMRM.
2012 if(vbFlags & CVertexBuffer::NormalFlag)
2014 vba.setNormalCoord(i, wedge.Attributes[attId] );
2015 attId++;
2017 if(vbFlags & CVertexBuffer::PrimaryColorFlag)
2019 vba.setColor(i, attToColor(wedge.Attributes[attId]) );
2020 attId++;
2022 if(vbFlags & CVertexBuffer::SecondaryColorFlag)
2024 vba.setSpecular(i, attToColor(wedge.Attributes[attId]) );
2025 attId++;
2027 for(k=0; k<CVertexBuffer::MaxStage;k++)
2029 if(vbFlags & (CVertexBuffer::TexCoord0Flag<<k))
2031 switch(mb.NumCoords[k])
2033 case 2:
2034 vba.setTexCoord(i, k, (CUV) attToUvw(wedge.Attributes[attId]) );
2035 break;
2036 case 3:
2038 CUVW uvw = attToUvw(wedge.Attributes[attId]);
2039 vba.setValueFloat3Ex((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), i, uvw.U, uvw.V, uvw.W);
2041 break;
2042 default:
2043 nlassert(0);
2044 break;
2046 attId++;
2050 // Setup SkinWeights.
2051 if(_Skinned)
2053 mbuild.SkinWeights[i]= wedge.VertexSkin;
2058 // Build Lods.
2059 // ========================
2060 // resize
2061 mbuild.Lods.resize(finalMRM.Lods.size());
2062 // fill.
2063 for(i=0; i<(sint)finalMRM.Lods.size(); i++)
2065 const CMRMMeshFinal::CLod &srcLod= finalMRM.Lods[i];
2066 CMeshMRMGeom::CLod &destLod= mbuild.Lods[i];
2068 // Basic.
2069 //---------
2071 // Copy NWedges infos.
2072 destLod.NWedges= srcLod.NWedges;
2073 // Copy Geomorphs infos.
2074 destLod.Geomorphs= srcLod.Geomorphs;
2077 // Reorder faces by rdrpass.
2078 //---------
2080 // First count the number of faces used by this LOD for each material
2081 vector<sint> matCount;
2082 // resize, and reset to 0.
2083 matCount.clear();
2084 matCount.resize(nbMats, 0);
2085 // For each face of this Lods, incr the mat face counter.
2086 for(j= 0; j<(sint)srcLod.Faces.size(); j++)
2088 sint matId= srcLod.Faces[j].MaterialId;
2089 nlassert(matId>=0);
2090 nlassert(matId<(sint)nbMats);
2091 // increment the refcount of this material by this LOD.
2092 matCount[matId]++;
2095 // Then for each material not empty, create a rdrPass, and ref it for this material.
2096 vector<sint> rdrPassIndex; // material to rdrPass map.
2097 rdrPassIndex.resize(nbMats);
2098 for(j=0; j<(sint)nbMats; j++)
2100 if(matCount[j]==0)
2101 rdrPassIndex[j]= -1;
2102 else
2104 // map material to rdrPass.
2105 sint idRdrPass= (sint)destLod.RdrPass.size();
2106 rdrPassIndex[j]= idRdrPass;
2107 // create a rdrPass.
2108 destLod.RdrPass.push_back(CMeshMRMGeom::CRdrPass());
2109 // assign the good materialId to this rdrPass.
2110 destLod.RdrPass[idRdrPass].MaterialId= j;
2111 // reserve the array of faces of this rdrPass.
2112 destLod.RdrPass[idRdrPass].PBlock.reserve(3*matCount[j]);
2116 // Then for each face, add it to the good rdrPass of this Lod.
2117 for(j= 0; j<(sint)srcLod.Faces.size(); j++)
2119 sint matId= srcLod.Faces[j].MaterialId;
2120 sint idRdrPass= rdrPassIndex[matId];
2121 // add this face to the good rdrPass.
2122 sint w0= srcLod.Faces[j].WedgeId[0];
2123 sint w1= srcLod.Faces[j].WedgeId[1];
2124 sint w2= srcLod.Faces[j].WedgeId[2];
2125 CIndexBuffer &ib = destLod.RdrPass[idRdrPass].PBlock;
2126 uint index = ib.getNumIndexes();
2127 ib.setNumIndexes(index+3);
2128 CIndexBufferReadWrite ibaWrite;
2129 ib.lock (ibaWrite);
2130 ibaWrite.setTri(index, w0, w1, w2);
2134 // Build skin info for this Lod.
2135 //---------
2136 for(j=0; j<NL3D_MESH_SKINNING_MAX_MATRIX; j++)
2138 destLod.InfluencedVertices[j].clear();
2140 destLod.MatrixInfluences.clear();
2141 if(_Skinned)
2143 // This is the set which tell what wedge has already been inserted.
2144 set<uint> wedgeInfSet;
2146 // First, build the list of vertices influenced by this Lod.
2147 for(j= 0; j<(sint)srcLod.Faces.size(); j++)
2149 for(k=0; k<3; k++)
2151 sint wedgeId= srcLod.Faces[j].WedgeId[k];
2152 // If it is a geomorph
2153 if(wedgeId<finalMRM.NGeomSpace)
2155 // add the start and end to the list (if not here). NB: wedgeId is both the id
2156 // of the dest wedge, and the id of the geomorph.
2157 sint wedgeStartId= destLod.Geomorphs[wedgeId].Start;
2158 sint wedgeEndId= destLod.Geomorphs[wedgeId].End;
2159 uint nMatUsedStart= finalMRM.Wedges[wedgeStartId].NSkinMatUsed;
2160 uint nMatUsedEnd= finalMRM.Wedges[wedgeEndId].NSkinMatUsed;
2162 // if insertion in the set work, add to the good array.
2163 if( wedgeInfSet.insert(wedgeStartId).second )
2164 destLod.InfluencedVertices[nMatUsedStart-1].push_back(wedgeStartId);
2165 if( wedgeInfSet.insert(wedgeEndId).second )
2166 destLod.InfluencedVertices[nMatUsedEnd-1].push_back(wedgeEndId);
2168 else
2170 uint nMatUsed= finalMRM.Wedges[wedgeId].NSkinMatUsed;
2172 // just add this wedge to the list (if not here).
2173 // if insertion in the set work, add to the array.
2174 if( wedgeInfSet.insert(wedgeId).second )
2175 destLod.InfluencedVertices[nMatUsed-1].push_back(wedgeId);
2180 // Optimisation: for better cache, sort the destLod.InfluencedVertices in increasing order.
2181 for(j=0; j<NL3D_MESH_SKINNING_MAX_MATRIX; j++)
2183 sort(destLod.InfluencedVertices[j].begin(), destLod.InfluencedVertices[j].end());
2187 // Then Build the MatrixInfluences array, for all thoses Influenced Vertices only.
2188 // This is the map MatrixId -> MatrixInfId.
2189 map<uint, uint> matrixInfMap;
2191 // For all influenced vertices, flags matrix they use.
2192 uint iSkinMat;
2193 for(iSkinMat= 0; iSkinMat<NL3D_MESH_SKINNING_MAX_MATRIX; iSkinMat++)
2195 for(j= 0; j<(sint)destLod.InfluencedVertices[iSkinMat].size(); j++)
2197 uint wedgeId= destLod.InfluencedVertices[iSkinMat][j];
2199 // take the original wedge.
2200 const CMRMMeshFinal::CWedge &wedge= finalMRM.Wedges[wedgeId];
2201 // For all matrix with not null influence...
2202 for(k= 0; k<NL3D_MESH_SKINNING_MAX_MATRIX; k++)
2204 float matWeight= wedge.VertexSkin.Weights[k];
2206 // This check the validity of skin weights sort. If false, problem before in the algo.
2207 if((uint)k<iSkinMat+1)
2209 nlassert( matWeight>0 );
2211 else
2213 nlassert( matWeight==0 );
2215 // if not null influence.
2216 if(matWeight>0)
2218 uint matId= wedge.VertexSkin.MatrixId[k];
2220 // search/insert the matrixInfId.
2221 map<uint, uint>::iterator it= matrixInfMap.find(matId);
2222 if( it==matrixInfMap.end() )
2224 uint matInfId= (uint)destLod.MatrixInfluences.size();
2225 matrixInfMap.insert( make_pair(matId, matInfId) );
2226 // create the new MatrixInfluence.
2227 destLod.MatrixInfluences.push_back(matId);
2238 // Indicate Skinning.
2239 mbuild.Skinned= _Skinned;
2243 bool useTgSpace = mb.MeshVertexProgram != NULL ? mb.MeshVertexProgram->needTangentSpace() : false;
2245 // Construct Blend Shapes
2246 //// mbuild <- finalMRM
2247 mbuild.BlendShapes.resize (finalMRM.MRMBlendShapesFinals.size());
2248 for (k = 0; k < (sint)mbuild.BlendShapes.size(); ++k)
2250 CBlendShape &rBS = mbuild.BlendShapes[k];
2251 sint32 nNbVertVB = (sint32)finalMRM.Wedges.size();
2252 bool bIsDeltaPos = false;
2253 rBS.deltaPos.resize (nNbVertVB, CVector(0.0f,0.0f,0.0f));
2254 bool bIsDeltaNorm = false;
2255 rBS.deltaNorm.resize (nNbVertVB, CVector(0.0f,0.0f,0.0f));
2256 bool bIsDeltaUV = false;
2257 rBS.deltaUV.resize (nNbVertVB, CUV(0.0f,0.0f));
2258 bool bIsDeltaCol = false;
2259 rBS.deltaCol.resize (nNbVertVB, CRGBAF(0.0f,0.0f,0.0f,0.0f));
2260 bool bIsDeltaTgSpace = false;
2261 if (useTgSpace)
2263 rBS.deltaTgSpace.resize(nNbVertVB, CVector::Null);
2266 rBS.VertRefs.resize (nNbVertVB, 0xffffffff);
2268 for (i = 0; i < nNbVertVB; i++)
2270 const CMRMMeshFinal::CWedge &rWedgeRef = finalMRM.Wedges[i];
2271 const CMRMMeshFinal::CWedge &rWedgeTar = finalMRM.MRMBlendShapesFinals[k].Wedges[i];
2273 CVector delta = rWedgeTar.Vertex - rWedgeRef.Vertex;
2274 CVectorH attr;
2276 if (delta.norm() > 0.001f)
2278 rBS.deltaPos[i] = delta;
2279 rBS.VertRefs[i] = i;
2280 bIsDeltaPos = true;
2283 attId = 0;
2284 if (vbFlags & CVertexBuffer::NormalFlag)
2286 attr = rWedgeRef.Attributes[attId];
2287 CVector NormRef = CVector(attr.x, attr.y, attr.z);
2288 attr = rWedgeTar.Attributes[attId];
2289 CVector NormTar = CVector(attr.x, attr.y, attr.z);
2290 delta = NormTar - NormRef;
2291 if (delta.norm() > 0.001f)
2293 rBS.deltaNorm[i] = delta;
2294 rBS.VertRefs[i] = i;
2295 bIsDeltaNorm = true;
2297 attId++;
2300 if (vbFlags & CVertexBuffer::PrimaryColorFlag)
2302 attr = rWedgeRef.Attributes[attId];
2303 CRGBAF RGBARef = CRGBAF(attr.x/255.0f, attr.y/255.0f, attr.z/255.0f, attr.w/255.0f);
2304 attr = rWedgeTar.Attributes[attId];
2305 CRGBAF RGBATar = CRGBAF(attr.x/255.0f, attr.y/255.0f, attr.z/255.0f, attr.w/255.0f);
2306 CRGBAF deltaRGBA = RGBATar - RGBARef;
2307 if ((deltaRGBA.R*deltaRGBA.R + deltaRGBA.G*deltaRGBA.G +
2308 deltaRGBA.B*deltaRGBA.B + deltaRGBA.A*deltaRGBA.A) > 0.0001f)
2310 rBS.deltaCol[i] = deltaRGBA;
2311 rBS.VertRefs[i] = i;
2312 bIsDeltaCol = true;
2314 attId++;
2317 if (vbFlags & CVertexBuffer::SecondaryColorFlag)
2318 { // Nothing to do !
2319 attId++;
2322 // Do that only for the UV0
2323 if (vbFlags & CVertexBuffer::TexCoord0Flag)
2325 attr = rWedgeRef.Attributes[attId];
2326 CUV UVRef = CUV(attr.x, attr.y);
2327 attr = rWedgeTar.Attributes[attId];
2328 CUV UVTar = CUV(attr.x, attr.y);
2329 CUV deltaUV = UVTar - UVRef;
2330 if ((deltaUV.U*deltaUV.U + deltaUV.V*deltaUV.V) > 0.0001f)
2332 rBS.deltaUV[i] = deltaUV;
2333 rBS.VertRefs[i] = i;
2334 bIsDeltaUV = true;
2336 attId++;
2339 if (useTgSpace)
2341 attr = rWedgeRef.Attributes[attId];
2342 CVector TgSpaceRef = CVector(attr.x, attr.y, attr.z);
2343 attr = rWedgeTar.Attributes[attId];
2344 CVector TgSpaceTar = CVector(attr.x, attr.y, attr.z);
2345 delta = TgSpaceTar - TgSpaceRef;
2346 if (delta.norm() > 0.001f)
2348 rBS.deltaTgSpace[i] = delta;
2349 rBS.VertRefs[i] = i;
2350 bIsDeltaTgSpace = true;
2352 attId++;
2355 } // End of all vertices added in blend shape
2357 // Delete unused items and calculate the number of vertex used (blended)
2359 sint32 nNbVertUsed = nNbVertVB;
2360 sint32 nDstPos = 0;
2361 for (j = 0; j < nNbVertVB; ++j)
2363 if (rBS.VertRefs[j] == 0xffffffff) // Is vertex UNused
2365 --nNbVertUsed;
2367 else // Vertex used
2369 if (nDstPos != j)
2371 rBS.VertRefs[nDstPos] = rBS.VertRefs[j];
2372 rBS.deltaPos[nDstPos] = rBS.deltaPos[j];
2373 rBS.deltaNorm[nDstPos] = rBS.deltaNorm[j];
2374 rBS.deltaUV[nDstPos] = rBS.deltaUV[j];
2375 rBS.deltaCol[nDstPos] = rBS.deltaCol[j];
2376 if (useTgSpace)
2378 rBS.deltaTgSpace[nDstPos] = rBS.deltaTgSpace[j];
2381 ++nDstPos;
2385 if (bIsDeltaPos)
2386 rBS.deltaPos.resize (nNbVertUsed);
2387 else
2388 rBS.deltaPos.resize (0);
2390 if (bIsDeltaNorm)
2391 rBS.deltaNorm.resize (nNbVertUsed);
2392 else
2393 rBS.deltaNorm.resize (0);
2395 if (bIsDeltaUV)
2396 rBS.deltaUV.resize (nNbVertUsed);
2397 else
2398 rBS.deltaUV.resize (0);
2400 if (bIsDeltaCol)
2401 rBS.deltaCol.resize (nNbVertUsed);
2402 else
2403 rBS.deltaCol.resize (0);
2405 if (bIsDeltaTgSpace)
2406 rBS.deltaTgSpace.resize (nNbVertUsed);
2407 else
2408 rBS.deltaTgSpace.resize (0);
2411 rBS.VertRefs.resize (nNbVertUsed);
2416 // ***************************************************************************
2417 void CMRMBuilder::buildMeshBuildMrm(const CMRMMeshFinal &finalMRM, CMeshMRMSkinnedGeom::CMeshBuildMRM &mbuild, uint32 vbFlags, uint32 nbMats, const CMesh::CMeshBuild &mb)
2419 sint i,j,k;
2420 sint attId;
2422 // reset the mbuild.
2423 mbuild= CMeshMRMSkinnedGeom::CMeshBuildMRM();
2424 // Setup VB.
2426 bool useFormatExt = false;
2427 // Check whether there are texture coordinates with more than 2 compnents, which force us to use an extended vertex format
2428 for (k = 0; k < CVertexBuffer::MaxStage; ++k)
2430 if (
2431 (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
2432 && mb.NumCoords[k] != 2)
2434 useFormatExt = true;
2435 break;
2439 uint numTexCoordUsed = 0;
2442 for (k = 0; k < CVertexBuffer::MaxStage; ++k)
2444 if (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
2446 numTexCoordUsed = k;
2450 if (!useFormatExt)
2452 // setup standard format
2453 mbuild.VBuffer.setVertexFormat(vbFlags);
2455 else // setup extended format
2457 mbuild.VBuffer.clearValueEx();
2458 if (vbFlags & CVertexBuffer::PositionFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::Position, CVertexBuffer::Float3);
2459 if (vbFlags & CVertexBuffer::NormalFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::Normal, CVertexBuffer::Float3);
2460 if (vbFlags & CVertexBuffer::PrimaryColorFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::PrimaryColor, CVertexBuffer::UChar4);
2461 if (vbFlags & CVertexBuffer::SecondaryColorFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::SecondaryColor, CVertexBuffer::UChar4);
2462 if (vbFlags & CVertexBuffer::WeightFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::Weight, CVertexBuffer::Float4);
2463 if (vbFlags & CVertexBuffer::PaletteSkinFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::PaletteSkin, CVertexBuffer::UChar4);
2464 if (vbFlags & CVertexBuffer::FogFlag) mbuild.VBuffer.addValueEx(CVertexBuffer::Fog, CVertexBuffer::Float1);
2466 for (k = 0; k < CVertexBuffer::MaxStage; ++k)
2468 if (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
2470 switch(mb.NumCoords[k])
2472 case 2:
2473 mbuild.VBuffer.addValueEx((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), CVertexBuffer::Float2);
2474 break;
2475 case 3:
2476 mbuild.VBuffer.addValueEx((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), CVertexBuffer::Float3);
2477 break;
2478 default:
2479 nlassert(0);
2480 break;
2484 mbuild.VBuffer.initEx();
2487 // Copy the UVRouting
2488 for (i=0; i<CVertexBuffer::MaxStage; i++)
2490 mbuild.VBuffer.setUVRouting (i, mb.UVRouting[i]);
2493 // Setup the VertexBuffer.
2494 // ========================
2495 // resize the VB.
2496 mbuild.VBuffer.setNumVertices((uint32)finalMRM.Wedges.size());
2498 CVertexBufferReadWrite vba;
2499 mbuild.VBuffer.lock (vba);
2501 // Setup SkinWeights.
2502 if(_Skinned)
2503 mbuild.SkinWeights.resize(finalMRM.Wedges.size());
2505 // fill the VB.
2506 for(i=0; i<(sint)finalMRM.Wedges.size(); i++)
2508 const CMRMMeshFinal::CWedge &wedge= finalMRM.Wedges[i];
2510 // setup Vertex.
2511 vba.setVertexCoord(i, wedge.Vertex);
2513 // seutp attributes.
2514 attId= 0;
2516 // For all activated attributes in mbuild, retrieve the attribute from the finalMRM.
2517 if(vbFlags & CVertexBuffer::NormalFlag)
2519 vba.setNormalCoord(i, wedge.Attributes[attId] );
2520 attId++;
2522 if(vbFlags & CVertexBuffer::PrimaryColorFlag)
2524 vba.setColor(i, attToColor(wedge.Attributes[attId]) );
2525 attId++;
2527 if(vbFlags & CVertexBuffer::SecondaryColorFlag)
2529 vba.setSpecular(i, attToColor(wedge.Attributes[attId]) );
2530 attId++;
2532 for(k=0; k<CVertexBuffer::MaxStage;k++)
2534 if(vbFlags & (CVertexBuffer::TexCoord0Flag<<k))
2536 switch(mb.NumCoords[k])
2538 case 2:
2539 vba.setTexCoord(i, k, (CUV) attToUvw(wedge.Attributes[attId]) );
2540 break;
2541 case 3:
2543 CUVW uvw = attToUvw(wedge.Attributes[attId]);
2544 vba.setValueFloat3Ex((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), i, uvw.U, uvw.V, uvw.W);
2546 break;
2547 default:
2548 nlassert(0);
2549 break;
2551 attId++;
2555 // Setup SkinWeights.
2556 if(_Skinned)
2558 mbuild.SkinWeights[i]= wedge.VertexSkin;
2563 // Build Lods.
2564 // ========================
2565 // resize
2566 mbuild.Lods.resize(finalMRM.Lods.size());
2567 // fill.
2568 for(i=0; i<(sint)finalMRM.Lods.size(); i++)
2570 const CMRMMeshFinal::CLod &srcLod= finalMRM.Lods[i];
2571 CMeshMRMSkinnedGeom::CLod &destLod= mbuild.Lods[i];
2573 // Basic.
2574 //---------
2576 // Copy NWedges infos.
2577 destLod.NWedges= srcLod.NWedges;
2578 // Copy Geomorphs infos.
2579 destLod.Geomorphs= srcLod.Geomorphs;
2582 // Reorder faces by rdrpass.
2583 //---------
2585 // First count the number of faces used by this LOD for each material
2586 vector<sint> matCount;
2587 // resize, and reset to 0.
2588 matCount.clear();
2589 matCount.resize(nbMats, 0);
2590 // For each face of this Lods, incr the mat face counter.
2591 for(j= 0; j<(sint)srcLod.Faces.size(); j++)
2593 sint matId= srcLod.Faces[j].MaterialId;
2594 nlassert(matId>=0);
2595 nlassert(matId<(sint)nbMats);
2596 // increment the refcount of this material by this LOD.
2597 matCount[matId]++;
2600 // Then for each material not empty, create a rdrPass, and ref it for this material.
2601 vector<sint> rdrPassIndex; // material to rdrPass map.
2602 rdrPassIndex.resize(nbMats);
2603 for(j=0; j<(sint)nbMats; j++)
2605 if(matCount[j]==0)
2606 rdrPassIndex[j]= -1;
2607 else
2609 // map material to rdrPass.
2610 sint idRdrPass= (sint)destLod.RdrPass.size();
2611 rdrPassIndex[j]= idRdrPass;
2612 // create a rdrPass.
2613 destLod.RdrPass.push_back(CMeshMRMSkinnedGeom::CRdrPass());
2614 // assign the good materialId to this rdrPass.
2615 destLod.RdrPass[idRdrPass].MaterialId= j;
2616 // reserve the array of faces of this rdrPass.
2617 destLod.RdrPass[idRdrPass].PBlock.reserve(3*matCount[j]);
2621 // Then for each face, add it to the good rdrPass of this Lod.
2622 for(j= 0; j<(sint)srcLod.Faces.size(); j++)
2624 sint matId= srcLod.Faces[j].MaterialId;
2625 sint idRdrPass= rdrPassIndex[matId];
2626 // add this face to the good rdrPass.
2627 sint w0= srcLod.Faces[j].WedgeId[0];
2628 sint w1= srcLod.Faces[j].WedgeId[1];
2629 sint w2= srcLod.Faces[j].WedgeId[2];
2630 destLod.RdrPass[idRdrPass].PBlock.push_back (w0);
2631 destLod.RdrPass[idRdrPass].PBlock.push_back (w1);
2632 destLod.RdrPass[idRdrPass].PBlock.push_back (w2);
2636 // Build skin info for this Lod.
2637 //---------
2638 for(j=0; j<NL3D_MESH_SKINNING_MAX_MATRIX; j++)
2640 destLod.InfluencedVertices[j].clear();
2642 destLod.MatrixInfluences.clear();
2643 if(_Skinned)
2645 // This is the set which tell what wedge has already been inserted.
2646 set<uint> wedgeInfSet;
2648 // First, build the list of vertices influenced by this Lod.
2649 for(j= 0; j<(sint)srcLod.Faces.size(); j++)
2651 for(k=0; k<3; k++)
2653 sint wedgeId= srcLod.Faces[j].WedgeId[k];
2654 // If it is a geomorph
2655 if(wedgeId<finalMRM.NGeomSpace)
2657 // add the start and end to the list (if not here). NB: wedgeId is both the id
2658 // of the dest wedge, and the id of the geomorph.
2659 sint wedgeStartId= destLod.Geomorphs[wedgeId].Start;
2660 sint wedgeEndId= destLod.Geomorphs[wedgeId].End;
2661 uint nMatUsedStart= finalMRM.Wedges[wedgeStartId].NSkinMatUsed;
2662 uint nMatUsedEnd= finalMRM.Wedges[wedgeEndId].NSkinMatUsed;
2664 // if insertion in the set work, add to the good array.
2665 if( wedgeInfSet.insert(wedgeStartId).second )
2666 destLod.InfluencedVertices[nMatUsedStart-1].push_back(wedgeStartId);
2667 if( wedgeInfSet.insert(wedgeEndId).second )
2668 destLod.InfluencedVertices[nMatUsedEnd-1].push_back(wedgeEndId);
2670 else
2672 uint nMatUsed= finalMRM.Wedges[wedgeId].NSkinMatUsed;
2674 // just add this wedge to the list (if not here).
2675 // if insertion in the set work, add to the array.
2676 if( wedgeInfSet.insert(wedgeId).second )
2677 destLod.InfluencedVertices[nMatUsed-1].push_back(wedgeId);
2682 // Optimisation: for better cache, sort the destLod.InfluencedVertices in increasing order.
2683 for(j=0; j<NL3D_MESH_SKINNING_MAX_MATRIX; j++)
2685 sort(destLod.InfluencedVertices[j].begin(), destLod.InfluencedVertices[j].end());
2689 // Then Build the MatrixInfluences array, for all thoses Influenced Vertices only.
2690 // This is the map MatrixId -> MatrixInfId.
2691 map<uint, uint> matrixInfMap;
2693 // For all influenced vertices, flags matrix they use.
2694 uint iSkinMat;
2695 for(iSkinMat= 0; iSkinMat<NL3D_MESH_SKINNING_MAX_MATRIX; iSkinMat++)
2697 for(j= 0; j<(sint)destLod.InfluencedVertices[iSkinMat].size(); j++)
2699 uint wedgeId= destLod.InfluencedVertices[iSkinMat][j];
2701 // take the original wedge.
2702 const CMRMMeshFinal::CWedge &wedge= finalMRM.Wedges[wedgeId];
2703 // For all matrix with not null influence...
2704 for(k= 0; k<NL3D_MESH_SKINNING_MAX_MATRIX; k++)
2706 float matWeight= wedge.VertexSkin.Weights[k];
2708 // This check the validity of skin weights sort. If false, problem before in the algo.
2709 if((uint)k<iSkinMat+1)
2711 nlassert( matWeight>0 );
2713 else
2715 nlassert( matWeight==0 );
2717 // if not null influence.
2718 if(matWeight>0)
2720 uint matId= wedge.VertexSkin.MatrixId[k];
2722 // search/insert the matrixInfId.
2723 map<uint, uint>::iterator it= matrixInfMap.find(matId);
2724 if( it==matrixInfMap.end() )
2726 uint matInfId= (uint)destLod.MatrixInfluences.size();
2727 matrixInfMap.insert( make_pair(matId, matInfId) );
2728 // create the new MatrixInfluence.
2729 destLod.MatrixInfluences.push_back(matId);
2740 // Indicate Skinning.
2741 mbuild.Skinned= _Skinned;
2745 bool useTgSpace = mb.MeshVertexProgram != NULL ? mb.MeshVertexProgram->needTangentSpace() : false;
2747 // Construct Blend Shapes
2748 //// mbuild <- finalMRM
2749 mbuild.BlendShapes.resize (finalMRM.MRMBlendShapesFinals.size());
2750 for (k = 0; k < (sint)mbuild.BlendShapes.size(); ++k)
2752 CBlendShape &rBS = mbuild.BlendShapes[k];
2753 sint32 nNbVertVB = (sint32)finalMRM.Wedges.size();
2754 bool bIsDeltaPos = false;
2755 rBS.deltaPos.resize (nNbVertVB, CVector(0.0f,0.0f,0.0f));
2756 bool bIsDeltaNorm = false;
2757 rBS.deltaNorm.resize (nNbVertVB, CVector(0.0f,0.0f,0.0f));
2758 bool bIsDeltaUV = false;
2759 rBS.deltaUV.resize (nNbVertVB, CUV(0.0f,0.0f));
2760 bool bIsDeltaCol = false;
2761 rBS.deltaCol.resize (nNbVertVB, CRGBAF(0.0f,0.0f,0.0f,0.0f));
2762 bool bIsDeltaTgSpace = false;
2763 if (useTgSpace)
2765 rBS.deltaTgSpace.resize(nNbVertVB, CVector::Null);
2768 rBS.VertRefs.resize (nNbVertVB, 0xffffffff);
2770 for (i = 0; i < nNbVertVB; i++)
2772 const CMRMMeshFinal::CWedge &rWedgeRef = finalMRM.Wedges[i];
2773 const CMRMMeshFinal::CWedge &rWedgeTar = finalMRM.MRMBlendShapesFinals[k].Wedges[i];
2775 CVector delta = rWedgeTar.Vertex - rWedgeRef.Vertex;
2776 CVectorH attr;
2778 if (delta.norm() > 0.001f)
2780 rBS.deltaPos[i] = delta;
2781 rBS.VertRefs[i] = i;
2782 bIsDeltaPos = true;
2785 attId = 0;
2786 if (vbFlags & CVertexBuffer::NormalFlag)
2788 attr = rWedgeRef.Attributes[attId];
2789 CVector NormRef = CVector(attr.x, attr.y, attr.z);
2790 attr = rWedgeTar.Attributes[attId];
2791 CVector NormTar = CVector(attr.x, attr.y, attr.z);
2792 delta = NormTar - NormRef;
2793 if (delta.norm() > 0.001f)
2795 rBS.deltaNorm[i] = delta;
2796 rBS.VertRefs[i] = i;
2797 bIsDeltaNorm = true;
2799 attId++;
2802 if (vbFlags & CVertexBuffer::PrimaryColorFlag)
2804 attr = rWedgeRef.Attributes[attId];
2805 CRGBAF RGBARef = CRGBAF(attr.x/255.0f, attr.y/255.0f, attr.z/255.0f, attr.w/255.0f);
2806 attr = rWedgeTar.Attributes[attId];
2807 CRGBAF RGBATar = CRGBAF(attr.x/255.0f, attr.y/255.0f, attr.z/255.0f, attr.w/255.0f);
2808 CRGBAF deltaRGBA = RGBATar - RGBARef;
2809 if ((deltaRGBA.R*deltaRGBA.R + deltaRGBA.G*deltaRGBA.G +
2810 deltaRGBA.B*deltaRGBA.B + deltaRGBA.A*deltaRGBA.A) > 0.0001f)
2812 rBS.deltaCol[i] = deltaRGBA;
2813 rBS.VertRefs[i] = i;
2814 bIsDeltaCol = true;
2816 attId++;
2819 if (vbFlags & CVertexBuffer::SecondaryColorFlag)
2820 { // Nothing to do !
2821 attId++;
2824 // Do that only for the UV0
2825 if (vbFlags & CVertexBuffer::TexCoord0Flag)
2827 attr = rWedgeRef.Attributes[attId];
2828 CUV UVRef = CUV(attr.x, attr.y);
2829 attr = rWedgeTar.Attributes[attId];
2830 CUV UVTar = CUV(attr.x, attr.y);
2831 CUV deltaUV = UVTar - UVRef;
2832 if ((deltaUV.U*deltaUV.U + deltaUV.V*deltaUV.V) > 0.0001f)
2834 rBS.deltaUV[i] = deltaUV;
2835 rBS.VertRefs[i] = i;
2836 bIsDeltaUV = true;
2838 attId++;
2841 if (useTgSpace)
2843 attr = rWedgeRef.Attributes[attId];
2844 CVector TgSpaceRef = CVector(attr.x, attr.y, attr.z);
2845 attr = rWedgeTar.Attributes[attId];
2846 CVector TgSpaceTar = CVector(attr.x, attr.y, attr.z);
2847 delta = TgSpaceTar - TgSpaceRef;
2848 if (delta.norm() > 0.001f)
2850 rBS.deltaTgSpace[i] = delta;
2851 rBS.VertRefs[i] = i;
2852 bIsDeltaTgSpace = true;
2854 attId++;
2857 } // End of all vertices added in blend shape
2859 // Delete unused items and calculate the number of vertex used (blended)
2861 sint32 nNbVertUsed = nNbVertVB;
2862 sint32 nDstPos = 0;
2863 for (j = 0; j < nNbVertVB; ++j)
2865 if (rBS.VertRefs[j] == 0xffffffff) // Is vertex UNused
2867 --nNbVertUsed;
2869 else // Vertex used
2871 if (nDstPos != j)
2873 rBS.VertRefs[nDstPos] = rBS.VertRefs[j];
2874 rBS.deltaPos[nDstPos] = rBS.deltaPos[j];
2875 rBS.deltaNorm[nDstPos] = rBS.deltaNorm[j];
2876 rBS.deltaUV[nDstPos] = rBS.deltaUV[j];
2877 rBS.deltaCol[nDstPos] = rBS.deltaCol[j];
2878 if (useTgSpace)
2880 rBS.deltaTgSpace[nDstPos] = rBS.deltaTgSpace[j];
2883 ++nDstPos;
2887 if (bIsDeltaPos)
2888 rBS.deltaPos.resize (nNbVertUsed);
2889 else
2890 rBS.deltaPos.resize (0);
2892 if (bIsDeltaNorm)
2893 rBS.deltaNorm.resize (nNbVertUsed);
2894 else
2895 rBS.deltaNorm.resize (0);
2897 if (bIsDeltaUV)
2898 rBS.deltaUV.resize (nNbVertUsed);
2899 else
2900 rBS.deltaUV.resize (0);
2902 if (bIsDeltaCol)
2903 rBS.deltaCol.resize (nNbVertUsed);
2904 else
2905 rBS.deltaCol.resize (0);
2907 if (bIsDeltaTgSpace)
2908 rBS.deltaTgSpace.resize (nNbVertUsed);
2909 else
2910 rBS.deltaTgSpace.resize (0);
2913 rBS.VertRefs.resize (nNbVertUsed);
2918 // ***************************************************************************
2919 void CMRMBuilder::buildBlendShapes (CMRMMesh& baseMesh,
2920 std::vector<CMesh::CMeshBuild*> &bsList, uint32 VertexFlags)
2922 uint32 i, j, k, m, destIndex;
2923 uint32 attId;
2924 CVectorH vh;
2925 vector<CMRMBlendShape> &bsMeshes= baseMesh.BlendShapes;
2927 bsMeshes.resize (bsList.size());
2929 for (i = 0; i < bsList.size(); ++i)
2931 // Construct a blend shape like a mrm mesh
2932 nlassert (baseMesh.Vertices.size() == bsList[i]->Vertices.size());
2933 bsMeshes[i].Vertices.resize (baseMesh.Vertices.size());
2934 bsMeshes[i].Vertices = bsList[i]->Vertices;
2936 bsMeshes[i].NumAttributes = baseMesh.NumAttributes;
2937 for (j = 0; j < (uint32)bsMeshes[i].NumAttributes; ++j)
2938 bsMeshes[i].Attributes[j].resize(baseMesh.Attributes[j].size());
2940 // For all corners parse the faces (given by the baseMesh) and construct blend shape mrm meshes
2941 for (j = 0; j < baseMesh.Faces.size(); ++j)
2942 for (k = 0; k < 3; ++k)
2944 const CMesh::CCorner &srcCorner = bsList[i]->Faces[j].Corner[k];
2945 CMRMCorner &neutralCorner = baseMesh.Faces[j].Corner[k];
2947 attId= 0;
2949 if (VertexFlags & CVertexBuffer::NormalFlag)
2951 destIndex = neutralCorner.Attributes[attId];
2952 vh.x = srcCorner.Normal.x;
2953 vh.y = srcCorner.Normal.y;
2954 vh.z = srcCorner.Normal.z;
2955 vh.w = 0.0f;
2956 bsMeshes[i].Attributes[attId].operator[](destIndex) = vh;
2957 attId++;
2959 if (VertexFlags & CVertexBuffer::PrimaryColorFlag)
2961 destIndex = neutralCorner.Attributes[attId];
2962 vh.x = srcCorner.Color.R;
2963 vh.y = srcCorner.Color.G;
2964 vh.z = srcCorner.Color.B;
2965 vh.w = srcCorner.Color.A;
2966 bsMeshes[i].Attributes[attId].operator[](destIndex) = vh;
2967 attId++;
2969 if (VertexFlags & CVertexBuffer::SecondaryColorFlag)
2971 destIndex = neutralCorner.Attributes[attId];
2972 vh.x = srcCorner.Specular.R;
2973 vh.y = srcCorner.Specular.G;
2974 vh.z = srcCorner.Specular.B;
2975 vh.w = srcCorner.Specular.A;
2976 bsMeshes[i].Attributes[attId].operator[](destIndex) = vh;
2977 attId++;
2979 for (m = 0; m < CVertexBuffer::MaxStage; ++m)
2981 if (VertexFlags & (CVertexBuffer::TexCoord0Flag<<m))
2983 destIndex = neutralCorner.Attributes[attId];
2984 vh.x = srcCorner.Uvws[m].U;
2985 vh.y = srcCorner.Uvws[m].V;
2986 vh.z = srcCorner.Uvws[m].W;
2987 vh.w = 0.0f;
2988 bsMeshes[i].Attributes[attId].operator[](destIndex) = vh;
2989 attId++;
2997 // ***************************************************************************
2998 void CMRMBuilder::compileMRM(const CMesh::CMeshBuild &mbuild, std::vector<CMesh::CMeshBuild*> &bsList,
2999 const CMRMParameters &params, CMeshMRMGeom::CMeshBuildMRM &mrmMesh,
3000 uint numMaxMaterial)
3002 // Temp data.
3003 CMRMMesh baseMesh;
3004 vector<CMRMMeshGeom> lodMeshs;
3005 CMRMMeshFinal finalMRM;
3006 vector<CMRMMeshFinal> finalBsMRM;
3007 uint32 vbFlags;
3010 nlassert(params.DistanceFinest>=0);
3011 nlassert(params.DistanceMiddle > params.DistanceFinest);
3012 nlassert(params.DistanceCoarsest > params.DistanceMiddle);
3015 // Copy some parameters.
3016 _SkinReduction= params.SkinReduction;
3018 // Skinning??
3019 _Skinned= ((mbuild.VertexFlags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag);
3020 // Skinning is OK only if SkinWeights are of same size as vertices.
3021 _Skinned= _Skinned && ( mbuild.Vertices.size()==mbuild.SkinWeights.size() );
3023 // MeshInterface setuped ?
3024 _HasMeshInterfaces= buildMRMSewingMeshes(mbuild, params.NLods, params.Divisor);
3026 // from mbuild, build an internal MRM mesh representation.
3027 // vbFlags returned is the VBuffer format supported by CMRMBuilder.
3028 // NB: skinning is removed because skinning is made in software in CMeshMRMGeom.
3029 vbFlags= buildMrmBaseMesh(mbuild, baseMesh);
3031 // Construct all blend shapes in the same way we have constructed the basemesh mrm
3032 buildBlendShapes (baseMesh, bsList, vbFlags);
3034 // If skinned, must ensure that skin weights have weights in ascending order.
3035 if(_Skinned)
3037 normalizeBaseMeshSkin(baseMesh);
3040 // from this baseMesh, builds all LODs of the MRM, with geomorph info. NB: vertices/wedges are duplicated.
3041 buildAllLods ( baseMesh, lodMeshs, params.NLods, params.Divisor );
3043 // From this array of LOD, build a finalMRM, by regrouping identical vertices/wedges, and compute index geomorphs.
3044 buildFinalMRM(lodMeshs, finalMRM);
3046 // From this finalMRM, build output: a CMeshBuildMRM.
3047 buildMeshBuildMrm(finalMRM, mrmMesh, vbFlags, numMaxMaterial, mbuild);
3049 // Copy degradation control params.
3050 mrmMesh.DistanceFinest= params.DistanceFinest;
3051 mrmMesh.DistanceMiddle= params.DistanceMiddle;
3052 mrmMesh.DistanceCoarsest= params.DistanceCoarsest;
3056 // ***************************************************************************
3057 void CMRMBuilder::compileMRM(const CMesh::CMeshBuild &mbuild, std::vector<CMesh::CMeshBuild*> &bsList,
3058 const CMRMParameters &params, CMeshMRMSkinnedGeom::CMeshBuildMRM &mrmMesh,
3059 uint numMaxMaterial)
3061 // Temp data.
3062 CMRMMesh baseMesh;
3063 vector<CMRMMeshGeom> lodMeshs;
3064 CMRMMeshFinal finalMRM;
3065 vector<CMRMMeshFinal> finalBsMRM;
3066 uint32 vbFlags;
3069 nlassert(params.DistanceFinest>=0);
3070 nlassert(params.DistanceMiddle > params.DistanceFinest);
3071 nlassert(params.DistanceCoarsest > params.DistanceMiddle);
3074 // Copy some parameters.
3075 _SkinReduction= params.SkinReduction;
3077 // Skinning??
3078 _Skinned= ((mbuild.VertexFlags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag);
3079 // Skinning is OK only if SkinWeights are of same size as vertices.
3080 _Skinned= _Skinned && ( mbuild.Vertices.size()==mbuild.SkinWeights.size() );
3082 // MeshInterface setuped ?
3083 _HasMeshInterfaces= buildMRMSewingMeshes(mbuild, params.NLods, params.Divisor);
3085 // from mbuild, build an internal MRM mesh representation.
3086 // vbFlags returned is the VBuffer format supported by CMRMBuilder.
3087 // NB: skinning is removed because skinning is made in software in CMeshMRMGeom.
3088 vbFlags= buildMrmBaseMesh(mbuild, baseMesh);
3090 // Construct all blend shapes in the same way we have constructed the basemesh mrm
3091 buildBlendShapes (baseMesh, bsList, vbFlags);
3093 // If skinned, must ensure that skin weights have weights in ascending order.
3094 if(_Skinned)
3096 normalizeBaseMeshSkin(baseMesh);
3099 // from this baseMesh, builds all LODs of the MRM, with geomorph info. NB: vertices/wedges are duplicated.
3100 buildAllLods ( baseMesh, lodMeshs, params.NLods, params.Divisor );
3102 // From this array of LOD, build a finalMRM, by regrouping identical vertices/wedges, and compute index geomorphs.
3103 buildFinalMRM(lodMeshs, finalMRM);
3105 // From this finalMRM, build output: a CMeshBuildMRM.
3106 buildMeshBuildMrm(finalMRM, mrmMesh, vbFlags, numMaxMaterial, mbuild);
3108 // Copy degradation control params.
3109 mrmMesh.DistanceFinest= params.DistanceFinest;
3110 mrmMesh.DistanceMiddle= params.DistanceMiddle;
3111 mrmMesh.DistanceCoarsest= params.DistanceCoarsest;
3115 // ***************************************************************************
3116 // ***************************************************************************
3117 // MRM Interface system
3118 // ***************************************************************************
3119 // ***************************************************************************
3121 // ***************************************************************************
3122 bool CMRMBuilder::buildMRMSewingMeshes(const CMesh::CMeshBuild &mbuild, uint nWantedLods, uint divisor)
3124 nlassert(nWantedLods>=1);
3125 nlassert(divisor>=1);
3126 if(mbuild.Interfaces.empty())
3127 return false;
3128 // must have same size
3129 if(mbuild.InterfaceLinks.size()!=mbuild.Vertices.size())
3130 return false;
3132 // **** For each interface, MRM-ize it and store.
3133 _SewingMeshes.resize(mbuild.Interfaces.size());
3134 for(uint i=0;i<mbuild.Interfaces.size();i++)
3136 _SewingMeshes[i].build(mbuild.Interfaces[i], nWantedLods, divisor);
3140 return true;
3144 } // NL3D