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