1001 lines
29 KiB
C++
1001 lines
29 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/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
|
|
|
|
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 contient 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= ¢erZonePatchs;
|
|
// 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(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 ¢erBV= 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 = fopen("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)
|
|
{
|
|
weldRadius = (float) atof(argv[3]);
|
|
}
|
|
|
|
std::string center=getName(argv[1]).c_str();
|
|
weldZones(center.c_str());
|
|
|
|
#if WELD_LOG
|
|
fclose(fdbg);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|