// 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 "nel/misc/types_nl.h" #include "nel/misc/debug.h" #include "nel/misc/path.h" #include "nel/misc/common.h" #include "nel/misc/file.h" #include "nel/misc/time_nl.h" #include "nel/misc/polygon.h" #include "nel/misc/smart_ptr.h" #include "nel/3d/scene_group.h" #include "nel/3d/transform_shape.h" #include "nel/3d/water_model.h" #include "nel/3d/water_shape.h" #include "nel/3d/quad_grid.h" #include "build_rbank.h" #include "build_surf.h" #include "surface_splitter.h" #include "nel/pacs/global_retriever.h" #include "nel/pacs/retriever_bank.h" #include "nel/pacs/surface_quad.h" #include "nel/pacs/local_retriever.h" #include "nel/pacs/retriever_instance.h" #include "nel/pacs/chain.h" #include "nel/pacs/collision_mesh_build.h" #include #include #include using namespace std; using namespace NLMISC; using namespace NL3D; class CIGBox { public: CIGBox() {} CIGBox(const string &name, const CAABBox &bbox) : Name(name), BBox(bbox) {} string Name; CAABBox BBox; void serial(NLMISC::IStream &f) { f.serial(Name, BBox); } }; /* string getZoneNameById(uint16 id) { uint x = id%256; uint y = id/256; char ych[32]; sprintf(ych,"%d_%c%c", y+1, 'A'+x/26, 'A'+x%26); return string(ych); } */ string getZoneNameByCoord(float x, float y) { const float zoneDim = 160.0f; float xcount = x/zoneDim; float ycount = -y/zoneDim + 1; char ych[32]; sprintf(ych,"%d_%c%c",(sint)ycount, 'A'+(sint)xcount/26, 'A'+(sint)xcount%26); return string(ych); } CVector getZoneCenterById(uint16 id) { CAABBox bbox; uint x, y; const float zdim = 160.0f; x = id%256; y = id/256; return CVector(zdim*((float)x+0.5f), -zdim*((float)y+0.5f), 0.0f); } uint32 getIdByCoord(uint x, uint y) { return y*256+x; } string changeExt(string name, const string &ext) { string::iterator it, last; last = name.end(); for (it=name.begin(); it!=name.end(); ++it) if (*it == '.') last = it; name.erase(last, name.end()); name.append("."); name.append(ext); return name; } void processAllPasses(string &zoneName) { uint /*i,*/ j; NLPACS::CZoneTessellation tessellation; vector fullChains; string name; string filename; try { uint16 zid = getZoneIdByName(zoneName); CAABBox box = getZoneBBoxById(zid); CVector translation = -box.getCenter(); if (tessellation.setup(zid, 4, translation)) { tessellation.build(); CAABBox tbox = tessellation.computeBBox(); tessellation.compile(); tessellation.generateBorders(1.0); NLPACS::CLocalRetriever retriever; CAABBox rbbox = tessellation.BestFittingBBox; CVector hs = rbbox.getHalfSize(); hs.z = 10000.0f; rbbox.setHalfSize(hs); retriever.setBBox(rbbox); retriever.setType(NLPACS::CLocalRetriever::Landscape); for (j=0; j fullChains; string name; string filename; try { uint16 zid = getZoneIdByName(zoneName); CAABBox box = getZoneBBoxById(zid); CVector translation = -box.getCenter(); if (tessellation.setup(zid, 4, translation)) { tessellation.build(); CAABBox tbox = tessellation.computeBBox(); vector boxes; try { if (CFile::fileExists (IGBoxes)) { CIFile binput(IGBoxes); binput.serialCont(boxes); } else { nlinfo("WARNING: IG list no found"); } } catch (const Exception &) { nlinfo("WARNING: IG list no found"); } for (i=0; i(shape.getShapePointer()); if (wshape == NULL) continue; CMatrix matrix; ig.getInstanceMatrix(j, matrix); CPolygon wpoly; wshape->getShapeInWorldSpace(wpoly); uint k; for (k=0; k Chains; CVectorD Start, End; sint FrontInstance, FrontChain; }; class CFaultyInstance { public: uint Instance; vector Chains; vector Reconstructed; }; class CChainRef { public: uint Chain, Previous; uint FrontChain; uint BorderId; uint From, To; }; class CFullChain { public: uint Instance; vector Vertices; vector Chains; }; void fixFaultyLinks(map &faultyInstances, const vector &instances, const vector &retrievers) { map::iterator ifi; uint i, j, k, l; // first // rebuild full chains // -- join all chains that are missing a link for (ifi=faultyInstances.begin(); ifi!=faultyInstances.end(); ++ifi) { CFaultyInstance &inst = (*ifi).second; // for each chain, find best matching ending chain for (k=0; k neighbs = instance.getNeighbors(); for (i=0; i::iterator ifn = faultyInstances.find(neighbs[i]); if (ifn == faultyInstances.end()) continue; CFaultyInstance &neighb = (*ifn).second; for (j=0; j 0.2f) { nlwarning("Couldn't reconstruct link between %d and %d, some vertices don't match", inst.Instance, neighb.Instance); break; } fci.Vertices[l] -= ori; fcn.Vertices[fci.Vertices.size()-1-l] -= orn; } if (l ifreeBorderIds, nfreeBorderIds; uint inextBorderId, nnextBorderId; for (l=0; l=0 && fcn.Chains[m].From>splitAt; --m) ; // no split ? if ((sint)m < 0 || fcn.Chains[m].From == splitAt) continue; // insert split in second chain fcn.Chains.insert(fcn.Chains.begin()+m+1, fcn.Chains[m]); fcn.Chains[m].To = splitAt; fcn.Chains[m+1].From = splitAt; fcn.Chains[m+1].Chain = newChainn++; } // generate splits from second chain on first chain for (l=0; l=0 && fci.Chains[m].From>splitAt; --m) ; // no split ? if ((sint)m < 0 || fci.Chains[m].From == splitAt) continue; // insert split in first chain fci.Chains.insert(fci.Chains.begin()+m+1, fci.Chains[m]); fci.Chains[m].To = splitAt; fci.Chains[m+1].From = splitAt; fci.Chains[m+1].Chain = newChaini++; } if (fci.Chains.size() != fcn.Chains.size()) { nlwarning("Couldn't reconstruct link between %d and %d, chain splitting failed", inst.Instance, neighb.Instance); break; } // renumerate border ids after splits for (l=0; l(retriever)).forceBorderChainId(fci.Chains[l].Chain, fci.Chains[l].BorderId); } for (l=0; l(nretriever)).forceBorderChainId(fcn.Chains[l].Chain, fcn.Chains[l].BorderId); } // insert/replace new chains in instances vector replacement; vector newIds; l=0; while (l= 2) { (const_cast(retriever)).replaceChain(previous, replacement); (const_cast(instance)).resetBorderChainLinks(newIds); } } l=0; while (l= 2) { (const_cast(nretriever)).replaceChain(previous, replacement); (const_cast(ninstance)).resetBorderChainLinks(newIds); } } // force links between instances (border chain links) for (l=0; l(instance)).forceBorderChainLink(fci.Chains[l].BorderId, neighb.Instance, fcn.Chains[m].BorderId, fcn.Chains[m].Chain, nretriever.getChain(fcn.Chains[m].Chain).getLeft()); (const_cast(ninstance)).forceBorderChainLink(fcn.Chains[m].BorderId, inst.Instance, fci.Chains[l].BorderId, fci.Chains[l].Chain, retriever.getChain(fci.Chains[l].Chain).getLeft()); if (Verbose) nlinfo("Fixed: link between %d/%d and %d/%d => %d/%d - %d/%d", fci.Instance, fci.Chains[l].Previous, fcn.Instance, fcn.Chains[m].Previous, fci.Instance, fci.Chains[l].Chain, fcn.Instance, fcn.Chains[m].Chain); } break; } } } } (const_cast(retriever)).computeCollisionChainQuad(); } } void processGlobalRetriever() { NLPACS::CRetrieverBank retrieverBank; NLPACS::CGlobalRetriever globalRetriever; uint ULid = getZoneIdByName(GlobalUL), DRid = getZoneIdByName(GlobalDR); CAABBox ULbbox = getZoneBBoxById(ULid); CAABBox DRbbox = getZoneBBoxById(DRid); CAABBox bbox; CVector vmin, vmax; vmin.minof(ULbbox.getMin(), DRbbox.getMin()); vmax.maxof(ULbbox.getMax(), DRbbox.getMax()); bbox.setMinMax(vmin, vmax); uint x0 = ULid%256, y0 = ULid/256, x1 = DRid%256, y1 = DRid/256; globalRetriever.setRetrieverBank(&retrieverBank); globalRetriever.init(); uint x, y; if (Verbose) nlinfo("make all instances"); for (y=y0; y<=y1; ++y) { for (x=x0; x<=x1; ++x) { try { string filename = OutputPath+getZoneNameById(x+y*256)+".lr"; if (CFile::fileExists (filename)) { uint retrieverId = retrieverBank.addRetriever(filename); globalRetriever.makeInstance(retrieverId, 0, getZoneCenterById((uint16)getIdByCoord(x, y))); } } catch (const Exception &e) { printf("%s\n", e.what ()); } } } if (Verbose) nlinfo("make all links"); globalRetriever.makeAllLinks(); // if (Verbose) // nlinfo("clean retriever bank up"); // retrieverBank.clean(); map faultyInstances; const vector &instances = globalRetriever.getInstances(); const vector &retrievers = retrieverBank.getRetrievers(); uint i, j; uint totalUnlinked = 0, totalLink = 0; for (i=0; i &links = instances[i].getBorderChainLinks(); CVector pos = instances[i].getBBox().getCenter(); string unlinkstr = "instance "+toString(i)+":"+getZoneNameById(getZoneIdByPos(pos))+":"; bool unlinkerr = false; const NLPACS::CLocalRetriever &retriever = retrievers[instances[i].getRetrieverId()]; CFaultyInstance fi; fi.Instance = i; for (j=0; j(i, fi)); } } if (Verbose) nlinfo("%d are still unlinked (%d links total)", totalUnlinked, totalLink); // rebuild full chains if (totalUnlinked > 0) { if (Verbose) nlinfo("Fixing faulty links..."); fixFaultyLinks(faultyInstances, instances, retrievers); // recheck const vector &instances = globalRetriever.getInstances(); const vector &retrievers = retrieverBank.getRetrievers(); uint i, j; uint totalUnlinked = 0, totalLink = 0; for (i=0; i &links = instances[i].getBorderChainLinks(); CVector pos = instances[i].getBBox().getCenter(); string unlinkstr = "instance "+toString(i)+":"+getZoneNameById(getZoneIdByPos(pos))+":"; bool unlinkerr = false; const NLPACS::CLocalRetriever &retriever = retrievers[instances[i].getRetrieverId()]; CFaultyInstance fi; fi.Instance = i; for (j=0; j(i, fi)); } } } if (Verbose) nlinfo("init the quad grid"); globalRetriever.initQuadGrid(); string filename; COFile outputRetriever; filename = OutputPath+GlobalRetriever; if (Verbose) nlinfo("save file %s", filename.c_str()); outputRetriever.open(filename); globalRetriever.serial(outputRetriever); COFile outputBank; filename = OutputPath+RetrieverBank; if (Verbose) nlinfo("save file %s", filename.c_str()); outputBank.open(filename); retrieverBank.serial(outputBank); retrieverBank.saveRetrievers(OutputPath, CFile::getFilenameWithoutExtension(RetrieverBank)); } /// void updateRetrieverBank() { NLPACS::CRetrieverBank retrieverBank; string filename; filename = OutputPath+RetrieverBank; CIFile inputBank; if (Verbose) nlinfo("load file %s", filename.c_str()); inputBank.open(filename); retrieverBank.serial(inputBank); inputBank.close(); COFile outputBank; if (Verbose) nlinfo("save file %s", filename.c_str()); outputBank.open(filename); retrieverBank.serial(outputBank); outputBank.close(); }