// NeL - MMORPG Framework
// 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 .
#include "../zone_lib/zone_utility.h"
#include
#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
#include
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(IndexInZonewvinf.IndexInZone)
return false;
if(PatchIndexwvinf.PatchIndex)
return false;
return PatchVertex[]\n");
printf("\t/? for this help\n");
}
/*******************************************************************\
findPatchIndex()
\*******************************************************************/
bool getPatchAndEdge(const std::vector& patchs,
uint16 baseVertex1, uint16 baseVertex2,
uint16& patchIndex,
uint8& edgeIndex)
{
uint ptch;
for(ptch=0; ptch &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 centerZonePatchs;
std::vector centerZoneBorderVertices;
zone.retrieve(centerZonePatchs, centerZoneBorderVertices);
std::vector::iterator itptch;
std::vector::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 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 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 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 &adjZonePatchs= adjZoneInfos[i].Patchs;
std::vector &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::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 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 centerBaseVertexIndexSet;
std::set currentAdjBaseVertexIndexSet;
for(ptch=0; ptch::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>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 centerVertices;
// for all patch, fill the array of vertices.
for(ptch=0; ptch > adjVertices;
for(i=0;i<8;i++)
{
if(adjZonesName[i]=="empty") continue;
if(!adjZoneFileFound[i]) continue;
// create the entry in the map.
vector &verts= adjVertices[adjZonesId[i]];
// for all patch, fill the array of vertices.
std::vector &adjZonePatchs= adjZoneInfos[i].Patchs;
for(ptch=0; ptch &adjZoneBorderVertices= adjZoneInfos[i].BorderVertices;
uint bv;
for(bv=0; bv outVertices;
outVertices.resize(centerVertices.size());
for(i=0; i &verts= adjVertices[adjZonesId[i]];
// for all patch, get vertices which are n Border of the cetnerZone.
std::vector &adjZonePatchs= adjZoneInfos[i].Patchs;
for(ptch=0; ptch 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 nbZones;
for(i=0;i<8;i++)
{
if(adjZonesName[i]=="empty") continue;
if(!adjZoneFileFound[i]) continue;
std::vector &adjZonePatchs= adjZoneInfos[i].Patchs;
std::vector &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;igetPatch(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 &adjZonePatchs= adjZoneInfos[i].Patchs;
std::vector &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