// 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 "nel/misc/types_nl.h"
#include "nel/misc/path.h"
#include "nel/misc/file.h"
#include "nel/misc/aabbox.h"
//
#include "nel/3d/quad_grid.h"
#include "nel/3d/bezier_patch.h"
#include "nel/3d/zone.h"
//
#include
#include
#include
#include
using namespace NLMISC;
using namespace NL3D;
// a patch vertex info, for quadtree insertion
struct CPatchVertexInfo
{
uint ZoneIndex; // this zone index, 0 for the midlle zone, and from 1 to 8 for the zones around
uint PatchIndex; // the Patch of this zone
uint PatchVertex; // the vertex of thi patch 0..3
CVector Pos;
CPatchVertexInfo() {}
CPatchVertexInfo(uint zoneIndex,
uint patchIndex,
uint patchVertex,
const CVector &pos
)
: ZoneIndex(zoneIndex),
PatchIndex(patchIndex),
PatchVertex(patchVertex),
Pos(pos)
{
}
};
typedef std::vector TPVVect;
typedef CQuadGrid TPVQuadGrid;
// ***************************************************************************
void bind_1_1 (std::vector &zoneInfos, uint patch0, uint edge0, uint patch1, uint edge1, uint zoneId)
{
// Bind type
zoneInfos[patch0].BindEdges[edge0].NPatchs = 1;
zoneInfos[patch1].BindEdges[edge1].NPatchs = 1;
// Zone ID
zoneInfos[patch0].BindEdges[edge0].ZoneId = zoneId;
zoneInfos[patch1].BindEdges[edge1].ZoneId = zoneId;
// Next
zoneInfos[patch0].BindEdges[edge0].Next[0] = patch1;
zoneInfos[patch1].BindEdges[edge1].Next[0] = patch0;
// Edge
zoneInfos[patch0].BindEdges[edge0].Edge[0] = edge1;
zoneInfos[patch1].BindEdges[edge1].Edge[0] = edge0;
}
// ***************************************************************************
void bind_1_2 (std::vector &zoneInfos, uint patch, uint edge, uint patch0, uint edge0, uint patch1, uint edge1, uint zoneId)
{
// Bind type
zoneInfos[patch].BindEdges[edge].NPatchs = 2;
zoneInfos[patch0].BindEdges[edge0].NPatchs = 5;
zoneInfos[patch1].BindEdges[edge1].NPatchs = 5;
// Zone ID
zoneInfos[patch].BindEdges[edge].ZoneId = zoneId;
zoneInfos[patch0].BindEdges[edge0].ZoneId = zoneId;
zoneInfos[patch1].BindEdges[edge1].ZoneId = zoneId;
// Next
zoneInfos[patch].BindEdges[edge].Next[0] = patch0;
zoneInfos[patch].BindEdges[edge].Next[1] = patch1;
zoneInfos[patch0].BindEdges[edge0].Next[0] = patch;
zoneInfos[patch1].BindEdges[edge1].Next[0] = patch;
// Edge
zoneInfos[patch].BindEdges[edge].Edge[0] = edge0;
zoneInfos[patch].BindEdges[edge].Edge[1] = edge1;
zoneInfos[patch0].BindEdges[edge0].Edge[0] = edge;
zoneInfos[patch1].BindEdges[edge1].Edge[0] = edge;
}
// ***************************************************************************
void bind_1_4 (std::vector &zoneInfos, uint patch, uint edge, uint patch0, uint edge0, uint patch1, uint edge1, uint patch2, uint edge2, uint patch3, uint edge3, uint zoneId)
{
// Bind type
zoneInfos[patch].BindEdges[edge].NPatchs = 4;
zoneInfos[patch0].BindEdges[edge0].NPatchs = 5;
zoneInfos[patch1].BindEdges[edge1].NPatchs = 5;
zoneInfos[patch2].BindEdges[edge2].NPatchs = 5;
zoneInfos[patch3].BindEdges[edge3].NPatchs = 5;
// Zone ID
zoneInfos[patch].BindEdges[edge].ZoneId = zoneId;
zoneInfos[patch0].BindEdges[edge0].ZoneId = zoneId;
zoneInfos[patch1].BindEdges[edge1].ZoneId = zoneId;
zoneInfos[patch2].BindEdges[edge2].ZoneId = zoneId;
zoneInfos[patch3].BindEdges[edge3].ZoneId = zoneId;
// Next
zoneInfos[patch].BindEdges[edge].Next[0] = patch0;
zoneInfos[patch].BindEdges[edge].Next[1] = patch1;
zoneInfos[patch].BindEdges[edge].Next[2] = patch2;
zoneInfos[patch].BindEdges[edge].Next[3] = patch3;
zoneInfos[patch0].BindEdges[edge0].Next[0] = patch;
zoneInfos[patch1].BindEdges[edge1].Next[0] = patch;
zoneInfos[patch2].BindEdges[edge2].Next[0] = patch;
zoneInfos[patch3].BindEdges[edge3].Next[0] = patch;
// Edge
zoneInfos[patch].BindEdges[edge].Edge[0] = edge0;
zoneInfos[patch].BindEdges[edge].Edge[1] = edge1;
zoneInfos[patch].BindEdges[edge].Edge[2] = edge2;
zoneInfos[patch].BindEdges[edge].Edge[3] = edge3;
zoneInfos[patch0].BindEdges[edge0].Edge[0] = edge;
zoneInfos[patch1].BindEdges[edge1].Edge[0] = edge;
zoneInfos[patch2].BindEdges[edge2].Edge[0] = edge;
zoneInfos[patch3].BindEdges[edge3].Edge[0] = edge;
}
// ***************************************************************************
/** Test whether 2 vertices could be welded */
static inline bool CanWeld(const CVector &v1, const CVector &v2, float weldThreshold)
{
return (v1 - v2).norm() < weldThreshold;
}
// ***************************************************************************
uint getOtherCountAndPos (const std::vector &zoneInfo, uint patch, uint edge, uint &otherPos)
{
// Must be a multiple patch bind
if (zoneInfo[patch].BindEdges[edge].NPatchs == 5)
{
uint i;
const CPatchInfo &otherPatchRef = zoneInfo[zoneInfo[patch].BindEdges[edge].Next[0]];
uint otherEdge = zoneInfo[patch].BindEdges[edge].Edge[0];
for (i=0; i &zoneInfos, uint patch0, uint edge0, uint patch1, uint edge1)
{
// Binded ?
if ( (zoneInfos[patch0].BindEdges[edge0].NPatchs != 0) && (zoneInfos[patch1].BindEdges[edge1].NPatchs != 0) )
{
// Binded ?
return (zoneInfos[patch0].BindEdges[edge0].Next[0] == patch1) ||
(zoneInfos[patch1].BindEdges[edge1].Next[0] == patch0);
}
return false;
}
// ***************************************************************************
CVector evalPatchEdge (CPatchInfo &patch, uint edge, float lambda)
{
// index of this border vertices
static const float indexToST[][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
const uint vIndex[] = { edge, (edge + 1) & 0x03 };
return patch.Patch.eval((1.f - lambda) * indexToST[vIndex[0]][0] + lambda * indexToST[vIndex[1]][0],
(1.f - lambda) * indexToST[vIndex[0]][1] + lambda * indexToST[vIndex[1]][1]);
}
// ***************************************************************************
void getFirst (CVector &a, CVector &b, CVector &c, CVector &d)
{
// ab
CVector ab = (a+b)/2.f;
// bc
CVector bc = (b+c)/2.f;
// cd
CVector cd = (c+d)/2.f;
b = ab;
c = (ab + bc) / 2.f;
d = ( (bc + cd) / 2.f + c ) / 2.f;
}
// ***************************************************************************
void getSecond (CVector &a, CVector &b, CVector &c, CVector &d)
{
// ab
CVector ab = (a+b)/2.f;
// bc
CVector bc = (b+c)/2.f;
// cd
CVector cd = (c+d)/2.f;
c = cd;
b = (bc + cd) / 2.f;
a = ( (ab + bc) / 2.f + b ) / 2.f;
}
// ***************************************************************************
void CleanZone ( std::vector &zoneInfos, uint zoneId, const CAABBoxExt &zoneBBox, float weldThreshold)
{
uint l, m, n, p, q; // some loop counters
///////////////////////////////
// retrieve datas from zones //
///////////////////////////////
// fill the quad grid
float zoneSize = 2.f * weldThreshold + std::max(zoneBBox.getMax().x - zoneBBox.getMin().x,
zoneBBox.getMax().y - zoneBBox.getMin().y);
TPVQuadGrid qg;
const uint numQGElt = 128;
qg.create (numQGElt, zoneSize / numQGElt);
for (l = 0; l < zoneInfos.size(); ++l)
{
CPatchInfo &patch = zoneInfos[l];
// for each base vertex of the patch
for (m = 0; m < 4; ++m)
{
CVector &pos = patch.Patch.Vertices[m];
// yes, insert it in the tree
const CVector half(weldThreshold, weldThreshold, weldThreshold);
qg.insert(pos - half, pos + half, CPatchVertexInfo(zoneId, l, m, pos));
}
}
/////////////////////////////////////////////////
// check whether each patch is correctly bound //
/////////////////////////////////////////////////
uint pass = 0;
while (1)
{
uint bind1Count = 0;
uint bind2Count = 0;
uint bind4Count = 0;
for (l = 0; l < zoneInfos.size(); ++l)
{
// Ref on patch
CPatchInfo &patch = zoneInfos[l];
// deals with each border
for (m = 0; m < 4; ++m)
{
const uint vIndex[] = { m, (m + 1) & 0x03 };
// if this border is said to be bound, no need to test..
if (patch.BindEdges[m].NPatchs == 0)
{
static TPVVect verts[2];
// Get vertices from other patch that could be welded with this patch boder's vertices.
for (q = 0; q < 2; ++q)
{
::GetCandidateVertices(patch.Patch.Vertices[vIndex[q]], qg, verts[q], l, zoneId, weldThreshold, true);
}
uint bindCount;
for (bindCount = 1; bindCount<5; bindCount<<=1)
{
// Float middle
float middle = 1.f / (float)bindCount; // 0 = 0.5; 1 = 0.25
// Try to find a patch that shares 2 consecutives vertices
static TPVVect binded4[5];
binded4[0] = verts[0];
binded4[bindCount] = verts[1];
// Compute points along the border and found list of vertex binded to it.
float lambda = middle;
for (n = 1; n PatchVertex == 5)
{
absolutePosition = true;
average = toWeld[w]->Pos;
}
// Add it;
if (!absolutePosition)
average += toWeld[w]->Pos;
// Not the same ?
float dist = (pos - toWeld[w]->Pos).norm();
if ( (pos - toWeld[w]->Pos).sqrnorm() > 0.0001 )
welded = true;
}
// Average
if (!absolutePosition)
average /= (float)toWeld.size ();
// Weld ?
if (welded)
{
// Welded
weldCount++;
// Set the pos
for (w = 0; w < toWeld.size (); w++)
{
if (toWeld[w]->PatchVertex != 5)
{
toWeld[w]->Pos = average;
zoneInfos[toWeld[w]->PatchIndex].Patch.Vertices[toWeld[w]->PatchVertex] = average;
}
}
}
}
}
}
if (weldCount)
printf ("Internal vertices welded: %d\n", weldCount);
// Weld all the Tangents !
weldCount = 0;
for (l = 0; l < zoneInfos.size(); ++l)
{
CPatchInfo &patch = zoneInfos[l];
// for each edge
int edge;
for (edge = 0; edge < 4; ++edge)
{
// Binded ?
uint bindCount = patch.BindEdges[edge].NPatchs;
if ( /*(bindCount == 1) || */(bindCount == 5) )
{
// Neighbor patch
uint otherPatch = patch.BindEdges[edge].Next[0];
uint otherEdge = patch.BindEdges[edge].Edge[0];
nlassert (otherPatch 0.0001 )
weldCount++;
// Fix it!
if (bindCount == 1)
{
patch.Patch.Tangents[2*edge+tang] += tangVect;
patch.Patch.Tangents[2*edge+tang] /= 2;
}
else
patch.Patch.Tangents[2*edge+tang] = tangVect;
}
}
}
}
if (weldCount)
printf ("Internal tangents welded: %d\n", weldCount);
}