Merge branch 'fixes' into main/gingo-test
[ryzomcore.git] / nel / tools / pacs / build_indoor_rbank / mouline.cpp
blobc731e8438ccc52141efd28180654b57b0bbfb669
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <map>
21 #include <vector>
22 #include <sstream>
24 #include "nel/pacs/collision_mesh_build.h"
25 #include "nel/pacs/local_retriever.h"
26 #include "nel/pacs/exterior_mesh.h"
28 #include "mouline.h"
29 #include "build_surfaces.h"
31 using namespace std;
32 using namespace NLMISC;
33 using namespace NLPACS;
36 // a reference on an edge
37 struct CEdgeKey
39 uint32 V0;
40 uint32 V1;
42 CEdgeKey() {}
43 CEdgeKey(uint32 v0, uint32 v1) : V0(v0), V1(v1) {}
45 bool operator() (const CEdgeKey &a, const CEdgeKey &b)
47 return a.V0 < b.V0 || (a.V0 == b.V0 && a.V1 < b.V1);
51 // the info on an edge
52 struct CEdgeInfo
54 sint32 Left, LeftEdge;
55 sint32 Right, RightEdge;
57 CEdgeInfo(sint32 left=-1, sint32 leftEdge=-1, sint32 right=-1, sint32 rightEdge=-1) : Left(left), LeftEdge(leftEdge), Right(right), RightEdge(rightEdge) {}
60 typedef map<CEdgeKey, CEdgeInfo, CEdgeKey> TLinkRelloc;
61 typedef TLinkRelloc::iterator ItTLinkRelloc;
65 void linkMesh(CCollisionMeshBuild &cmb, bool linkInterior)
67 uint i, j;
68 TLinkRelloc relloc;
70 // check each edge of each face
71 for (i=0; i<cmb.Faces.size(); ++i)
73 if (cmb.Faces[i].Surface == CCollisionFace::ExteriorSurface && linkInterior ||
74 cmb.Faces[i].Surface >= CCollisionFace::InteriorSurfaceFirst && !linkInterior)
75 continue;
77 for (j=0; j<3; ++j)
79 cmb.Faces[i].Edge[j] = -1;
81 uint edge = (j+2)%3;
82 uint32 va = cmb.Faces[i].V[j],
83 vb = cmb.Faces[i].V[(j+1)%3];
85 ItTLinkRelloc it;
86 if ((it = relloc.find(CEdgeKey(va, vb))) != relloc.end())
88 // in this case, the left triangle of the edge has already been found.
89 // should throw an error
90 nlerror("On face %d, edge %d: left side of edge (%d,%d) already linked to face %d",
91 i, edge, va, vb, (*it).second.Left);
93 else if ((it = relloc.find(CEdgeKey(vb, va))) != relloc.end())
95 // in this case, we must check the right face has been set yet
96 if ((*it).second.Right != -1)
98 nlerror("On face %d, edge %d: right side of edge (%d,%d) already linked to face %d",
99 i, edge, vb, va, (*it).second.Right);
102 (*it).second.Right = i;
103 (*it).second.RightEdge = edge;
105 else
107 // if the edge wasn't present yet, create it and set it up.
108 relloc.insert(make_pair(CEdgeKey(va, vb), CEdgeInfo(i, edge, -1, -1)));
113 // for each checked edge, update the edge info inside the faces
114 ItTLinkRelloc it;
115 for (it=relloc.begin(); it!=relloc.end(); ++it)
117 sint32 left, leftEdge;
118 sint32 right, rightEdge;
120 // get the link info on the edge
121 left = (*it).second.Left;
122 leftEdge = (*it).second.LeftEdge;
123 right = (*it).second.Right;
124 rightEdge = (*it).second.RightEdge;
126 // update both faces
127 if (left != -1)
128 cmb.Faces[left].Edge[leftEdge] = right;
129 if (right != -1)
130 cmb.Faces[right].Edge[rightEdge] = left;
137 void buildExteriorMesh(CCollisionMeshBuild &cmb, CExteriorMesh &em)
139 uint startFace = 0;
140 vector<CExteriorMesh::CEdge> edges;
142 uint i;
143 for (i=0; i<cmb.Faces.size(); ++i)
145 cmb.Faces[i].EdgeFlags[0] = false;
146 cmb.Faces[i].EdgeFlags[1] = false;
147 cmb.Faces[i].EdgeFlags[2] = false;
150 while (true)
152 // find the first non interior face
153 uint i, edge;
154 bool found = false;
155 for (i=startFace; i<cmb.Faces.size() && !found; ++i)
157 if (cmb.Faces[i].Surface != CCollisionFace::ExteriorSurface)
158 continue;
160 for (edge=0; edge<3 && !found; ++edge)
161 if (cmb.Faces[i].Edge[edge] == -1 && !cmb.Faces[i].EdgeFlags[edge])
163 // nlassert(cmb.Faces[i].Material != 0xdeadbeef);
164 found = true;
165 break;
168 if (found)
169 break;
173 if (!found)
174 break;
176 // cmb.Faces[i].Material = 0xdeadbeef;
178 startFace = i+1;
180 sint32 current = i;
181 sint32 next = cmb.Faces[current].Edge[edge];
183 sint oedge;
184 sint pivot = (edge+1)%3;
185 sint nextEdge = edge;
186 bool allowThis = true;
188 uint numLink = 0;
189 uint firstEdge = (uint)edges.size();
191 vector<CExteriorMesh::CEdge> loop;
193 while (true)
195 if (cmb.Faces[current].EdgeFlags[nextEdge])
197 // if reaches the end of the border, then quits.
198 break;
200 else if (next == -1)
202 // if the next edge belongs to the border, then go on the same element
203 cmb.Faces[current].EdgeFlags[nextEdge] = true;
204 /// \todo get the real edge link
205 sint link = (cmb.Faces[current].Visibility[nextEdge]) ? -1 : 0; //(numLink++);
207 //edges.push_back(CExteriorMesh::CEdge(cmb.Vertices[cmb.Faces[current].V[pivot]], link));
208 loop.push_back(CExteriorMesh::CEdge(cmb.Vertices[cmb.Faces[current].V[pivot]], link));
210 pivot = (pivot+1)%3;
211 nextEdge = (nextEdge+1)%3;
212 next = cmb.Faces[current].Edge[nextEdge];
214 else
216 // if the next element is inside the surface, then go to the next element
217 for (oedge=0; oedge<3 && cmb.Faces[next].Edge[oedge]!=current; ++oedge)
219 nlassert(oedge != 3);
220 current = next;
221 pivot = (oedge+2)%3;
222 nextEdge = (oedge+1)%3;
223 next = cmb.Faces[current].Edge[nextEdge];
227 // mark the end of a ext mesh block
228 // this way, collisions won't be checked in the pacs engine
229 if (loop.size() >= 3)
231 uint n = (uint)loop.size();
232 while (loop.front().Link >= 0 && loop.back().Link >= 0 && n > 0)
234 loop.push_back(loop.front());
235 loop.erase(loop.begin());
236 --n;
239 loop.push_back(loop.front());
240 loop.back().Link = -2;
241 edges.insert(edges.end(), loop.begin(), loop.end());
242 //edges.push_back(edges[firstEdge]);
243 //edges.back().Link = -2;
246 bool previousWasLink = false;
247 sint previousLink = -1;
248 for (i=0; i<edges.size(); ++i)
250 // nldebug("ext-mesh: vertex=%d (%.2f,%.2f,%.2f) link=%d", i, edges[i].Start.x, edges[i].Start.y, edges[i].Start.z, edges[i].Link);
251 if (edges[i].Link >= 0)
253 if (!previousWasLink)
254 ++previousLink;
255 edges[i].Link = previousLink;
256 previousWasLink = true;
258 else
260 previousWasLink = false;
264 em.setEdges(edges);
269 void linkExteriorToInterior(CLocalRetriever &lr)
271 CExteriorMesh em = lr.getExteriorMesh();
272 vector<CExteriorMesh::CEdge> edges = em.getEdges();
273 vector<CExteriorMesh::CLink> links;
274 const vector<CChain> &chains = lr.getChains();
275 const vector<COrderedChain3f> &ochains = lr.getFullOrderedChains();
276 const vector<uint16> &bchains = lr.getBorderChains();
279 uint i;
281 nlinfo("Border chains (to be linked) for this retriever:");
283 for (i=0; i<bchains.size(); ++i)
285 char w[256];
286 std::stringstream ss;
287 const CChain &chain = chains[bchains[i]];
288 sprintf(w, "Border chain %d: chain=%d ", i, bchains[i]);
289 ss << w;
290 uint och;
291 for (och=0; och<chain.getSubChains().size(); ++och)
293 const COrderedChain3f &ochain = ochains[chain.getSubChain(och)];
294 sprintf(w, "subchain=%d", chain.getSubChain(och));
295 ss << w;
296 uint v;
297 for (v=0; v<ochain.getVertices().size(); ++v)
299 sprintf(w, " (%.2f,%.2f)", ochain[v].x, ochain[v].y);
300 ss << w;
304 nlinfo("%s", ss.str().c_str());
308 uint edge, ch;
309 for (edge=0; edge+1<edges.size(); )
311 if (edges[edge].Link == -1 || edges[edge].Link == -2)
313 ++edge;
314 continue;
317 uint startedge = edge;
318 uint stopedge;
320 for (stopedge=edge; stopedge+1<edges.size() && edges[stopedge+1].Link == edges[startedge].Link; ++stopedge)
323 edge = stopedge+1;
325 CVector start = edges[startedge].Start, stop = edges[stopedge+1].Start;
326 bool found = false;
328 for (ch=0; ch<bchains.size() && !found; ++ch)
330 // get the border chain.
331 //const CChain &chain = chains[bchains[ch]];
333 const CVector &cstart = lr.getStartVector(bchains[ch]),
334 &cstop = lr.getStopVector(bchains[ch]);
336 float d = (start-cstart).norm()+(stop-cstop).norm();
337 if (d < 1.0e-1f)
339 found = true;
340 break;
344 // create a link
345 CExteriorMesh::CLink link;
347 if (!found)
349 nlwarning("in linkInteriorToExterior():");
350 nlwarning("couldn't find any link to the exterior edge %d-%d!!", startedge, stopedge);
352 else
354 // set it up to point on the chain and surface
355 link.BorderChainId = ch;
356 link.ChainId = bchains[ch];
357 link.SurfaceId = (uint16)chains[link.ChainId].getLeft();
360 // enlarge the links
361 if (edges[startedge].Link >= (sint)links.size())
362 links.resize(edges[startedge].Link+1);
364 // if the link already exists, warning
365 if (links[edges[startedge].Link].BorderChainId != 0xFFFF ||
366 links[edges[startedge].Link].ChainId != 0xFFFF ||
367 links[edges[startedge].Link].SurfaceId != 0xFFFF)
369 nlwarning("in linkInteriorToExterior():");
370 nlwarning("link %d already set!!", edges[startedge].Link);
373 // setup the link
374 links[edges[startedge].Link] = link;
377 // em.setEdges(edges);
378 em.setLinks(links);
379 lr.setExteriorMesh(em);
387 void computeRetriever(CCollisionMeshBuild &cmb, CLocalRetriever &lr, CVector &translation, bool useCmbTrivialTranslation)
389 // set the retriever
390 lr.setType(CLocalRetriever::Interior);
392 // if should use the own cmb bbox, then compute it
393 if (useCmbTrivialTranslation)
395 translation = cmb.computeTrivialTranslation();
396 // snap the translation vector to a meter wide grid
397 translation.x = (float)ceil(translation.x);
398 translation.y = (float)ceil(translation.y);
399 translation.z = 0.0f;
402 uint i, j;
404 for (i=0; i<cmb.Faces.size(); ++i)
406 CVector normal = ((cmb.Vertices[cmb.Faces[i].V[1]]-cmb.Vertices[cmb.Faces[i].V[0]])^(cmb.Vertices[cmb.Faces[i].V[2]]-cmb.Vertices[cmb.Faces[i].V[0]])).normed();
408 if (normal.z < 0.0f)
410 nlwarning("Face %d in cmb (%s) has negative normal! -- face is flipped", i, cmb.Faces[i].Surface == CCollisionFace::InteriorSurfaceFirst ? "interior" : "exterior");
412 std::swap(cmb.Faces[i].V[1], cmb.Faces[i].V[2]);
413 std::swap(cmb.Faces[i].Visibility[1], cmb.Faces[i].Visibility[2]);
418 // first link faces
420 linkMesh(cmb, false);
421 linkMesh(cmb, true);
423 vector<string> errors;
425 cmb.link(false, errors);
426 cmb.link(true, errors);
428 if (!errors.empty())
430 nlwarning("Edge issues reported !!");
431 uint i;
432 for (i=0; i<errors.size(); ++i)
433 nlwarning("%s", errors[i].c_str());
434 nlerror("Can't continue.");
437 // translate the meshbuild to the local axis
438 cmb.translate(translation);
440 // find the exterior mesh border
441 CExteriorMesh extMesh;
442 buildExteriorMesh(cmb, extMesh);
443 lr.setExteriorMesh(extMesh);
445 // build the surfaces in the local retriever
446 buildSurfaces(cmb, lr);
448 // create the snapping faces and vertices
449 // after the build surfaces because the InternalSurfaceId is filled within buildSurfaces()...
450 buildSnapping(cmb, lr);
453 lr.computeLoopsAndTips();
455 lr.findBorderChains();
456 lr.updateChainIds();
457 lr.computeTopologies();
459 lr.unify();
461 lr.computeCollisionChainQuad();
464 for (i=0; i<lr.getSurfaces().size(); ++i)
465 lr.dumpSurface(i);
468 linkExteriorToInterior(lr);
470 // compute the bbox of the retriever
471 CAABBox bbox;
472 bool first = true;
474 for (i=0; i<extMesh.getEdges().size(); ++i)
475 if (!first)
476 bbox.extend(extMesh.getEdge(i).Start);
477 else
478 bbox.setCenter(extMesh.getEdge(i).Start), first=false;
480 for (i=0; i<lr.getOrderedChains().size(); ++i)
481 for (j=0; j<lr.getOrderedChain(i).getVertices().size(); ++j)
482 if (!first)
483 bbox.extend(lr.getOrderedChain(i)[j].unpack3f());
484 else
485 bbox.setCenter(lr.getOrderedChain(i)[j].unpack3f()), first=false;
487 CVector bboxhs = bbox.getHalfSize();
488 bboxhs.z = 10000.0f;
489 bbox.setHalfSize(bboxhs);
491 lr.setBBox(bbox);