khanat-code-old/code/nel/tools/3d/zone_welder/zone_welder.cpp
2016-12-09 16:04:26 +01:00

1009 lines
28 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "../zone_lib/zone_utility.h"
#include <iostream>
#include "nel/misc/types_nl.h"
#include "nel/misc/file.h"
#include "nel/misc/common.h"
#include "nel/3d/quad_tree.h"
#include "nel/3d/zone.h"
#include "nel/3d/landscape.h"
#include "nel/3d/zone_smoother.h"
#include "nel/3d/zone_tgt_smoother.h"
#include "nel/3d/zone_corner_smoother.h"
#include <vector>
#include <set>
using namespace NL3D;
using namespace NLMISC;
using namespace std;
#define WELD_LOG 1
FILE *fdbg;
std::string inputDir;
std::string inputExt;
std::string outputDir;
std::string outputExt;
float weldRadius = 1.1f;
/* Zone ID
0 1 2
3 4
5 6 7
*/
// Define this to stop the welder on a source edge
// #define NL_DEBUG_WELD
#define NL_DEBUG_WELD_V0 (CVector(16320,-24064,0))
#define NL_DEBUG_WELD_V1 (CVector(16352,-24065,0))
#define NL_DEBUG_WELD_THRESHOLD 1.f
#ifdef NL_DEBUG_WELD
bool isTheSame (const CVector &v0, const CVector &v1)
{
CVector delta = v0 - v1;
delta.z = 0;
return delta.norm() < NL_DEBUG_WELD_THRESHOLD;
}
#endif // NL_DEBUG_WELD
/**
* CWeldableVertexInfos
*/
struct CWeldableVertexInfos
{
uint16 IndexInZone; // base vertex
sint PatchIndex; // patch
uint8 PatchVertex; // 0,1,2,3
CWeldableVertexInfos()
{
IndexInZone = 0;
PatchIndex = 0;
PatchVertex = 0;
}
bool operator< (const CWeldableVertexInfos& wvinf) const
{
if(IndexInZone<wvinf.IndexInZone)
return true;
if(IndexInZone>wvinf.IndexInZone)
return false;
if(PatchIndex<wvinf.PatchIndex)
return true;
if(PatchIndex>wvinf.PatchIndex)
return false;
return PatchVertex<wvinf.PatchVertex;
}
};
struct CVectorInfluence
{
CVector Vertex;
float Inf;
bool OnBorder;
};
struct CAdjacentVertex
{
CVector Vertex;
uint IdOnCenterZone;
bool OnBorder;
};
/*******************************************************************\
writeInstructions()
\*******************************************************************/
void writeInstructions()
{
printf("zone_welder <input.zone><output.zone>[<weld threshold>]\n");
printf("\t/? for this help\n");
}
/*******************************************************************\
findPatchIndex()
\*******************************************************************/
bool getPatchAndEdge(const std::vector<CPatchInfo>& patchs,
uint16 baseVertex1, uint16 baseVertex2,
uint16& patchIndex,
uint8& edgeIndex)
{
uint ptch;
for(ptch=0; ptch<patchs.size(); ptch++)
{
uint i;
for(i=0; i<4; i++)
{
if(patchs[ptch].BaseVertices[i] == baseVertex1)
{
#if WELD_LOG
fprintf(fdbg,"patch %d continent bv %d : %d %d %d %d\n",
ptch,
baseVertex1,
patchs[ptch].BaseVertices[0],
patchs[ptch].BaseVertices[1],
patchs[ptch].BaseVertices[2],
patchs[ptch].BaseVertices[3]);
#endif
if(patchs[ptch].BaseVertices[(i+1)%4] == baseVertex2)
{
edgeIndex = i;
patchIndex = ptch;
return true;
}
if(patchs[ptch].BaseVertices[(i-1)%4] == baseVertex2)
{
edgeIndex = (i-1)%4;
patchIndex = ptch;
return true;
}
}
}
}
return false;
}
void CleanZone ( std::vector<CPatchInfo> &zoneInfos, uint zoneId, const CAABBoxExt &zoneBBox, float weldThreshold);
/*******************************************************************\
weldZones()
\*******************************************************************/
void weldZones(const char *center)
{
uint i,j;
// load zone in the center
CIFile zoneFile(inputDir+center+inputExt);
CZone zone;
zone.serial(zoneFile);
zoneFile.close();
// retrieving infos from the center zone
uint16 centerZoneId = zone.getZoneId();
std::vector<CPatchInfo> centerZonePatchs;
std::vector<CBorderVertex> centerZoneBorderVertices;
zone.retrieve(centerZonePatchs, centerZoneBorderVertices);
std::vector<CPatchInfo>::iterator itptch;
std::vector<CBorderVertex>::iterator itbv;
// if no id yet, we add a correct id
if(centerZoneId==0)
{
centerZoneId = createZoneId(center);
// edge neighbour : current zone
for(itptch = centerZonePatchs.begin(); itptch!=centerZonePatchs.end(); itptch++)
{
for(j=0; j<4; j++)
{
(*itptch).BindEdges[j].ZoneId = centerZoneId;
}
}
// border vertices neighbour : current zone
for(itbv = centerZoneBorderVertices.begin(); itbv<centerZoneBorderVertices.end(); itbv++)
{
(*itbv).NeighborZoneId = centerZoneId;
}
}
#if WELD_LOG
fprintf(fdbg,"id(center) = %d\n",centerZoneId);
#endif
// *** Clean internal zone
// * Bind 1-1 1-2 1-4 internal patches that are not binded
// * Make a global welded on vertices
// * Force tangents position
CleanZone ( centerZonePatchs, centerZoneId, zone.getZoneBB(), weldRadius);
// Yoyo was here: Smooth the tangents of the zone.
//================================================
// NB: do it only for edges sharing 2 patchs of centerZone. (don't care adjacent zones).
// smoothing with adjacent zones is done with a better smoothing tool: CZoneTgtSmoother, see below,
// after the weld of the zone.
{
CZoneSmoother zonesmoother;
CZoneSmoother::CZoneInfo smoothZones[5];
smoothZones[0].ZoneId= centerZoneId;
smoothZones[0].Patchs= &centerZonePatchs;
// 30deg ???
zonesmoother.smoothTangents(smoothZones, (float)(Pi/6));
}
// load 8 adjacent adjZones
bool adjZoneFileFound[8];
CZone adjZones[8];
CZoneInfo adjZoneInfos[8];
uint16 adjZonesId[8];
std::vector<std::string> adjZonesName;
getAdjacentZonesName(center, adjZonesName);
for(i=0; i<8; i++)
{
if(adjZonesName[i]=="empty") continue;
adjZoneFileFound[i] = true;
CIFile f;
try
{
std::string ss(outputDir+adjZonesName[i]+outputExt);
if (f.open(ss))
{
printf("reading file %s\n", ss.c_str());
adjZones[i].serial(f);
adjZones[i].retrieve(adjZoneInfos[i].Patchs, adjZoneInfos[i].BorderVertices);
adjZoneInfos[i].ZoneId= adjZonesId[i] = adjZones[i].getZoneId();
f.close();
}
else
{
// nlwarning ("WARNING File not found: %s\n", ss.c_str());
adjZonesName[i]="empty";
}
}
catch(const exception &e)
{
nlwarning ("ERROR %s\n", e.what ());
adjZoneFileFound[i] = false;
}
}
// QuadTree for storing adjZones points
CQuadTree<CWeldableVertexInfos> quadTrees[8];
// new base, to change from XZ to XY (Nel speaking)
CMatrix base;
CVector I(1,0,0);
CVector J(0,0,-1);
CVector K(0,1,0);
base.setRot(I,J,K, true);
uint ptch;
uint16 weldCount = 0;
// Error messages
vector<string> errorMessage;
for(i=0; i<8; i++)
{
if(adjZonesName[i]=="empty") continue;
if(!adjZoneFileFound[i]) continue;
// setting quad tree
uint qTreeDepth = 5;
CAABBoxExt bb = adjZones[i].getZoneBB();
quadTrees[i].create (5, bb.getCenter(), 2*bb.getRadius());
quadTrees[i].changeBase(base);
// retrieving infos from the current adjacent zone
std::vector<CPatchInfo> &adjZonePatchs= adjZoneInfos[i].Patchs;
std::vector<CBorderVertex> &adjZoneBorderVertices= adjZoneInfos[i].BorderVertices;
// if no id yet, we add a correct id
nlassert(adjZonesId[i]!=0);
if(adjZonesId[i]==0)
{
adjZonesId[i] = createZoneId(getName (adjZonesName[i]));
adjZoneInfos[i].ZoneId= adjZonesId[i];
// edge neighbour : current zone
for(itptch = adjZonePatchs.begin(); itptch!=adjZonePatchs.end(); itptch++)
{
for(j=0; j<4; j++)
{
(*itptch).BindEdges[j].ZoneId = adjZonesId[i];
}
}
// border vertices neighbour : current zone
for(itbv = adjZoneBorderVertices.begin(); itbv!=adjZoneBorderVertices.end(); itbv++)
{
(*itbv).NeighborZoneId = adjZonesId[i];
}
}
#if WELD_LOG
fprintf(fdbg,"------------------------------------------\n");
fprintf(fdbg,"id(%d) = %d\n",i,adjZonesId[i]);
#endif
// an edge of current adjacent patch with neighbour zoneId==center zoneId is
// set to no neighbour.
for(ptch = 0; ptch<adjZonePatchs.size(); ptch++)
{
for(j=0; j<4; j++)
{
if(adjZonePatchs[ptch].BindEdges[j].ZoneId == centerZoneId)
{
adjZonePatchs[ptch].BindEdges[j].NPatchs = 0;
}
}
}
fprintf(fdbg,"(before) zone %u bordervertices size : %u\n",i,(uint)adjZoneBorderVertices.size());
// delete border vertices of the adjacent zone if their neighbour zoneId
// is equal to current zone zoneId
std::vector<CBorderVertex>::iterator itborder = adjZoneBorderVertices.begin();
while(itborder != adjZoneBorderVertices.end())
{
if((*itborder).NeighborZoneId == centerZoneId)
{
itborder = adjZoneBorderVertices.erase(itborder);
}
else
itborder++;
}
fprintf(fdbg,"(after) zone %u bordervertices size : %u\n",i,(uint)adjZoneBorderVertices.size());
// A set for storing base vertex index already added in the quad tree
std::set<uint16> adjBaseVertexIndexSet;
// if point in adjacent zone is not in the set :
// -> add it in the set
// -> add it in the quad
for(ptch = 0; ptch<adjZonePatchs.size(); ptch++)
{
for(j=0; j<4; j++)
{
CWeldableVertexInfos wvinf;
wvinf.IndexInZone = adjZonePatchs[ptch].BaseVertices[j]; // useful ????
wvinf.PatchIndex = ptch;
wvinf.PatchVertex = j;
if(adjBaseVertexIndexSet.find(wvinf.IndexInZone) == adjBaseVertexIndexSet.end())
{
adjBaseVertexIndexSet.insert(wvinf.IndexInZone);
CVector bboxmin;
CVector bboxmax;
bboxmin.x = adjZonePatchs[ptch].Patch.Vertices[j].x;
bboxmin.y = adjZonePatchs[ptch].Patch.Vertices[j].y;
bboxmin.z = adjZonePatchs[ptch].Patch.Vertices[j].z;
bboxmax = bboxmin;
quadTrees[i].insert(bboxmin,bboxmax,wvinf);
}
}
}
quadTrees[i].clearSelection();
float bboxRadius = 10; //TEMP !!
std::set<uint16> centerBaseVertexIndexSet;
std::set<uint16> currentAdjBaseVertexIndexSet;
for(ptch=0; ptch<centerZonePatchs.size(); ptch++) // for all patchs in center zone
{
// stores infos for edge part
CWeldableVertexInfos nearVertexInfos[4];
bool toWeld[4];
CVector bboxmin;
CVector bboxmax;
// for every points in center patch we look for close points in adjacent patch
for(j=0; j<4; j++) // 4 patch vertices (in center zone)
{
toWeld[j] = false;
// already 'checked for welding' vertices are stored in a set
centerBaseVertexIndexSet.insert(centerZonePatchs[ptch].BaseVertices[j]);
//fprintf(fdbg,"%d - %d) CZBV(%d)\n",i,baseVertexIndexSet.size(),centerZonePatchs[ptch].BaseVertices[j]);
bboxmin.x = centerZonePatchs[ptch].Patch.Vertices[j].x - bboxRadius;
bboxmin.y = centerZonePatchs[ptch].Patch.Vertices[j].y - bboxRadius;
bboxmin.z = centerZonePatchs[ptch].Patch.Vertices[j].z - bboxRadius;
bboxmax.x = centerZonePatchs[ptch].Patch.Vertices[j].x + bboxRadius;
bboxmax.y = centerZonePatchs[ptch].Patch.Vertices[j].y + bboxRadius;
bboxmax.z = centerZonePatchs[ptch].Patch.Vertices[j].z + bboxRadius;
//quadTrees[i].select(bboxmin,bboxmax);
quadTrees[i].selectAll(); // TEMP !!!
// current vertex coordinates in center zone
CVector vctr;
vctr.x = centerZonePatchs[ptch].Patch.Vertices[j].x;
vctr.y = centerZonePatchs[ptch].Patch.Vertices[j].y;
vctr.z = centerZonePatchs[ptch].Patch.Vertices[j].z;
CWeldableVertexInfos wvinf;
float minDistance = weldRadius + 1; // rq: we weld only if we found a distance
// inferior to weldRadius
CQuadTree<CWeldableVertexInfos>::CIterator itqdt = quadTrees[i].begin();
// for all points near of current vertex in adjacent zone..
while (itqdt != quadTrees[i].end())
{
CVector vadj;
vadj.x = adjZonePatchs[(*itqdt).PatchIndex].Patch.Vertices[(*itqdt).PatchVertex].x;
vadj.y = adjZonePatchs[(*itqdt).PatchIndex].Patch.Vertices[(*itqdt).PatchVertex].y;
vadj.z = adjZonePatchs[(*itqdt).PatchIndex].Patch.Vertices[(*itqdt).PatchVertex].z;
CVector adjToCenter;
adjToCenter.x = vctr.x - vadj.x;
adjToCenter.y = vctr.y - vadj.y;
adjToCenter.z = vctr.z - vadj.z;
float dist = adjToCenter.norm();
// if dist min we keep infos on this vertex(adj zone)
// we keep the closest.
if(dist<weldRadius && dist<minDistance)
{
#ifdef NL_DEBUG_WELD
nlverify (!isTheSame (centerZonePatchs[ptch].Patch.Vertices[j], NL_DEBUG_WELD_V0));
nlverify (!isTheSame (centerZonePatchs[ptch].Patch.Vertices[j], NL_DEBUG_WELD_V1));
#endif // NL_DEBUG_WELD
minDistance = dist;
wvinf = (*itqdt);
}
itqdt++;
}
quadTrees[i].clearSelection();
if(minDistance<weldRadius) // i.e if we have found 2 vertices to weld
{
// we save CBorderVertex info, and add it into the adjacent zone
CBorderVertex adjBorderV;
adjBorderV.CurrentVertex = wvinf.IndexInZone;
adjBorderV.NeighborZoneId = centerZoneId;
adjBorderV.NeighborVertex = centerZonePatchs[ptch].BaseVertices[j];
nearVertexInfos[j] = wvinf;
// we save CBorderVertex info, and add it into the center zone
CBorderVertex centerBorderV;
centerBorderV.CurrentVertex = centerZonePatchs[ptch].BaseVertices[j];
centerBorderV.NeighborZoneId = adjZonesId[i];
centerBorderV.NeighborVertex = wvinf.IndexInZone;
toWeld[j] = true;
if(centerBaseVertexIndexSet.find(centerZonePatchs[ptch].BaseVertices[j]) != centerBaseVertexIndexSet.end())
{
if(currentAdjBaseVertexIndexSet.find(wvinf.IndexInZone) == currentAdjBaseVertexIndexSet.end())
{
currentAdjBaseVertexIndexSet.insert(wvinf.IndexInZone);
adjZoneBorderVertices.push_back(adjBorderV);
centerZoneBorderVertices.push_back(centerBorderV);
weldCount++;
#if WELD_LOG
fprintf(fdbg,"%d) weld vertices : zone%d.(patch%d.vertex%d).baseVertex%d to centerZone.(patch%d.vertex%d).baseVertex%d\n",
weldCount,i,wvinf.PatchIndex,wvinf.PatchVertex,wvinf.IndexInZone,ptch,j,centerZonePatchs[ptch].BaseVertices[j]);
#endif
}
}
}
}
// then we bind edges (made of weldable vertices) and modify tangents
for(j=0; j<4; j++)
{
#ifdef NL_DEBUG_WELD
if (
(isTheSame (centerZonePatchs[ptch].Patch.Vertices[j], NL_DEBUG_WELD_V0) ||
isTheSame (centerZonePatchs[ptch].Patch.Vertices[(j+1)%4], NL_DEBUG_WELD_V0) ) &&
(isTheSame (centerZonePatchs[ptch].Patch.Vertices[j], NL_DEBUG_WELD_V1) ||
isTheSame (centerZonePatchs[ptch].Patch.Vertices[(j+1)%4], NL_DEBUG_WELD_V1) )
)
nlstop;
#endif // NL_DEBUG_WELD
// if vertex has been welded...
if(toWeld[j] == false) continue;
// ...we look if next vertex(i.e if the edge) in center zone has to be welded
if(toWeld[(j+1)%4] == false) continue;
// We know the two adjacent base vertices
// we look for the adjacent patch and the edge containing these vertices
uint8 edgeIndex;
uint16 patchIndex;
if(! getPatchAndEdge(adjZonePatchs,
nearVertexInfos[j].IndexInZone,
nearVertexInfos[(j+1)%4].IndexInZone,
patchIndex,
edgeIndex))
{
#if WELD_LOG
fprintf(fdbg,"* Error * : Can't find patch containing the following edge : %d - %d\n",
nearVertexInfos[j].IndexInZone,
nearVertexInfos[(j+1)%4].IndexInZone);
#endif
nlwarning ("ERROR : zone_welder : Can't find patch containing the following edge : %d - %d\n",
nearVertexInfos[j].IndexInZone,
nearVertexInfos[(j+1)%4].IndexInZone);
continue;
}
#if WELD_LOG
fprintf(fdbg,"weld edges : zone%d.patch%d.edge%d(%d-%d) to centerZone.patch%d.edge%d(%d-%d)\n",
i,
patchIndex,
edgeIndex,
nearVertexInfos[j].IndexInZone,
nearVertexInfos[(j+1)%4].IndexInZone,
ptch,
j,
centerZonePatchs[ptch].BaseVertices[j],
centerZonePatchs[ptch].BaseVertices[(j+1)%4] );
fprintf(fdbg,"center patch %d : %d %d %d %d\n\n",
ptch,
centerZonePatchs[ptch].BaseVertices[0],
centerZonePatchs[ptch].BaseVertices[1],
centerZonePatchs[ptch].BaseVertices[2],
centerZonePatchs[ptch].BaseVertices[3]);
#endif
// Check the edge find is not binded
if (adjZonePatchs[patchIndex].BindEdges[edgeIndex].NPatchs!=0)
{
// Build an error message
char error[8000];
// Zone name
string nameCenter, nameAdj;
getZoneNameByCoord (centerZoneId&0xff, (centerZoneId>>8)+1, nameCenter);
getZoneNameByCoord (adjZonesId[i]&0xff, (adjZonesId[i]>>8)+1, nameAdj);
// Main message
smprintf (error, 2048,
"Bind Error: try to bind the patch n %d in zone n %s with patch n %d in zone %s\n"
"This patch is already binded with the following patches : ", ptch+1, nameAdj.c_str(),
patchIndex+1, nameCenter.c_str() );
// Sub message
for (uint i=0; i<adjZonePatchs[patchIndex].BindEdges[edgeIndex].NPatchs; i++)
{
// Last patch ?
bool last=(i==(uint)(adjZonePatchs[patchIndex].BindEdges[edgeIndex].NPatchs-1));
// Sub message
char subMessage[512];
smprintf ( subMessage, 512,
"patch n %d%s", adjZonePatchs[patchIndex].BindEdges[edgeIndex].Next[i]+1, last?"\n":",");
// Concat the message
strcat (error, subMessage);
}
// Add an error message
errorMessage.push_back (error);
}
else
{
#ifdef NL_DEBUG_WELD
if (
(isTheSame (centerZonePatchs[ptch].Patch.Vertices[j], NL_DEBUG_WELD_V0) ||
isTheSame (centerZonePatchs[ptch].Patch.Vertices[(j+1)%4], NL_DEBUG_WELD_V0) ) &&
(isTheSame (centerZonePatchs[ptch].Patch.Vertices[j], NL_DEBUG_WELD_V1) ||
isTheSame (centerZonePatchs[ptch].Patch.Vertices[(j+1)%4], NL_DEBUG_WELD_V1) )
)
nlstop;
#endif // NL_DEBUG_WELD
centerZonePatchs[ptch].BindEdges[j].NPatchs = 1;
centerZonePatchs[ptch].BindEdges[j].ZoneId = adjZonesId[i];
centerZonePatchs[ptch].BindEdges[j].Next[0] = patchIndex;
centerZonePatchs[ptch].BindEdges[j].Edge[0] = edgeIndex;
// adjacent zone edge
adjZonePatchs[patchIndex].BindEdges[edgeIndex].NPatchs = 1;
adjZonePatchs[patchIndex].BindEdges[edgeIndex].ZoneId = centerZoneId;
adjZonePatchs[patchIndex].BindEdges[edgeIndex].Next[0] = ptch;
adjZonePatchs[patchIndex].BindEdges[edgeIndex].Edge[0] = j;
// force the same smooth flag
bool smoothFlag = centerZonePatchs[ptch].getSmoothFlag (j);
smoothFlag &= adjZonePatchs[patchIndex].getSmoothFlag (edgeIndex);
centerZonePatchs[ptch].setSmoothFlag (j, smoothFlag);
adjZonePatchs[patchIndex].setSmoothFlag (edgeIndex, smoothFlag);
// tangent become the mean or both tangents (adj and center)
// Here we cross the mean because adjacent edges are counter-oriented
// due to the patchs constant orientation.
CVector middle0= (centerZonePatchs[ptch].Patch.Tangents[2*j]+
adjZonePatchs[patchIndex].Patch.Tangents[2*edgeIndex+1])/2;
CVector middle1= (centerZonePatchs[ptch].Patch.Tangents[2*j+1]+
adjZonePatchs[patchIndex].Patch.Tangents[2*edgeIndex])/2;
centerZonePatchs[ptch].Patch.Tangents[2*j] =
adjZonePatchs[patchIndex].Patch.Tangents[2*edgeIndex+1] = middle0;
centerZonePatchs[ptch].Patch.Tangents[2*j+1] =
adjZonePatchs[patchIndex].Patch.Tangents[2*edgeIndex] = middle1;
}
}
}
}
// Yoyo: compute the mean on vertices beetween zones.
//====================================
// do it before "make coplanar beetween zones", because CZoneTgtSmoother use tangents and vertices to smooth.
{
// build all input vertices for center and adjacents zones
//------------------
// For center zone rebuild vertices.
vector<CVector> centerVertices;
// for all patch, fill the array of vertices.
for(ptch=0; ptch<centerZonePatchs.size(); ptch++)
{
CPatchInfo &pa= centerZonePatchs[ptch];
for(uint corner= 0; corner<4; corner++)
{
uint idVert= pa.BaseVertices[corner];
// write this vertex in array.
centerVertices.resize( max((uint)centerVertices.size(), idVert+1) );
centerVertices[idVert]= pa.Patch.Vertices[corner];
}
}
// For all adjacent zone rebuild vertices.
map<uint16, vector<CAdjacentVertex> > adjVertices;
for(i=0;i<8;i++)
{
if(adjZonesName[i]=="empty") continue;
if(!adjZoneFileFound[i]) continue;
// create the entry in the map.
vector<CAdjacentVertex> &verts= adjVertices[adjZonesId[i]];
// for all patch, fill the array of vertices.
std::vector<CPatchInfo> &adjZonePatchs= adjZoneInfos[i].Patchs;
for(ptch=0; ptch<adjZonePatchs.size(); ptch++)
{
CPatchInfo &pa= adjZonePatchs[ptch];
for(uint corner= 0; corner<4; corner++)
{
uint idVert= pa.BaseVertices[corner];
// write this vertex in array.
verts.resize( max((uint)verts.size(), idVert+1) );
verts[idVert].Vertex= pa.Patch.Vertices[corner];
verts[idVert].OnBorder= false;
}
}
// for all borderVertices with centerZoneId, fill verts neighbor info.
std::vector<CBorderVertex> &adjZoneBorderVertices= adjZoneInfos[i].BorderVertices;
uint bv;
for(bv=0; bv<adjZoneBorderVertices.size(); bv++)
{
CBorderVertex &adjBV= adjZoneBorderVertices[bv];
if(adjBV.NeighborZoneId == centerZoneId)
{
verts[adjBV.CurrentVertex].OnBorder= true;
verts[adjBV.CurrentVertex].IdOnCenterZone= adjBV.NeighborVertex;
}
}
}
// compute the mean on border vertices
//------------------
// create / reset the result vertices.
vector<CVectorInfluence> outVertices;
outVertices.resize(centerVertices.size());
for(i=0; i<outVertices.size(); i++)
{
outVertices[i].Vertex= centerVertices[i];
outVertices[i].Inf= 1;
outVertices[i].OnBorder= false;
}
// For all borderVertices of centerZone, choose the good vertex, add neighbor influence
uint bv;
for(bv=0; bv<centerZoneBorderVertices.size(); bv++)
{
CBorderVertex &centerBV= centerZoneBorderVertices[bv];
uint centerVert= centerBV.CurrentVertex;
if( adjVertices.find(centerBV.NeighborZoneId) != adjVertices.end() )
{
outVertices[centerVert].Vertex+= adjVertices[centerBV.NeighborZoneId][centerBV.NeighborVertex].Vertex;
outVertices[centerVert].Inf++;
outVertices[centerVert].OnBorder= true;
}
}
// normalize influence.
for(i=0; i<outVertices.size(); i++)
{
if(outVertices[i].Inf!=1)
{
outVertices[i].Vertex/= outVertices[i].Inf;
outVertices[i].Inf= 1;
}
}
// for all zones, get the new vertices.
//------------------
// For center zone, for all patchs, copy from outVertices.
for(ptch=0; ptch<centerZonePatchs.size(); ptch++)
{
CPatchInfo &pa= centerZonePatchs[ptch];
for(uint corner= 0; corner<4; corner++)
{
uint idVert= pa.BaseVertices[corner];
if(outVertices[idVert].OnBorder)
{
// copy the vertex.
pa.Patch.Vertices[corner]= outVertices[idVert].Vertex;
}
}
}
// For all borderVertices of adjacentZone, copy from outVertices.
for(i=0;i<8;i++)
{
if(adjZonesName[i]=="empty") continue;
if(!adjZoneFileFound[i]) continue;
// get the entry in the map.
vector<CAdjacentVertex> &verts= adjVertices[adjZonesId[i]];
// for all patch, get vertices which are n Border of the cetnerZone.
std::vector<CPatchInfo> &adjZonePatchs= adjZoneInfos[i].Patchs;
for(ptch=0; ptch<adjZonePatchs.size(); ptch++)
{
CPatchInfo &pa= adjZonePatchs[ptch];
for(uint corner= 0; corner<4; corner++)
{
uint idVert= pa.BaseVertices[corner];
if(verts[idVert].OnBorder)
{
pa.Patch.Vertices[corner]= outVertices[verts[idVert].IdOnCenterZone].Vertex;
}
}
}
}
}
// Yoyo: make coplanar beetween zones.
//====================================
{
std::vector<CZoneInfo> zones;
CZoneInfo zinf;
// center.
zinf.ZoneId= centerZoneId;
zinf.Patchs= centerZonePatchs;
zinf.BorderVertices= centerZoneBorderVertices;
zones.push_back(zinf);
// adjs.
for(i=0;i<8;i++)
{
if(adjZonesName[i]=="empty") continue;
if(!adjZoneFileFound[i]) continue;
zones.push_back(adjZoneInfos[i]);
}
CZoneTgtSmoother tgtsmoother;
tgtsmoother.makeVerticesCoplanar(zones);
// retrieve center zone result.
centerZonePatchs= zones[0].Patchs;
centerZoneBorderVertices= zones[0].BorderVertices;
// retrieve adj zone result.
sint numZone= 1;
for(i=0;i<8;i++)
{
if(adjZonesName[i]=="empty") continue;
if(!adjZoneFileFound[i]) continue;
adjZoneInfos[i]= zones[numZone];
numZone++;
}
}
// Yoyo: compute corner smooth info.
//====================================
// CANNOT DO IT HERE, BECAUSE THE CURRENT ZONE MAY NOT BE CORRECLTY WELDED.
// MUST DO IT IN ZONE_LIGHTER.
/*{
// build a landscape, because CZoneCornerSmooth use compiled zones.
CLandscape land;
CZoneCornerSmoother zcs;
land.init();
// add center zone.
zone.build(centerZoneId, centerZonePatchs, centerZoneBorderVertices);
land.addZone(zone);
CZone *centerZone= land.getZone(centerZoneId);
// add adjacent zones.
vector<CZone*> nbZones;
for(i=0;i<8;i++)
{
if(adjZonesName[i]=="empty") continue;
if(!adjZoneFileFound[i]) continue;
std::vector<CPatchInfo> &adjZonePatchs= adjZoneInfos[i].Patchs;
std::vector<CBorderVertex> &adjZoneBorderVertices= adjZoneInfos[i].BorderVertices;
adjZones[i].build(adjZonesId[i], adjZonePatchs, adjZoneBorderVertices);
land.addZone(adjZones[i]);
CZone *nbZone= land.getZone(adjZonesId[i]);
if(nbZone)
nbZones.push_back(nbZone);
}
// now, do the zoneCornerSmoother.
if(centerZone)
{
// go.
zcs.computeAllCornerSmoothFlags(centerZone, nbZones);
// get result from the compiled zone, and copy in the uncompiled one (ie in centerZonePatchs).
for(i=0;i<centerZonePatchs.size();i++)
{
const CPatch &paSrc= *((const CZone*)centerZone)->getPatch(i);
CPatchInfo &paDst= centerZonePatchs[i];
for(uint corner=0; corner<4; corner++)
paDst.setCornerSmoothFlag(corner, paSrc.getCornerSmoothFlag(corner));
}
}
}*/
// Some errors ?
if (errorMessage.empty())
{
// Save adjacent zones.
//=====================
for(i=0;i<8;i++)
{
if(adjZonesName[i]=="empty") continue;
if(!adjZoneFileFound[i]) continue;
std::vector<CPatchInfo> &adjZonePatchs= adjZoneInfos[i].Patchs;
std::vector<CBorderVertex> &adjZoneBorderVertices= adjZoneInfos[i].BorderVertices;
adjZones[i].build(adjZonesId[i], adjZonePatchs, adjZoneBorderVertices);
#if WELD_LOG
fprintf(fdbg,"[%d] binds :\n", i);
adjZones[i].debugBinds(fdbg);
#endif
std::string strtmp;
//strtmp = outputPath;
strtmp = outputDir+adjZonesName[i]+outputExt;
COFile adjSave(strtmp);
printf("writing file %s\n",strtmp.c_str());
adjZones[i].serial(adjSave);
}
// Save center zone.
//==================
zone.build(centerZoneId, centerZonePatchs, centerZoneBorderVertices);
std::string strtmp;
strtmp = outputDir+center+outputExt;
COFile centerSave(strtmp);
printf("writing file %s\n",strtmp.c_str());
zone.serial(centerSave);
}
else
{
// Main message
nlwarning ("ERROR weld failed. Correct errors below: (indices are MAX indices (+1))\n");
// For each message
for (uint i=0; i<errorMessage.size(); i++)
{
// Message
nlwarning ("%s", errorMessage[i].c_str());
}
}
}
/*******************************************************************\
main()
\*******************************************************************/
int main(sint argc, char **argv)
{
// no zone file in argument
if(argc<3)
{
writeInstructions();
return 0;
}
// help
if(strcmp(argv[1],"/?")==0)
{
writeInstructions();
return 0;
}
#if WELD_LOG
fdbg = nlfopen("log.txt","wt");
fprintf(fdbg,"Center zone : %s\n",argv[1]);
#endif
printf("Center zone : %s\n",argv[1]);
inputDir = getDir (argv[1]);
inputExt = getExt (argv[1]);
outputDir = getDir (argv[2]);
outputExt = getExt (argv[2]);
if(argc == 4)
{
NLMISC::fromString(argv[3], weldRadius);
}
std::string center=getName(argv[1]).c_str();
weldZones(center.c_str());
#if WELD_LOG
fclose(fdbg);
#endif
return 0;
}