// 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); }