// 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