// 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 "surface_splitter.h" using namespace std; using namespace NLMISC; using namespace NLPACS; // ----------------------- // // Constructor CSurfaceSplitter::CSurfaceSplitter() { } // void CSurfaceSplitter::build(CLocalRetriever &lr) { nlinfo("--- Build SurfaceSplitter..."); nlinfo("------------------------------------------"); uint i; initEdgeGrid(); _NumChains = 0; _NumSurfaces = 0; _NumTips = 0; for (i=0; i= 0 ? CSurfaceId(0, (uint16)pacsChain.getLeft()) : CSurfaceId(); CSurfaceId right = pacsChain.getRight() >= 0 ? CSurfaceId(0, (uint16)pacsChain.getRight()) : CSurfaceId(); vector vertices; uint i; // walk through all subchains for (i=0; i0; --j) vertices.push_back(CVector2s64(pacsOChain[j])); } // add final chain point if (i == pacsChain.getSubChains().size()-1) vertices.push_back(CVector2s64(pacsOChain[j])); } addChain(left,right, vertices); } // void CSurfaceSplitter::buildSurface(CLocalRetriever &lr, uint surface) { const NLPACS::CRetrievableSurface &pacsSurface = lr.getSurface(surface); CSurface newSurface; newSurface.Id = CSurfaceId(0, surface); uint i; // walk through all loops for (i=0; iDontSplit) continue; CVector2s64 inters; CFixed64 ndist; if (intersect(chain.Vertices[edge], chain.Vertices[edge+1], ichain->Vertices[iedge.Edge], ichain->Vertices[iedge.Edge+1], inters, ndist)) { if (inters != chain.Vertices[edge+1] || edge != chain.Vertices.size()-2) { ++numInters; nlinfo("Intersection: %d:%d[%.3f,%.3f-%.3f,%.3f]-%d:%d[%.3f,%.3f-%.3f,%.3f] : [%.3f,%.3f]", chain.Id.Id, edge, p0.x, p0.y, p1.x, p1.y, iedge.Chain.Id, iedge.Edge, ichain->Vertices[iedge.Edge].asVector().x, ichain->Vertices[iedge.Edge].asVector().y, ichain->Vertices[iedge.Edge+1].asVector().x, ichain->Vertices[iedge.Edge+1].asVector().y, inters.asVector().x, inters.asVector().y); if (closerDist > ndist) { collisionFound = true; collidingEdge = iedge; collision = inters; } } else { nlinfo("Intersection: %d:%d[%.3f,%.3f-%.3f,%.3f]-%d:%d[%.3f,%.3f-%.3f,%.3f] : [%.3f,%.3f] -- SKIPPED", chain.Id.Id, edge, p0.x, p0.y, p1.x, p1.y, iedge.Chain.Id, iedge.Edge, ichain->Vertices[iedge.Edge].asVector().x, ichain->Vertices[iedge.Edge].asVector().y, ichain->Vertices[iedge.Edge+1].asVector().x, ichain->Vertices[iedge.Edge+1].asVector().y, inters.asVector().x, inters.asVector().y); } } } // split chain if (collisionFound) { if (chain.Id == collidingEdge.Chain) { // self colliding chain // check order //nlassert(edge >= 0); // always true for unsigned nlassert(edge < collidingEdge.Edge); nlassert(collidingEdge.Edge < chain.Vertices.size()-1); // must split the chain in 3 parts uint e; vector begin; vector middle; vector end; vector v; CChainId beginId; CChainId middleId; CChainId endId; for (e=0; e<=edge; ++e) begin.push_back(chain.Vertices[e]); begin.push_back(collision); if (collision != chain.Vertices[e]) middle.push_back(collision); for (; e<=collidingEdge.Edge; ++e) middle.push_back(chain.Vertices[e]); middle.push_back(collision); if (collision != chain.Vertices[e]) end.push_back(collision); for (; e= 0); // always true for unsigned nlassert(edge < chain.Vertices.size()-1); // split the chain uint e; vector begin; vector end; vector v; CChainId beginId; CChainId endId; // split the first chain for (e=0; e<=edge; ++e) begin.push_back(chain.Vertices[e]); begin.push_back(collision); if (collision != chain.Vertices[e]) end.push_back(collision); for (; eVertices[e]); begin.push_back(collision); if (collision != collide->Vertices[e]) end.push_back(collision); for (; eVertices.size(); ++e) end.push_back(collide->Vertices[e]); beginId = addChain(collide->Left, collide->Right, begin); endId = addChain(collide->Left, collide->Right, end); v.push_back(beginId); v.push_back(endId); replaceChain(collide->Id, v); } return; } } } // bool CSurfaceSplitter::intersect(const CVector2s64 &v0, const CVector2s64 &v1, const CVector2s64 &c0, const CVector2s64 &c1, CVector2s64 &intersect, CFixed64 &ndist) { if (v0 == c0 || v0 == c1) return false; if (v1 == c0 || v1 == c1) { intersect = v1; ndist = CFixed64(1.0); return true; } CVector2s64 nnc(c0.y-c1.y, c1.x-c0.x), nnv(v0.y-v1.y, v1.x-v0.x); CFixed64 dv = (v1-v0)*nnc; // vectors are colinears ? if ((sint64)dv == 0) return false; CFixed64 nv = (c0-v0)*nnc; if ((sint64)dv < 0) dv=-dv, nv=-nv; // intersection outside main edge ? (or at first point ?) if ((sint64)nv<=0 || nv>dv) return false; CFixed64 dc = (c1-c0)*(c1-c0); // second edge null ? if ((sint64)dc == 0) return false; CFixed64 lv = nv/dv; if ((sint64)lv == 0) return false; CFixed64 nc = (v0-c0 + (v1-v0)*lv)*(c1-c0); // intersection outside colliding edge ? if ((sint64)nc<0 || nc>dc) return false; // treat each singular case if (nv == dv) intersect = v1; else if ((sint64)nc == 0) intersect = c0; else if (nc == dc) intersect = c1; else // compute intersecting point intersect = v0 + (v1-v0)*lv; ndist = lv; return true; } // CSurfaceSplitter::CChainId CSurfaceSplitter::addChain(const CSurfaceId &left, const CSurfaceId &right, const vector &points, bool dontSplit) { pair res = _Chains.insert(make_pair(CChainId(_NumChains++), CChain())); CChain &chain = (*(res.first)).second; chain.Id = (*(res.first)).first; chain.Left = left; chain.Right = right; uint i; for (i=0; iremoveChain(chainId); if ((surf = getSurface(chain.Right))) surf->removeChain(chainId); } // void CSurfaceSplitter::replaceChain(CChainId chainId, const vector &chains) { // get chain it TChainMap::iterator it = _Chains.find(chainId); if ((it == _Chains.end())) return; CChain &chain = (*it).second; CSurface *surf; nlinfo("-- Replace --"); dumpChain(chainId); nlinfo("-- By --"); uint c; for (c=0; cLoops.size(); ++loop) { CLoop &ploop = surf->Loops[loop]; vector::iterator it; for (it=ploop.Chains.begin(); it!=ploop.Chains.end(); ++it) { if (*it == chainId) { it = ploop.Chains.erase(it); sint i; for (i=(sint)chains.size()-1; i>=0; --i) { it = ploop.Chains.insert(it, chains[i]); } } } } } if ((surf = getSurface(chain.Right))) { uint loop; for (loop=0; loopLoops.size(); ++loop) { CLoop &ploop = surf->Loops[loop]; vector::iterator it; for (it=ploop.Chains.begin(); it!=ploop.Chains.end(); ++it) { if (*it == chainId) { it = ploop.Chains.erase(it); uint i; for (i=0; i