Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / ligo / zone_template.cpp
blobe21cde43886eabe9ba5168b5cf18de1a106be84d
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdligo.h"
18 #include "nel/ligo/zone_template.h"
19 #include "nel/ligo/ligo_error.h"
20 #include "nel/ligo/ligo_config.h"
22 #include "nel/misc/stream.h"
23 #include "nel/misc/matrix.h"
25 using namespace std;
26 using namespace NLMISC;
28 namespace NLLIGO
31 const uint SnappedXFlag = 1;
32 const uint SnappedYFlag = 2;
34 // ***************************************************************************
36 inline void CZoneTemplate::snap (float& value, float snap)
38 // Snap it
39 value = snap * (float) floor ( (value / snap) + 0.5f );
42 // ***************************************************************************
44 inline bool CZoneTemplate::snapOnGrid (float& value, float resolution, float snap)
46 // Calc the floor
47 float _floor = (float) ( resolution * floor (value / resolution) );
48 nlassert (_floor<=value);
50 // Calc the remainder
51 float remainder = value - _floor;
52 //nlassert ( (remainder>=0) && (remainder<resolution) );
54 // Check the snape
55 if ( remainder <= snap )
57 // Flag it
58 value = _floor;
60 // Floor is good
61 return true;
63 else if ( (resolution - remainder) <= snap )
65 // Flag it
66 value = _floor + resolution;
68 // Floor + resolution is good
69 return true;
71 return false;
74 // ***************************************************************************
76 inline bool CZoneTemplate::isSnapedOnGrid (float value, float resolution, float snap)
78 // Snapped
79 float snapped = value;
80 return snapOnGrid (snapped, resolution, snap);
83 // ***************************************************************************
85 inline sint32 CZoneTemplate::getSnappedIndex (float value, float resolution, float snap)
87 // Snapped
88 float snapped = value;
90 // This value must be snapped
91 nlverify (snapOnGrid (snapped, resolution, snap));
93 // Return the index
94 return (sint32) floor ( (snapped / resolution) + 0.5f );
97 // ***************************************************************************
99 bool CZoneTemplate::build (const std::vector<NLMISC::CVector> &vertices, const std::vector< std::pair<uint, uint> > &indexes, const CLigoConfig &config, CLigoError &errors)
101 // Clear the error message
102 errors.clear ();
104 // Make an boundary flag array
105 vector<uint> boundaryFlags;
107 // Vertices count
108 uint vertexCount = (uint)vertices.size();
110 // Resize the array
111 boundaryFlags.resize (vertexCount, 0);
113 // *** Build the flag array and the snapped vertex array
115 // For each vertices
116 uint vertex;
117 for (vertex = 0; vertex < vertexCount; vertex++)
119 // Snap the point on the X grid
120 if (isSnapedOnGrid (vertices[vertex].x, config.CellSize, config.Snap))
121 // Flag on X
122 boundaryFlags[vertex]|=SnappedXFlag;
124 // Snap the point on the Y grid
125 if (isSnapedOnGrid (vertices[vertex].y, config.CellSize, config.Snap))
126 // Flag on Y
127 boundaryFlags[vertex]|=SnappedYFlag;
130 // *** Build the edge set
131 multimap<uint, uint> edgePair;
132 multimap<uint, uint> edgePairReverse;
134 // Index count
135 uint edgeCount = (uint)indexes.size();
137 // For each vertices
138 uint edge;
139 for (edge = 0; edge < edgeCount; edge++)
141 // Ref on the pair
142 const pair<uint, uint> &theEdge = indexes[edge];
144 // Vertex snapped ?
145 if ( boundaryFlags[theEdge.first] && boundaryFlags[theEdge.second] )
147 // Common coordinates
148 uint common = boundaryFlags[theEdge.first] & boundaryFlags[theEdge.second];
150 // Snapped on the same kind of coordinates ?
151 if ( common )
153 // Keep this edge ?
154 bool keep = false;
156 // Snapped both on X ?
157 if ( common & SnappedXFlag )
159 // Keep it
160 keep = true;
163 // Snapped both on X ?
164 if ( common & SnappedYFlag )
166 // Keep it
167 keep = true;
170 // Keep this edge ?
171 if (keep)
173 // Already inserted ?
174 bool first = edgePair.find (theEdge.first) != edgePair.end();
175 bool second = edgePairReverse.find (theEdge.second) != edgePairReverse.end();
177 // First already inserted
178 if (first || second)
180 // Error, two times the same vertex
181 errors.MainError = CLigoError::VertexAlreadyUsed;
183 if (first)
184 errors.pushVertexError (CLigoError::VertexAlreadyUsed, theEdge.first, 0);
186 if (second)
187 errors.pushVertexError (CLigoError::VertexAlreadyUsed, theEdge.second, 0);
189 return false;
192 if ((!first) && (!second))
194 // Add to the map
195 edgePair.insert (map<uint, uint>::value_type(theEdge.first, theEdge.second));
196 edgePairReverse.insert (map<uint, uint>::value_type(theEdge.second, theEdge.first));
203 // *** Build the list of non included vertices
205 // For each vertices
206 for (uint i=0; i<vertexCount; i++)
208 // Vertex is inserted ?
209 if (edgePair.find (i) == edgePair.end())
211 // No, add an error message
212 errors.pushVertexError (CLigoError::NotInserted, i, 0);
214 else
216 // No, add an error message
217 errors.pushVertexError (CLigoError::Inserted, i, 0);
221 // *** Build the linked list
223 // No vertices found ?
224 if (edgePair.begin() == edgePair.end())
226 // Error message
227 errors.MainError = CLigoError::NoEdgeVertices;
228 return false;
231 // Build the linked segments
232 list<list<uint> > segmentList;
233 multimap<uint, uint>::iterator currentVert = edgePair.begin();
235 // For each remaining segment
236 while (currentVert != edgePair.end())
238 // Get next vert
239 uint first = currentVert->first;
240 uint next = currentVert->second;
242 // New list
243 segmentList.push_front (list<uint>());
244 list<uint> &listVert = *segmentList.begin();
246 // Put the first vertices of the edge list
247 listVert.push_back (first);
248 listVert.push_back (next);
250 // Erase it and
251 edgePair.erase (currentVert);
253 // Erase the reverse one
254 currentVert = edgePairReverse.find (next);
255 nlassert (currentVert != edgePairReverse.end());
256 edgePairReverse.erase (currentVert);
258 // Look forward
259 currentVert = edgePair.find (next);
260 while (currentVert != edgePair.end())
262 // Backup
263 //uint current = currentVert->first;
264 next = currentVert->second;
266 // Push the next vertex
267 listVert.push_back (next);
269 // Erase it and
270 edgePair.erase (currentVert);
272 // Erase the reverse one
273 currentVert = edgePairReverse.find (next);
274 nlassert (currentVert != edgePairReverse.end());
275 edgePairReverse.erase (currentVert);
277 // Look forward
278 currentVert = edgePair.find (next);
281 // Edgelist ok ?
282 if (next != first)
284 // No, look backward
285 currentVert = edgePairReverse.find (first);
286 while (currentVert != edgePairReverse.end())
288 // Backup
289 uint current = currentVert->second;
290 next = currentVert->first;
292 // Push the next vertex
293 listVert.push_front (current);
295 // Erase it
296 edgePairReverse.erase (currentVert);
298 // Erase the reverse one
299 currentVert = edgePair.find (current);
300 nlassert (currentVert != edgePair.end());
301 edgePair.erase (currentVert);
303 // Look forward
304 currentVert = edgePairReverse.find (current);
308 // Next edge list
309 currentVert = edgePair.begin();
312 // ** Error traitment
314 // Ok
315 bool ok = true;
317 // Edge index
318 uint edgeIndex = 0;
320 // List ok ?
321 list<list<uint> >::iterator iteList = segmentList.begin ();
322 while (iteList != segmentList.end())
324 // Only one list
325 list<uint> &listVert = *iteList;
327 // First and last edge
328 uint first = *listVert.begin();
329 uint last = *(--listVert.end());
331 // Opened edge ?
332 if ( first != last )
334 // Opened edge
335 errors.pushVertexError (CLigoError::OpenedEdge, first, edgeIndex);
336 errors.pushVertexError (CLigoError::OpenedEdge, last, edgeIndex);
338 // Main error
339 errors.MainError = CLigoError::OpenedEdge;
341 // Not ko
342 ok = false;
345 // Next edge list
346 edgeIndex++;
347 iteList++;
350 if (segmentList.size () > 1)
352 // Main error
353 errors.MainError = CLigoError::MultipleEdge;
355 // Not ok
356 ok = false;
359 // Ok ?
360 if (ok)
362 // Only one list
363 list<uint> &listVert = *segmentList.begin ();
365 // Test vertex enchainement
366 list<uint>::iterator vertIte = listVert.begin();
368 // Current vertex id
369 uint previous = *(--listVert.end());
370 vertIte++;
372 // Error vertex set
373 set<uint> errored;
375 // For each vertices
376 while (vertIte != listVert.end ())
378 // Vertex id
379 uint next = *vertIte;
381 // Common flags
382 uint commonFlags = boundaryFlags[previous]&boundaryFlags[next];
384 // The both on X ?
385 if ( commonFlags & SnappedXFlag )
387 // Get x index
388 sint32 prevIndex = getSnappedIndex (vertices[previous].x, config.CellSize, config.Snap);
389 sint32 nextIndex = getSnappedIndex (vertices[next].x, config.CellSize, config.Snap);
391 // Not the same ?
392 if (prevIndex != nextIndex)
394 // Vertex list error
395 if (errored.insert (previous).second)
396 errors.pushVertexError (CLigoError::VertexList, previous, 0);
397 if (errored.insert (next).second)
398 errors.pushVertexError (CLigoError::VertexList, next, 0);
400 // Main error
401 errors.MainError = CLigoError::VertexList;
405 // Next vertex
406 previous = next;
407 vertIte++;
410 // No error ?
411 if (errored.empty())
413 // Only one list
414 nlassert (segmentList.size()==1);
416 // First of the list
417 vertIte = listVert.begin();
419 // Remove first
420 listVert.erase (vertIte);
422 // Find a corner
423 list<uint>::iterator firstIte = listVert.begin();
424 while (firstIte != listVert.end())
426 // Corner ?
427 if ( (boundaryFlags[*firstIte] & (SnappedXFlag|SnappedYFlag)) == (SnappedXFlag|SnappedYFlag) )
428 // Yes, exit
429 break;
431 // Next
432 firstIte++;
435 // Can't be the last
436 if (firstIte == listVert.end())
438 // No corner found
439 errors.MainError = CLigoError::NoCornerFound;
441 return false;
444 // First of the segment
445 vertIte = firstIte;
447 // Current edge list
448 std::vector<uint32> edge;
450 // Push the first
451 edge.push_back (*vertIte);
453 // Next
454 vertIte++;
456 // End ?
457 if (vertIte == listVert.end())
458 // Start
459 vertIte = listVert.begin();
461 // Edge index
462 uint edgeIndex = 0;
464 // Build the edges
465 for(;;)
467 // Add it
468 edge.push_back (*vertIte);
470 // Corner ?
471 if ( (boundaryFlags[*vertIte] & (SnappedXFlag|SnappedYFlag)) == (SnappedXFlag|SnappedYFlag) )
473 // Get the index of start and end of the edge
474 sint32 startX = getSnappedIndex (vertices[edge[0]].x, config.CellSize, config.Snap);
475 sint32 startY = getSnappedIndex (vertices[edge[0]].y, config.CellSize, config.Snap);
476 sint32 endX = getSnappedIndex (vertices[edge[edge.size()-1]].x, config.CellSize, config.Snap);
477 sint32 endY = getSnappedIndex (vertices[edge[edge.size()-1]].y, config.CellSize, config.Snap);
479 // Same point ?
480 if ((startX==endX) && (startY==endY))
482 // Error, two times the same vertex
483 errors.MainError = CLigoError::TwoCornerVertices;
484 errors.pushVertexError (CLigoError::TwoCornerVertices, edge[0], 0);
485 errors.pushVertexError (CLigoError::TwoCornerVertices, edge[edge.size()-1], 0);
487 return false;
490 // Same point ?
491 if ((abs(startX-endX)>1) || (abs(startY-endY)>1))
493 // Error, two times the same vertex
494 errors.MainError = CLigoError::CornerIsMissing;
495 errors.pushVertexError (CLigoError::CornerIsMissing, edge[0], 0);
496 errors.pushVertexError (CLigoError::CornerIsMissing, edge[edge.size()-1], 0);
498 return false;
501 // Get rotation
502 uint rotation = 4;
503 if ((endX-startX)==1)
505 if ((endY-startY)==0)
506 rotation = 0;
508 else if ((endX-startX)==-1)
510 if ((endY-startY)==0)
511 rotation = 2;
513 else if ((endX-startX)==0)
515 if ((endY-startY)==1)
516 rotation = 1;
517 else if ((endY-startY)==-1)
518 rotation = 3;
521 // Checks
522 nlassert (rotation != 4);
524 // Build the vertex array
525 vector<CVector> vertexArray;
526 vertexArray.resize (edge.size());
528 // Rotate matrix
529 CMatrix mat;
530 mat.identity();
531 mat.rotateZ ((float)rotation * (float)Pi / 2);
532 mat.setPos (CVector (vertices[edge[0]].x, vertices[edge[0]].y, 0));
533 mat.invert ();
535 // Rotate the array
536 for (uint i=0; i<edge.size(); i++)
538 // Get the value on the edge
539 vertexArray[i] = mat * vertices[edge[i]];
542 // Build the edge
543 _Edges.resize (edgeIndex+1);
545 // It must work without errors
546 CLigoError errorBis;
547 if (!_Edges[edgeIndex].build (vertexArray, edge, rotation, startX, startY, config, errorBis))
549 // Flat zone
550 errors.MainError = CLigoError::FlatZone;
552 return false;
555 // One more edge
556 edgeIndex++;
558 // Exit ?
559 if (vertIte == firstIte)
560 break;
562 // Clear the temp edge
563 edge.clear ();
565 // Push back the last vertex
566 edge.push_back (*vertIte);
569 // Next vertex
570 vertIte++;
572 // End ?
573 if (vertIte == listVert.end())
574 // Start
575 vertIte = listVert.begin();
578 sint32 bestX = 0x7fffffff;
579 sint32 bestY = 0x80000000;
580 uint bestEdge = 0xffffffff;
582 // Sort edges : the first as the lower x then greater y
583 uint edgeId;
584 for (edgeId=0; edgeId<_Edges.size(); edgeId++)
586 // Get the matrix
587 CMatrix mat;
588 _Edges[edgeId].buildMatrix (mat, config);
590 // First vertex
591 CVector pos = mat * _Edges[edgeId].getVertex (0);
593 // Get X and Y
594 sint32 x = getSnappedIndex (pos.x, config.CellSize, config.Snap);
595 sint32 y = getSnappedIndex (pos.y, config.CellSize, config.Snap);
597 // Best ?
598 if ((x<bestX)||((x==bestX)&&(y>bestY)))
600 // This edgeId is best
601 bestX=x;
602 bestY=y;
603 bestEdge = edgeId;
607 // Check
608 nlassert (bestEdge!=0xffffffff);
610 // Reoder
611 std::vector<CZoneEdge> newEdge (_Edges.size());
612 for (edgeId=0; edgeId<_Edges.size(); edgeId++)
614 // Copy the edge
615 newEdge[edgeId]=_Edges[bestEdge++];
617 // Next
618 if (bestEdge==_Edges.size())
619 bestEdge=0;
622 // Copy the final array
623 _Edges=newEdge;
625 // Return ok
626 return true;
630 // Errors.
631 return false;
634 // ***************************************************************************
636 void CZoneTemplate::serial (NLMISC::IStream& s)
638 // open an XML node
639 s.xmlPush ("LIGO_ZONE_TEMPLATE");
641 // An header file
642 s.serialCheck (string ("LigoZoneTemplate") );
644 // Node for the boundaries
645 s.xmlPush ("EDGES");
647 // Serial the Vertices
648 s.serialCont (_Edges);
650 // Node for the boundaries
651 s.xmlPop ();
653 // Close the node
654 s.xmlPop ();
657 // ***************************************************************************
659 void CZoneTemplate::getMask (std::vector<bool> &mask, uint &width, uint &height)
661 // Some constantes
662 static const sint32 addX[4] = { 1, 0, -1, 0 };
663 static const sint32 addY[4] = { 0, 1, 0, -1 };
664 static const sint32 cellX[4] = { 0, -1, -1, 0 };
665 static const sint32 cellY[4] = { 0, 0, -1, -1 };
666 static const sint32 moveX[4] = { 0, 1, 0, -1 };
667 static const sint32 moveY[4] = { -1, 0, 1, 0 };
669 // Max
670 sint32 xMax = 0x80000000;
671 sint32 yMax = 0x80000000;
673 // For each edges
674 uint edges;
675 for (edges=0; edges<_Edges.size(); edges++)
677 // Get the rotation
678 uint32 rot = _Edges[edges].getRotation ();
679 nlassert (rot<4);
681 // Get X and Y max coordinates
682 sint32 x = _Edges[edges].getOffsetX () + addX[rot];
683 sint32 y = _Edges[edges].getOffsetY () + addY[rot];
685 // Greater ?
686 if (x > xMax)
687 xMax = x;
688 if (y > yMax)
689 yMax = y;
692 // Build the array
693 width = (uint32) xMax;
694 height = (uint32) yMax;
696 // Bit array for each cell
697 vector<uint32> edgeArray (xMax*yMax, 0);
699 // Resize it
700 mask.resize (xMax*yMax, false);
702 // Set of the cells in the mask
703 set<pair<sint32, sint32> > setCell;
705 // For each edge
706 for (edges=0; edges<_Edges.size(); edges++)
708 // Get the rotation
709 uint32 rot = _Edges[edges].getRotation ();
710 nlassert (rot<4);
712 // Get its x and y cell coordinate
713 sint32 x = _Edges[edges].getOffsetX () + cellX[rot];
714 sint32 y = _Edges[edges].getOffsetY () + cellY[rot];
716 // Fill the edge array
717 edgeArray[x+y*width] |= (1<<rot);
719 // Insert the cell
720 setCell.insert ( pair<sint32, sint32> (x, y) );
723 // Second set
724 set<pair<sint32, sint32> > setCell2;
726 // For each element in the set
727 set<pair<sint32, sint32> >::iterator ite = setCell.begin();
728 while (ite != setCell.end())
730 // For each direction
731 for (uint dir=0; dir<4; dir++)
733 // Get its x and y cell coordinate
734 sint32 x = ite->first;
735 sint32 y = ite->second;
737 // Edge in this direction ?
738 while ( (edgeArray[x+y*width] & (1<<dir) ) == 0)
740 // Move in this direction
741 x += moveX[dir];
742 y += moveY[dir];
744 // insert it
745 setCell2.insert ( pair<sint32, sint32> (x, y) );
747 // Some checks
748 nlassert (x>=0);
749 nlassert (x<(sint32)width);
750 nlassert (y>=0);
751 nlassert (y<(sint32)height);
755 // Next one
756 ite++;
759 // Merge the two set
760 ite = setCell2.begin();
761 while (ite != setCell2.end())
763 // Merge
764 setCell.insert (*ite);
766 // Next element
767 ite++;
770 // Done, fill the array
771 ite = setCell.begin();
772 while (ite != setCell.end())
774 // Merge
775 mask[ite->first+ite->second*width] = true;
777 // Next element
778 ite++;
782 // ***************************************************************************