1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "../zone_lib/zone_utility.h"
28 #include "nel/misc/types_nl.h"
29 #include "nel/misc/file.h"
30 #include "nel/misc/common.h"
31 #include "nel/3d/quad_tree.h"
32 #include "nel/3d/zone.h"
33 #include "nel/3d/landscape.h"
34 #include "nel/3d/zone_smoother.h"
35 #include "nel/3d/zone_tgt_smoother.h"
36 #include "nel/3d/zone_corner_smoother.h"
40 using namespace NLMISC
;
50 std::string outputDir
;
51 std::string outputExt
;
53 float weldRadius
= 1.1f
;
61 // Define this to stop the welder on a source edge
62 // #define NL_DEBUG_WELD
63 #define NL_DEBUG_WELD_V0 (CVector(16320,-24064,0))
64 #define NL_DEBUG_WELD_V1 (CVector(16352,-24065,0))
65 #define NL_DEBUG_WELD_THRESHOLD 1.f
68 bool isTheSame (const CVector
&v0
, const CVector
&v1
)
70 CVector delta
= v0
- v1
;
72 return delta
.norm() < NL_DEBUG_WELD_THRESHOLD
;
74 #endif // NL_DEBUG_WELD
77 * CWeldableVertexInfos
79 struct CWeldableVertexInfos
81 uint16 IndexInZone
; // base vertex
82 sint PatchIndex
; // patch
83 uint8 PatchVertex
; // 0,1,2,3
85 CWeldableVertexInfos()
92 bool operator< (const CWeldableVertexInfos
& wvinf
) const
94 if(IndexInZone
<wvinf
.IndexInZone
)
96 if(IndexInZone
>wvinf
.IndexInZone
)
98 if(PatchIndex
<wvinf
.PatchIndex
)
100 if(PatchIndex
>wvinf
.PatchIndex
)
102 return PatchVertex
<wvinf
.PatchVertex
;
107 struct CVectorInfluence
115 struct CAdjacentVertex
123 /*******************************************************************\
125 \*******************************************************************/
126 void writeInstructions()
128 printf("zone_welder <input.zone><output.zone>[<weld threshold>]\n");
129 printf("\t/? for this help\n");
133 /*******************************************************************\
135 \*******************************************************************/
136 bool getPatchAndEdge(const std::vector
<CPatchInfo
>& patchs
,
137 uint16 baseVertex1
, uint16 baseVertex2
,
143 for(ptch
=0; ptch
<patchs
.size(); ptch
++)
148 if(patchs
[ptch
].BaseVertices
[i
] == baseVertex1
)
151 fprintf(fdbg
,"patch %d continent bv %d : %d %d %d %d\n",
154 patchs
[ptch
].BaseVertices
[0],
155 patchs
[ptch
].BaseVertices
[1],
156 patchs
[ptch
].BaseVertices
[2],
157 patchs
[ptch
].BaseVertices
[3]);
160 if(patchs
[ptch
].BaseVertices
[(i
+1)%4] == baseVertex2
)
166 if(patchs
[ptch
].BaseVertices
[(i
-1)%4] == baseVertex2
)
178 void CleanZone ( std::vector
<CPatchInfo
> &zoneInfos
, uint zoneId
, const CAABBoxExt
&zoneBBox
, float weldThreshold
);
180 /*******************************************************************\
182 \*******************************************************************/
183 void weldZones(const char *center
)
187 // load zone in the center
188 CIFile
zoneFile(inputDir
+center
+inputExt
);
190 zone
.serial(zoneFile
);
193 // retrieving infos from the center zone
194 uint16 centerZoneId
= zone
.getZoneId();
195 std::vector
<CPatchInfo
> centerZonePatchs
;
196 std::vector
<CBorderVertex
> centerZoneBorderVertices
;
197 zone
.retrieve(centerZonePatchs
, centerZoneBorderVertices
);
199 std::vector
<CPatchInfo
>::iterator itptch
;
200 std::vector
<CBorderVertex
>::iterator itbv
;
202 // if no id yet, we add a correct id
205 centerZoneId
= createZoneId(center
);
207 // edge neighbour : current zone
208 for(itptch
= centerZonePatchs
.begin(); itptch
!=centerZonePatchs
.end(); itptch
++)
212 (*itptch
).BindEdges
[j
].ZoneId
= centerZoneId
;
216 // border vertices neighbour : current zone
217 for(itbv
= centerZoneBorderVertices
.begin(); itbv
<centerZoneBorderVertices
.end(); itbv
++)
219 (*itbv
).NeighborZoneId
= centerZoneId
;
224 fprintf(fdbg
,"id(center) = %d\n",centerZoneId
);
227 // *** Clean internal zone
228 // * Bind 1-1 1-2 1-4 internal patches that are not binded
229 // * Make a global welded on vertices
230 // * Force tangents position
231 CleanZone ( centerZonePatchs
, centerZoneId
, zone
.getZoneBB(), weldRadius
);
233 // Yoyo was here: Smooth the tangents of the zone.
234 //================================================
235 // NB: do it only for edges sharing 2 patchs of centerZone. (don't care adjacent zones).
236 // smoothing with adjacent zones is done with a better smoothing tool: CZoneTgtSmoother, see below,
237 // after the weld of the zone.
239 CZoneSmoother zonesmoother
;
240 CZoneSmoother::CZoneInfo smoothZones
[5];
241 smoothZones
[0].ZoneId
= centerZoneId
;
242 smoothZones
[0].Patchs
= ¢erZonePatchs
;
244 zonesmoother
.smoothTangents(smoothZones
, (float)(Pi
/6));
249 // load 8 adjacent adjZones
250 bool adjZoneFileFound
[8];
252 CZoneInfo adjZoneInfos
[8];
253 uint16 adjZonesId
[8];
254 std::vector
<std::string
> adjZonesName
;
255 getAdjacentZonesName(center
, adjZonesName
);
258 if(adjZonesName
[i
]=="empty") continue;
260 adjZoneFileFound
[i
] = true;
264 std::string
ss(outputDir
+adjZonesName
[i
]+outputExt
);
267 printf("reading file %s\n", ss
.c_str());
268 adjZones
[i
].serial(f
);
269 adjZones
[i
].retrieve(adjZoneInfos
[i
].Patchs
, adjZoneInfos
[i
].BorderVertices
);
270 adjZoneInfos
[i
].ZoneId
= adjZonesId
[i
] = adjZones
[i
].getZoneId();
275 // nlwarning ("WARNING File not found: %s\n", ss.c_str());
276 adjZonesName
[i
]="empty";
279 catch(const exception
&e
)
281 nlwarning ("ERROR %s\n", e
.what ());
282 adjZoneFileFound
[i
] = false;
286 // QuadTree for storing adjZones points
287 CQuadTree
<CWeldableVertexInfos
> quadTrees
[8];
289 // new base, to change from XZ to XY (Nel speaking)
294 base
.setRot(I
,J
,K
, true);
300 uint16 weldCount
= 0;
303 vector
<string
> errorMessage
;
307 if(adjZonesName
[i
]=="empty") continue;
308 if(!adjZoneFileFound
[i
]) continue;
312 CAABBoxExt bb
= adjZones
[i
].getZoneBB();
313 quadTrees
[i
].create (5, bb
.getCenter(), 2*bb
.getRadius());
314 quadTrees
[i
].changeBase(base
);
316 // retrieving infos from the current adjacent zone
317 std::vector
<CPatchInfo
> &adjZonePatchs
= adjZoneInfos
[i
].Patchs
;
318 std::vector
<CBorderVertex
> &adjZoneBorderVertices
= adjZoneInfos
[i
].BorderVertices
;
321 // if no id yet, we add a correct id
322 nlassert(adjZonesId
[i
]!=0);
325 adjZonesId
[i
] = createZoneId(getName (adjZonesName
[i
]));
326 adjZoneInfos
[i
].ZoneId
= adjZonesId
[i
];
328 // edge neighbour : current zone
329 for(itptch
= adjZonePatchs
.begin(); itptch
!=adjZonePatchs
.end(); itptch
++)
333 (*itptch
).BindEdges
[j
].ZoneId
= adjZonesId
[i
];
337 // border vertices neighbour : current zone
338 for(itbv
= adjZoneBorderVertices
.begin(); itbv
!=adjZoneBorderVertices
.end(); itbv
++)
340 (*itbv
).NeighborZoneId
= adjZonesId
[i
];
345 fprintf(fdbg
,"------------------------------------------\n");
346 fprintf(fdbg
,"id(%d) = %d\n",i
,adjZonesId
[i
]);
349 // an edge of current adjacent patch with neighbour zoneId==center zoneId is
350 // set to no neighbour.
351 for(ptch
= 0; ptch
<adjZonePatchs
.size(); ptch
++)
355 if(adjZonePatchs
[ptch
].BindEdges
[j
].ZoneId
== centerZoneId
)
357 adjZonePatchs
[ptch
].BindEdges
[j
].NPatchs
= 0;
362 fprintf(fdbg
,"(before) zone %u bordervertices size : %u\n",i
,(uint
)adjZoneBorderVertices
.size());
364 // delete border vertices of the adjacent zone if their neighbour zoneId
365 // is equal to current zone zoneId
366 std::vector
<CBorderVertex
>::iterator itborder
= adjZoneBorderVertices
.begin();
367 while(itborder
!= adjZoneBorderVertices
.end())
369 if((*itborder
).NeighborZoneId
== centerZoneId
)
371 itborder
= adjZoneBorderVertices
.erase(itborder
);
376 fprintf(fdbg
,"(after) zone %u bordervertices size : %u\n",i
,(uint
)adjZoneBorderVertices
.size());
378 // A set for storing base vertex index already added in the quad tree
379 std::set
<uint16
> adjBaseVertexIndexSet
;
381 // if point in adjacent zone is not in the set :
382 // -> add it in the set
383 // -> add it in the quad
384 for(ptch
= 0; ptch
<adjZonePatchs
.size(); ptch
++)
388 CWeldableVertexInfos wvinf
;
389 wvinf
.IndexInZone
= adjZonePatchs
[ptch
].BaseVertices
[j
]; // useful ????
390 wvinf
.PatchIndex
= ptch
;
391 wvinf
.PatchVertex
= j
;
392 if(adjBaseVertexIndexSet
.find(wvinf
.IndexInZone
) == adjBaseVertexIndexSet
.end())
394 adjBaseVertexIndexSet
.insert(wvinf
.IndexInZone
);
397 bboxmin
.x
= adjZonePatchs
[ptch
].Patch
.Vertices
[j
].x
;
398 bboxmin
.y
= adjZonePatchs
[ptch
].Patch
.Vertices
[j
].y
;
399 bboxmin
.z
= adjZonePatchs
[ptch
].Patch
.Vertices
[j
].z
;
401 quadTrees
[i
].insert(bboxmin
,bboxmax
,wvinf
);
406 quadTrees
[i
].clearSelection();
409 float bboxRadius
= 10; //TEMP !!
411 std::set
<uint16
> centerBaseVertexIndexSet
;
412 std::set
<uint16
> currentAdjBaseVertexIndexSet
;
414 for(ptch
=0; ptch
<centerZonePatchs
.size(); ptch
++) // for all patchs in center zone
416 // stores infos for edge part
417 CWeldableVertexInfos nearVertexInfos
[4];
425 // for every points in center patch we look for close points in adjacent patch
426 for(j
=0; j
<4; j
++) // 4 patch vertices (in center zone)
431 // already 'checked for welding' vertices are stored in a set
432 centerBaseVertexIndexSet
.insert(centerZonePatchs
[ptch
].BaseVertices
[j
]);
434 //fprintf(fdbg,"%d - %d) CZBV(%d)\n",i,baseVertexIndexSet.size(),centerZonePatchs[ptch].BaseVertices[j]);
436 bboxmin
.x
= centerZonePatchs
[ptch
].Patch
.Vertices
[j
].x
- bboxRadius
;
437 bboxmin
.y
= centerZonePatchs
[ptch
].Patch
.Vertices
[j
].y
- bboxRadius
;
438 bboxmin
.z
= centerZonePatchs
[ptch
].Patch
.Vertices
[j
].z
- bboxRadius
;
440 bboxmax
.x
= centerZonePatchs
[ptch
].Patch
.Vertices
[j
].x
+ bboxRadius
;
441 bboxmax
.y
= centerZonePatchs
[ptch
].Patch
.Vertices
[j
].y
+ bboxRadius
;
442 bboxmax
.z
= centerZonePatchs
[ptch
].Patch
.Vertices
[j
].z
+ bboxRadius
;
444 //quadTrees[i].select(bboxmin,bboxmax);
445 quadTrees
[i
].selectAll(); // TEMP !!!
447 // current vertex coordinates in center zone
449 vctr
.x
= centerZonePatchs
[ptch
].Patch
.Vertices
[j
].x
;
450 vctr
.y
= centerZonePatchs
[ptch
].Patch
.Vertices
[j
].y
;
451 vctr
.z
= centerZonePatchs
[ptch
].Patch
.Vertices
[j
].z
;
453 CWeldableVertexInfos wvinf
;
454 float minDistance
= weldRadius
+ 1; // rq: we weld only if we found a distance
455 // inferior to weldRadius
457 CQuadTree
<CWeldableVertexInfos
>::CIterator itqdt
= quadTrees
[i
].begin();
458 // for all points near of current vertex in adjacent zone..
459 while (itqdt
!= quadTrees
[i
].end())
462 vadj
.x
= adjZonePatchs
[(*itqdt
).PatchIndex
].Patch
.Vertices
[(*itqdt
).PatchVertex
].x
;
463 vadj
.y
= adjZonePatchs
[(*itqdt
).PatchIndex
].Patch
.Vertices
[(*itqdt
).PatchVertex
].y
;
464 vadj
.z
= adjZonePatchs
[(*itqdt
).PatchIndex
].Patch
.Vertices
[(*itqdt
).PatchVertex
].z
;
467 adjToCenter
.x
= vctr
.x
- vadj
.x
;
468 adjToCenter
.y
= vctr
.y
- vadj
.y
;
469 adjToCenter
.z
= vctr
.z
- vadj
.z
;
470 float dist
= adjToCenter
.norm();
472 // if dist min we keep infos on this vertex(adj zone)
473 // we keep the closest.
474 if(dist
<weldRadius
&& dist
<minDistance
)
477 nlverify (!isTheSame (centerZonePatchs
[ptch
].Patch
.Vertices
[j
], NL_DEBUG_WELD_V0
));
478 nlverify (!isTheSame (centerZonePatchs
[ptch
].Patch
.Vertices
[j
], NL_DEBUG_WELD_V1
));
479 #endif // NL_DEBUG_WELD
486 quadTrees
[i
].clearSelection();
488 if(minDistance
<weldRadius
) // i.e if we have found 2 vertices to weld
490 // we save CBorderVertex info, and add it into the adjacent zone
491 CBorderVertex adjBorderV
;
492 adjBorderV
.CurrentVertex
= wvinf
.IndexInZone
;
493 adjBorderV
.NeighborZoneId
= centerZoneId
;
494 adjBorderV
.NeighborVertex
= centerZonePatchs
[ptch
].BaseVertices
[j
];
495 nearVertexInfos
[j
] = wvinf
;
497 // we save CBorderVertex info, and add it into the center zone
498 CBorderVertex centerBorderV
;
499 centerBorderV
.CurrentVertex
= centerZonePatchs
[ptch
].BaseVertices
[j
];
500 centerBorderV
.NeighborZoneId
= adjZonesId
[i
];
501 centerBorderV
.NeighborVertex
= wvinf
.IndexInZone
;
505 if(centerBaseVertexIndexSet
.find(centerZonePatchs
[ptch
].BaseVertices
[j
]) != centerBaseVertexIndexSet
.end())
507 if(currentAdjBaseVertexIndexSet
.find(wvinf
.IndexInZone
) == currentAdjBaseVertexIndexSet
.end())
509 currentAdjBaseVertexIndexSet
.insert(wvinf
.IndexInZone
);
510 adjZoneBorderVertices
.push_back(adjBorderV
);
511 centerZoneBorderVertices
.push_back(centerBorderV
);
515 fprintf(fdbg
,"%d) weld vertices : zone%d.(patch%d.vertex%d).baseVertex%d to centerZone.(patch%d.vertex%d).baseVertex%d\n",
516 weldCount
,i
,wvinf
.PatchIndex
,wvinf
.PatchVertex
,wvinf
.IndexInZone
,ptch
,j
,centerZonePatchs
[ptch
].BaseVertices
[j
]);
525 // then we bind edges (made of weldable vertices) and modify tangents
531 (isTheSame (centerZonePatchs
[ptch
].Patch
.Vertices
[j
], NL_DEBUG_WELD_V0
) ||
532 isTheSame (centerZonePatchs
[ptch
].Patch
.Vertices
[(j
+1)%4], NL_DEBUG_WELD_V0
) ) &&
533 (isTheSame (centerZonePatchs
[ptch
].Patch
.Vertices
[j
], NL_DEBUG_WELD_V1
) ||
534 isTheSame (centerZonePatchs
[ptch
].Patch
.Vertices
[(j
+1)%4], NL_DEBUG_WELD_V1
) )
537 #endif // NL_DEBUG_WELD
538 // if vertex has been welded...
539 if(toWeld
[j
] == false) continue;
540 // ...we look if next vertex(i.e if the edge) in center zone has to be welded
541 if(toWeld
[(j
+1)%4] == false) continue;
543 // We know the two adjacent base vertices
544 // we look for the adjacent patch and the edge containing these vertices
547 if(! getPatchAndEdge(adjZonePatchs
,
548 nearVertexInfos
[j
].IndexInZone
,
549 nearVertexInfos
[(j
+1)%4].IndexInZone
,
554 fprintf(fdbg
,"* Error * : Can't find patch containing the following edge : %d - %d\n",
555 nearVertexInfos
[j
].IndexInZone
,
556 nearVertexInfos
[(j
+1)%4].IndexInZone
);
558 nlwarning ("ERROR : zone_welder : Can't find patch containing the following edge : %d - %d\n",
559 nearVertexInfos
[j
].IndexInZone
,
560 nearVertexInfos
[(j
+1)%4].IndexInZone
);
565 fprintf(fdbg
,"weld edges : zone%d.patch%d.edge%d(%d-%d) to centerZone.patch%d.edge%d(%d-%d)\n",
569 nearVertexInfos
[j
].IndexInZone
,
570 nearVertexInfos
[(j
+1)%4].IndexInZone
,
573 centerZonePatchs
[ptch
].BaseVertices
[j
],
574 centerZonePatchs
[ptch
].BaseVertices
[(j
+1)%4] );
575 fprintf(fdbg
,"center patch %d : %d %d %d %d\n\n",
577 centerZonePatchs
[ptch
].BaseVertices
[0],
578 centerZonePatchs
[ptch
].BaseVertices
[1],
579 centerZonePatchs
[ptch
].BaseVertices
[2],
580 centerZonePatchs
[ptch
].BaseVertices
[3]);
583 // Check the edge find is not binded
584 if (adjZonePatchs
[patchIndex
].BindEdges
[edgeIndex
].NPatchs
!=0)
586 // Build an error message
588 stringstream sserror
;
591 string nameCenter
, nameAdj
;
592 getZoneNameByCoord (centerZoneId
&0xff, (centerZoneId
>>8)+1, nameCenter
);
593 getZoneNameByCoord (adjZonesId
[i
]&0xff, (adjZonesId
[i
]>>8)+1, nameAdj
);
597 "Bind Error: try to bind the patch n %d in zone n %s with patch n %d in zone %s\n"
598 "This patch is already binded with the following patches : ", ptch
+1, nameAdj
.c_str(),
599 patchIndex
+1, nameCenter
.c_str() );
603 for (uint i
=0; i
<adjZonePatchs
[patchIndex
].BindEdges
[edgeIndex
].NPatchs
; i
++)
606 bool last
=(i
==(uint
)(adjZonePatchs
[patchIndex
].BindEdges
[edgeIndex
].NPatchs
-1));
610 "patch n %d%s", adjZonePatchs
[patchIndex
].BindEdges
[edgeIndex
].Next
[i
]+1, last
?"\n":",");
612 // Concat the message
616 // Add an error message
617 errorMessage
.push_back(sserror
.str());
623 (isTheSame (centerZonePatchs
[ptch
].Patch
.Vertices
[j
], NL_DEBUG_WELD_V0
) ||
624 isTheSame (centerZonePatchs
[ptch
].Patch
.Vertices
[(j
+1)%4], NL_DEBUG_WELD_V0
) ) &&
625 (isTheSame (centerZonePatchs
[ptch
].Patch
.Vertices
[j
], NL_DEBUG_WELD_V1
) ||
626 isTheSame (centerZonePatchs
[ptch
].Patch
.Vertices
[(j
+1)%4], NL_DEBUG_WELD_V1
) )
629 #endif // NL_DEBUG_WELD
630 centerZonePatchs
[ptch
].BindEdges
[j
].NPatchs
= 1;
631 centerZonePatchs
[ptch
].BindEdges
[j
].ZoneId
= adjZonesId
[i
];
632 centerZonePatchs
[ptch
].BindEdges
[j
].Next
[0] = patchIndex
;
633 centerZonePatchs
[ptch
].BindEdges
[j
].Edge
[0] = edgeIndex
;
635 // adjacent zone edge
636 adjZonePatchs
[patchIndex
].BindEdges
[edgeIndex
].NPatchs
= 1;
637 adjZonePatchs
[patchIndex
].BindEdges
[edgeIndex
].ZoneId
= centerZoneId
;
638 adjZonePatchs
[patchIndex
].BindEdges
[edgeIndex
].Next
[0] = ptch
;
639 adjZonePatchs
[patchIndex
].BindEdges
[edgeIndex
].Edge
[0] = j
;
641 // force the same smooth flag
642 bool smoothFlag
= centerZonePatchs
[ptch
].getSmoothFlag (j
);
643 smoothFlag
&= adjZonePatchs
[patchIndex
].getSmoothFlag (edgeIndex
);
644 centerZonePatchs
[ptch
].setSmoothFlag (j
, smoothFlag
);
645 adjZonePatchs
[patchIndex
].setSmoothFlag (edgeIndex
, smoothFlag
);
647 // tangent become the mean or both tangents (adj and center)
648 // Here we cross the mean because adjacent edges are counter-oriented
649 // due to the patchs constant orientation.
650 CVector middle0
= (centerZonePatchs
[ptch
].Patch
.Tangents
[2*j
]+
651 adjZonePatchs
[patchIndex
].Patch
.Tangents
[2*edgeIndex
+1])/2;
652 CVector middle1
= (centerZonePatchs
[ptch
].Patch
.Tangents
[2*j
+1]+
653 adjZonePatchs
[patchIndex
].Patch
.Tangents
[2*edgeIndex
])/2;
655 centerZonePatchs
[ptch
].Patch
.Tangents
[2*j
] =
656 adjZonePatchs
[patchIndex
].Patch
.Tangents
[2*edgeIndex
+1] = middle0
;
658 centerZonePatchs
[ptch
].Patch
.Tangents
[2*j
+1] =
659 adjZonePatchs
[patchIndex
].Patch
.Tangents
[2*edgeIndex
] = middle1
;
668 // Yoyo: compute the mean on vertices beetween zones.
669 //====================================
670 // do it before "make coplanar beetween zones", because CZoneTgtSmoother use tangents and vertices to smooth.
672 // build all input vertices for center and adjacents zones
675 // For center zone rebuild vertices.
676 vector
<CVector
> centerVertices
;
677 // for all patch, fill the array of vertices.
678 for(ptch
=0; ptch
<centerZonePatchs
.size(); ptch
++)
680 CPatchInfo
&pa
= centerZonePatchs
[ptch
];
681 for(uint corner
= 0; corner
<4; corner
++)
683 uint idVert
= pa
.BaseVertices
[corner
];
685 // write this vertex in array.
686 centerVertices
.resize( max((uint
)centerVertices
.size(), idVert
+1) );
687 centerVertices
[idVert
]= pa
.Patch
.Vertices
[corner
];
691 // For all adjacent zone rebuild vertices.
692 map
<uint16
, vector
<CAdjacentVertex
> > adjVertices
;
695 if(adjZonesName
[i
]=="empty") continue;
696 if(!adjZoneFileFound
[i
]) continue;
698 // create the entry in the map.
699 vector
<CAdjacentVertex
> &verts
= adjVertices
[adjZonesId
[i
]];
701 // for all patch, fill the array of vertices.
702 std::vector
<CPatchInfo
> &adjZonePatchs
= adjZoneInfos
[i
].Patchs
;
703 for(ptch
=0; ptch
<adjZonePatchs
.size(); ptch
++)
705 CPatchInfo
&pa
= adjZonePatchs
[ptch
];
706 for(uint corner
= 0; corner
<4; corner
++)
708 uint idVert
= pa
.BaseVertices
[corner
];
710 // write this vertex in array.
711 verts
.resize( max((uint
)verts
.size(), idVert
+1) );
712 verts
[idVert
].Vertex
= pa
.Patch
.Vertices
[corner
];
713 verts
[idVert
].OnBorder
= false;
717 // for all borderVertices with centerZoneId, fill verts neighbor info.
718 std::vector
<CBorderVertex
> &adjZoneBorderVertices
= adjZoneInfos
[i
].BorderVertices
;
720 for(bv
=0; bv
<adjZoneBorderVertices
.size(); bv
++)
722 CBorderVertex
&adjBV
= adjZoneBorderVertices
[bv
];
723 if(adjBV
.NeighborZoneId
== centerZoneId
)
725 verts
[adjBV
.CurrentVertex
].OnBorder
= true;
726 verts
[adjBV
.CurrentVertex
].IdOnCenterZone
= adjBV
.NeighborVertex
;
732 // compute the mean on border vertices
736 // create / reset the result vertices.
737 vector
<CVectorInfluence
> outVertices
;
738 outVertices
.resize(centerVertices
.size());
739 for(i
=0; i
<outVertices
.size(); i
++)
741 outVertices
[i
].Vertex
= centerVertices
[i
];
742 outVertices
[i
].Inf
= 1;
743 outVertices
[i
].OnBorder
= false;
747 // For all borderVertices of centerZone, choose the good vertex, add neighbor influence
749 for(bv
=0; bv
<centerZoneBorderVertices
.size(); bv
++)
751 CBorderVertex
¢erBV
= centerZoneBorderVertices
[bv
];
752 uint centerVert
= centerBV
.CurrentVertex
;
753 if( adjVertices
.find(centerBV
.NeighborZoneId
) != adjVertices
.end() )
755 outVertices
[centerVert
].Vertex
+= adjVertices
[centerBV
.NeighborZoneId
][centerBV
.NeighborVertex
].Vertex
;
756 outVertices
[centerVert
].Inf
++;
757 outVertices
[centerVert
].OnBorder
= true;
760 // normalize influence.
761 for(i
=0; i
<outVertices
.size(); i
++)
763 if(outVertices
[i
].Inf
!=1)
765 outVertices
[i
].Vertex
/= outVertices
[i
].Inf
;
766 outVertices
[i
].Inf
= 1;
771 // for all zones, get the new vertices.
774 // For center zone, for all patchs, copy from outVertices.
775 for(ptch
=0; ptch
<centerZonePatchs
.size(); ptch
++)
777 CPatchInfo
&pa
= centerZonePatchs
[ptch
];
778 for(uint corner
= 0; corner
<4; corner
++)
780 uint idVert
= pa
.BaseVertices
[corner
];
782 if(outVertices
[idVert
].OnBorder
)
785 pa
.Patch
.Vertices
[corner
]= outVertices
[idVert
].Vertex
;
791 // For all borderVertices of adjacentZone, copy from outVertices.
794 if(adjZonesName
[i
]=="empty") continue;
795 if(!adjZoneFileFound
[i
]) continue;
797 // get the entry in the map.
798 vector
<CAdjacentVertex
> &verts
= adjVertices
[adjZonesId
[i
]];
800 // for all patch, get vertices which are n Border of the cetnerZone.
801 std::vector
<CPatchInfo
> &adjZonePatchs
= adjZoneInfos
[i
].Patchs
;
802 for(ptch
=0; ptch
<adjZonePatchs
.size(); ptch
++)
804 CPatchInfo
&pa
= adjZonePatchs
[ptch
];
805 for(uint corner
= 0; corner
<4; corner
++)
807 uint idVert
= pa
.BaseVertices
[corner
];
809 if(verts
[idVert
].OnBorder
)
811 pa
.Patch
.Vertices
[corner
]= outVertices
[verts
[idVert
].IdOnCenterZone
].Vertex
;
822 // Yoyo: make coplanar beetween zones.
823 //====================================
825 std::vector
<CZoneInfo
> zones
;
829 zinf
.ZoneId
= centerZoneId
;
830 zinf
.Patchs
= centerZonePatchs
;
831 zinf
.BorderVertices
= centerZoneBorderVertices
;
832 zones
.push_back(zinf
);
837 if(adjZonesName
[i
]=="empty") continue;
838 if(!adjZoneFileFound
[i
]) continue;
839 zones
.push_back(adjZoneInfos
[i
]);
842 CZoneTgtSmoother tgtsmoother
;
843 tgtsmoother
.makeVerticesCoplanar(zones
);
845 // retrieve center zone result.
846 centerZonePatchs
= zones
[0].Patchs
;
847 centerZoneBorderVertices
= zones
[0].BorderVertices
;
849 // retrieve adj zone result.
853 if(adjZonesName
[i
]=="empty") continue;
854 if(!adjZoneFileFound
[i
]) continue;
856 adjZoneInfos
[i
]= zones
[numZone
];
862 // Yoyo: compute corner smooth info.
863 //====================================
864 // CANNOT DO IT HERE, BECAUSE THE CURRENT ZONE MAY NOT BE CORRECLTY WELDED.
865 // MUST DO IT IN ZONE_LIGHTER.
867 // build a landscape, because CZoneCornerSmooth use compiled zones.
869 CZoneCornerSmoother zcs;
874 zone.build(centerZoneId, centerZonePatchs, centerZoneBorderVertices);
876 CZone *centerZone= land.getZone(centerZoneId);
878 // add adjacent zones.
879 vector<CZone*> nbZones;
882 if(adjZonesName[i]=="empty") continue;
883 if(!adjZoneFileFound[i]) continue;
885 std::vector<CPatchInfo> &adjZonePatchs= adjZoneInfos[i].Patchs;
886 std::vector<CBorderVertex> &adjZoneBorderVertices= adjZoneInfos[i].BorderVertices;
888 adjZones[i].build(adjZonesId[i], adjZonePatchs, adjZoneBorderVertices);
889 land.addZone(adjZones[i]);
891 CZone *nbZone= land.getZone(adjZonesId[i]);
893 nbZones.push_back(nbZone);
896 // now, do the zoneCornerSmoother.
900 zcs.computeAllCornerSmoothFlags(centerZone, nbZones);
902 // get result from the compiled zone, and copy in the uncompiled one (ie in centerZonePatchs).
903 for(i=0;i<centerZonePatchs.size();i++)
905 const CPatch &paSrc= *((const CZone*)centerZone)->getPatch(i);
906 CPatchInfo &paDst= centerZonePatchs[i];
907 for(uint corner=0; corner<4; corner++)
908 paDst.setCornerSmoothFlag(corner, paSrc.getCornerSmoothFlag(corner));
914 if (errorMessage
.empty())
916 // Save adjacent zones.
917 //=====================
920 if(adjZonesName
[i
]=="empty") continue;
921 if(!adjZoneFileFound
[i
]) continue;
923 std::vector
<CPatchInfo
> &adjZonePatchs
= adjZoneInfos
[i
].Patchs
;
924 std::vector
<CBorderVertex
> &adjZoneBorderVertices
= adjZoneInfos
[i
].BorderVertices
;
926 adjZones
[i
].build(adjZonesId
[i
], adjZonePatchs
, adjZoneBorderVertices
);
928 fprintf(fdbg
,"[%d] binds :\n", i
);
929 adjZones
[i
].debugBinds(fdbg
);
933 //strtmp = outputPath;
934 strtmp
= outputDir
+adjZonesName
[i
]+outputExt
;
935 COFile
adjSave(strtmp
);
936 printf("writing file %s\n",strtmp
.c_str());
937 adjZones
[i
].serial(adjSave
);
943 zone
.build(centerZoneId
, centerZonePatchs
, centerZoneBorderVertices
);
945 strtmp
= outputDir
+center
+outputExt
;
947 COFile
centerSave(strtmp
);
948 printf("writing file %s\n",strtmp
.c_str());
949 zone
.serial(centerSave
);
954 nlwarning ("ERROR weld failed. Correct errors below: (indices are MAX indices (+1))\n");
957 for (uint i
=0; i
<errorMessage
.size(); i
++)
960 nlwarning ("%s", errorMessage
[i
].c_str());
968 /*******************************************************************\
970 \*******************************************************************/
971 int main(sint argc
, char **argv
)
973 // no zone file in argument
981 if(strcmp(argv
[1],"/?")==0)
988 fdbg
= nlfopen("log.txt","wt");
989 fprintf(fdbg
,"Center zone : %s\n",argv
[1]);
992 printf("Center zone : %s\n",argv
[1]);
994 inputDir
= getDir (argv
[1]);
995 inputExt
= getExt (argv
[1]);
996 outputDir
= getDir (argv
[2]);
997 outputExt
= getExt (argv
[2]);
1001 NLMISC::fromString(argv
[3], weldRadius
);
1004 std::string center
=getName(argv
[1]).c_str();
1005 weldZones(center
.c_str());