mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-11-30 15:45:59 +00:00
663 lines
19 KiB
C++
663 lines
19 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
#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 <vector>
|
|
#include <algorithm>
|
|
#include <memory>
|
|
#include <set>
|
|
|
|
|
|
|
|
|
|
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<CPatchVertexInfo *> TPVVect;
|
|
typedef CQuadGrid<CPatchVertexInfo> TPVQuadGrid;
|
|
|
|
// ***************************************************************************
|
|
|
|
void bind_1_1 (std::vector<CPatchInfo> &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<CPatchInfo> &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<CPatchInfo> &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<CPatchInfo> &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<otherPatchRef.BindEdges[otherEdge].NPatchs; i++)
|
|
{
|
|
if ( (otherPatchRef.BindEdges[otherEdge].Next[i] == patch) && (otherPatchRef.BindEdges[otherEdge].Edge[i] == edge) )
|
|
{
|
|
otherPos = i;
|
|
return otherPatchRef.BindEdges[otherEdge].NPatchs;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
/** Get all vertices that are near the given one */
|
|
|
|
static void GetCandidateVertices(const CVector &pos,
|
|
TPVQuadGrid &qg,
|
|
TPVVect &dest,
|
|
uint patchToExclude,
|
|
uint patchToExcludeZone,
|
|
float weldThreshold,
|
|
bool exclude
|
|
)
|
|
{
|
|
dest.clear();
|
|
const CVector half(weldThreshold, weldThreshold, weldThreshold);
|
|
float weldThresholdSrt = weldThreshold * weldThreshold;
|
|
qg.select(pos - half, pos + half);
|
|
for (TPVQuadGrid::CIterator it = qg.begin(); it != qg.end(); ++it)
|
|
{
|
|
if ( ::CanWeld((*it).Pos, pos, weldThreshold) )
|
|
{
|
|
if ( (!exclude) || (! ((*it).ZoneIndex == patchToExcludeZone && (*it).PatchIndex == patchToExclude) ) )
|
|
{
|
|
// Final distance test
|
|
if ( (pos - (*it).Pos).sqrnorm () <= weldThresholdSrt )
|
|
dest.push_back(&(*it));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool isBinded (std::vector<CPatchInfo> &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<CPatchInfo> &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 <bindCount; ++n)
|
|
{
|
|
CVector borderPos = evalPatchEdge (patch, m, lambda);
|
|
::GetCandidateVertices(borderPos, qg, binded4[n], l, zoneId, weldThreshold, true);
|
|
lambda += middle;
|
|
}
|
|
|
|
// Binded patches and edges
|
|
uint neighborPatches[4];
|
|
uint neighborEdges[4];
|
|
|
|
// Patch binded
|
|
for (q = 0; q < bindCount; q++)
|
|
{
|
|
for (n = 0; n < binded4[q].size(); n++)
|
|
{
|
|
for (p = 0; p < binded4[q+1].size(); p++)
|
|
{
|
|
// Ref on the two patches
|
|
const CPatchVertexInfo &pv0 = *(binded4[q][n]);
|
|
const CPatchVertexInfo &pv1 = *(binded4[q+1][p]);
|
|
|
|
// Direct or indirect ?
|
|
// Vertex id
|
|
uint v0 = pv0.PatchVertex;
|
|
uint v1 = pv1.PatchVertex;
|
|
if ( pv0.ZoneIndex == pv1.ZoneIndex && pv0.PatchIndex == pv1.PatchIndex )
|
|
{
|
|
// Direct edge ?
|
|
if ( ( ( pv0.PatchVertex - pv1.PatchVertex) & 3 ) == 1 )
|
|
{
|
|
// Patch id
|
|
uint patchId2 = pv0.PatchIndex;
|
|
|
|
// Edge id
|
|
uint edge = v1;
|
|
|
|
// Edge not binded ?
|
|
if (zoneInfos[patchId2].BindEdges[edge].NPatchs == 0)
|
|
{
|
|
// Save the patch
|
|
neighborPatches[q] = patchId2;
|
|
neighborEdges[q] = edge;
|
|
goto exit24;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (n == binded4[q].size())
|
|
// No bind found, stop
|
|
break;
|
|
exit24:;
|
|
}
|
|
|
|
// Find all binded patches ?
|
|
if (q == bindCount)
|
|
{
|
|
// Check The patches are binded together
|
|
for (q=0; q<bindCount-1; q++)
|
|
{
|
|
if (!isBinded (zoneInfos, neighborPatches[q], (neighborEdges[q]-1)&3, neighborPatches[q+1], (neighborEdges[q+1]+1)&3))
|
|
break;
|
|
}
|
|
|
|
// Not breaked ?
|
|
if (q == (bindCount-1) )
|
|
{
|
|
// Bind it
|
|
if (bindCount == 1)
|
|
{
|
|
bind_1_1 (zoneInfos, l, m, neighborPatches[0], neighborEdges[0], zoneId);
|
|
bind1Count++;
|
|
}
|
|
else if (bindCount == 2)
|
|
{
|
|
bind_1_2 (zoneInfos, l, m, neighborPatches[0], neighborEdges[0], neighborPatches[1], neighborEdges[1], zoneId);
|
|
bind2Count++;
|
|
}
|
|
else
|
|
{
|
|
bind_1_4 (zoneInfos, l, m, neighborPatches[0], neighborEdges[0], neighborPatches[1], neighborEdges[1],
|
|
neighborPatches[2], neighborEdges[2], neighborPatches[3], neighborEdges[3], zoneId);
|
|
bind4Count++;
|
|
}
|
|
// Exit connectivity loop
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Print binds
|
|
if (bind1Count || bind2Count || bind4Count)
|
|
{
|
|
printf ("Internal bind pass %d: ", pass);
|
|
if (bind1Count)
|
|
printf ("bind1-1 %d; \n", bind1Count);
|
|
if (bind2Count)
|
|
printf ("bind1-2 %d; \n", bind2Count);
|
|
if (bind4Count)
|
|
printf ("bind1-4 %d; \n", bind4Count);
|
|
}
|
|
else
|
|
// No more bind, stop
|
|
break;
|
|
|
|
// Next pass
|
|
pass++;
|
|
}
|
|
|
|
// Insert vertex binded in the map
|
|
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 == 2) || (bindCount == 4) )
|
|
{
|
|
// Start
|
|
float middle = 1.f / (float)bindCount; // 0 = 0.5; 1 = 0.25
|
|
float lambda = middle;
|
|
|
|
// For all binded vertices
|
|
uint vert;
|
|
for (vert = 1; vert < bindCount; vert++)
|
|
{
|
|
// Eval the binded position
|
|
CVector borderPos = evalPatchEdge (patch, edge, lambda);
|
|
|
|
// yes, insert it in the tree
|
|
const CVector half(weldThreshold, weldThreshold, weldThreshold);
|
|
qg.insert (borderPos - half, borderPos + half, CPatchVertexInfo(zoneId, l, 5, borderPos));
|
|
|
|
// New position
|
|
lambda += middle;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Weld all the vertices !
|
|
uint weldCount = 0;
|
|
for (l = 0; l < zoneInfos.size(); ++l)
|
|
{
|
|
CPatchInfo &patch = zoneInfos[l];
|
|
|
|
// for each edge
|
|
int vert;
|
|
for (vert = 0; vert < 4; ++vert)
|
|
{
|
|
// Not on an opened edge ?
|
|
if ( (patch.BindEdges[vert].NPatchs != 0) && (patch.BindEdges[(vert-1)&3].NPatchs != 0) )
|
|
{
|
|
// Welded ?
|
|
bool welded = false;
|
|
|
|
// Get the vertex to weld
|
|
static TPVVect toWeld;
|
|
CVector pos = patch.Patch.Vertices[vert];
|
|
::GetCandidateVertices (pos, qg, toWeld, l, zoneId, weldThreshold, false);
|
|
|
|
// Weld it
|
|
CVector average (0,0,0);
|
|
uint w;
|
|
bool absolutePosition = false;
|
|
for (w = 0; w < toWeld.size (); w++)
|
|
{
|
|
// Welded vertex ?
|
|
if (toWeld[w]->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<zoneInfos.size ());
|
|
nlassert (otherEdge<4);
|
|
|
|
// Get the vertices
|
|
CVector A, B, C, D;
|
|
A = zoneInfos[otherPatch].Patch.Vertices[otherEdge];
|
|
B = zoneInfos[otherPatch].Patch.Tangents[otherEdge*2];
|
|
C = zoneInfos[otherPatch].Patch.Tangents[otherEdge*2+1];
|
|
D = zoneInfos[otherPatch].Patch.Vertices[(otherEdge+1)&3];
|
|
|
|
// Pos
|
|
uint otherPos;
|
|
uint otherCount = getOtherCountAndPos (zoneInfos, l, edge, otherPos);
|
|
nlassert ( ( (bindCount == 1) && (otherCount == 1) ) || ( (bindCount == 5) && ( (otherCount == 2) || (otherCount == 4) ) ) );
|
|
|
|
// Calc tangents
|
|
if (otherCount == 2)
|
|
{
|
|
if (otherPos == 0)
|
|
getFirst (A, B, C, D);
|
|
else
|
|
getSecond (A, B, C, D);
|
|
}
|
|
else if (otherCount == 4)
|
|
{
|
|
if (otherPos == 0)
|
|
{
|
|
getFirst (A, B, C, D);
|
|
getFirst (A, B, C, D);
|
|
}
|
|
else if (otherPos == 1)
|
|
{
|
|
getFirst (A, B, C, D);
|
|
getSecond (A, B, C, D);
|
|
}
|
|
else if (otherPos == 2)
|
|
{
|
|
getSecond (A, B, C, D);
|
|
getFirst (A, B, C, D);
|
|
}
|
|
else if (otherPos == 3)
|
|
{
|
|
getSecond (A, B, C, D);
|
|
getSecond (A, B, C, D);
|
|
}
|
|
}
|
|
|
|
// 2 tangents
|
|
uint tang;
|
|
for (tang=0; tang<2; tang++)
|
|
{
|
|
nlassert (2*edge+tang < 8);
|
|
|
|
// Eval the binded position
|
|
const CVector &tangVect = (tang==0) ? C : B;
|
|
|
|
// Next offset
|
|
float dist = (patch.Patch.Tangents[2*edge+tang] - tangVect).norm();
|
|
if ( (patch.Patch.Tangents[2*edge+tang] - tangVect).sqrnorm() > 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);
|
|
}
|