1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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"
26 using namespace NLMISC
;
31 const uint SnappedXFlag
= 1;
32 const uint SnappedYFlag
= 2;
34 // ***************************************************************************
36 inline void CZoneTemplate::snap (float& value
, float snap
)
39 value
= snap
* (float) floor ( (value
/ snap
) + 0.5f
);
42 // ***************************************************************************
44 inline bool CZoneTemplate::snapOnGrid (float& value
, float resolution
, float snap
)
47 float _floor
= (float) ( resolution
* floor (value
/ resolution
) );
48 nlassert (_floor
<=value
);
51 float remainder
= value
- _floor
;
52 //nlassert ( (remainder>=0) && (remainder<resolution) );
55 if ( remainder
<= snap
)
63 else if ( (resolution
- remainder
) <= snap
)
66 value
= _floor
+ resolution
;
68 // Floor + resolution is good
74 // ***************************************************************************
76 inline bool CZoneTemplate::isSnapedOnGrid (float value
, float resolution
, float snap
)
79 float snapped
= value
;
80 return snapOnGrid (snapped
, resolution
, snap
);
83 // ***************************************************************************
85 inline sint32
CZoneTemplate::getSnappedIndex (float value
, float resolution
, float snap
)
88 float snapped
= value
;
90 // This value must be snapped
91 nlverify (snapOnGrid (snapped
, resolution
, snap
));
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
104 // Make an boundary flag array
105 vector
<uint
> boundaryFlags
;
108 uint vertexCount
= (uint
)vertices
.size();
111 boundaryFlags
.resize (vertexCount
, 0);
113 // *** Build the flag array and the snapped vertex array
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
))
122 boundaryFlags
[vertex
]|=SnappedXFlag
;
124 // Snap the point on the Y grid
125 if (isSnapedOnGrid (vertices
[vertex
].y
, config
.CellSize
, config
.Snap
))
127 boundaryFlags
[vertex
]|=SnappedYFlag
;
130 // *** Build the edge set
131 multimap
<uint
, uint
> edgePair
;
132 multimap
<uint
, uint
> edgePairReverse
;
135 uint edgeCount
= (uint
)indexes
.size();
139 for (edge
= 0; edge
< edgeCount
; edge
++)
142 const pair
<uint
, uint
> &theEdge
= indexes
[edge
];
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 ?
156 // Snapped both on X ?
157 if ( common
& SnappedXFlag
)
163 // Snapped both on X ?
164 if ( common
& SnappedYFlag
)
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
180 // Error, two times the same vertex
181 errors
.MainError
= CLigoError::VertexAlreadyUsed
;
184 errors
.pushVertexError (CLigoError::VertexAlreadyUsed
, theEdge
.first
, 0);
187 errors
.pushVertexError (CLigoError::VertexAlreadyUsed
, theEdge
.second
, 0);
192 if ((!first
) && (!second
))
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
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);
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())
227 errors
.MainError
= CLigoError::NoEdgeVertices
;
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())
239 uint first
= currentVert
->first
;
240 uint next
= currentVert
->second
;
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
);
251 edgePair
.erase (currentVert
);
253 // Erase the reverse one
254 currentVert
= edgePairReverse
.find (next
);
255 nlassert (currentVert
!= edgePairReverse
.end());
256 edgePairReverse
.erase (currentVert
);
259 currentVert
= edgePair
.find (next
);
260 while (currentVert
!= edgePair
.end())
263 //uint current = currentVert->first;
264 next
= currentVert
->second
;
266 // Push the next vertex
267 listVert
.push_back (next
);
270 edgePair
.erase (currentVert
);
272 // Erase the reverse one
273 currentVert
= edgePairReverse
.find (next
);
274 nlassert (currentVert
!= edgePairReverse
.end());
275 edgePairReverse
.erase (currentVert
);
278 currentVert
= edgePair
.find (next
);
285 currentVert
= edgePairReverse
.find (first
);
286 while (currentVert
!= edgePairReverse
.end())
289 uint current
= currentVert
->second
;
290 next
= currentVert
->first
;
292 // Push the next vertex
293 listVert
.push_front (current
);
296 edgePairReverse
.erase (currentVert
);
298 // Erase the reverse one
299 currentVert
= edgePair
.find (current
);
300 nlassert (currentVert
!= edgePair
.end());
301 edgePair
.erase (currentVert
);
304 currentVert
= edgePairReverse
.find (current
);
309 currentVert
= edgePair
.begin();
312 // ** Error traitment
321 list
<list
<uint
> >::iterator iteList
= segmentList
.begin ();
322 while (iteList
!= segmentList
.end())
325 list
<uint
> &listVert
= *iteList
;
327 // First and last edge
328 uint first
= *listVert
.begin();
329 uint last
= *(--listVert
.end());
335 errors
.pushVertexError (CLigoError::OpenedEdge
, first
, edgeIndex
);
336 errors
.pushVertexError (CLigoError::OpenedEdge
, last
, edgeIndex
);
339 errors
.MainError
= CLigoError::OpenedEdge
;
350 if (segmentList
.size () > 1)
353 errors
.MainError
= CLigoError::MultipleEdge
;
363 list
<uint
> &listVert
= *segmentList
.begin ();
365 // Test vertex enchainement
366 list
<uint
>::iterator vertIte
= listVert
.begin();
369 uint previous
= *(--listVert
.end());
376 while (vertIte
!= listVert
.end ())
379 uint next
= *vertIte
;
382 uint commonFlags
= boundaryFlags
[previous
]&boundaryFlags
[next
];
385 if ( commonFlags
& SnappedXFlag
)
388 sint32 prevIndex
= getSnappedIndex (vertices
[previous
].x
, config
.CellSize
, config
.Snap
);
389 sint32 nextIndex
= getSnappedIndex (vertices
[next
].x
, config
.CellSize
, config
.Snap
);
392 if (prevIndex
!= nextIndex
)
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);
401 errors
.MainError
= CLigoError::VertexList
;
414 nlassert (segmentList
.size()==1);
417 vertIte
= listVert
.begin();
420 listVert
.erase (vertIte
);
423 list
<uint
>::iterator firstIte
= listVert
.begin();
424 while (firstIte
!= listVert
.end())
427 if ( (boundaryFlags
[*firstIte
] & (SnappedXFlag
|SnappedYFlag
)) == (SnappedXFlag
|SnappedYFlag
) )
436 if (firstIte
== listVert
.end())
439 errors
.MainError
= CLigoError::NoCornerFound
;
444 // First of the segment
448 std::vector
<uint32
> edge
;
451 edge
.push_back (*vertIte
);
457 if (vertIte
== listVert
.end())
459 vertIte
= listVert
.begin();
468 edge
.push_back (*vertIte
);
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
);
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);
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);
503 if ((endX
-startX
)==1)
505 if ((endY
-startY
)==0)
508 else if ((endX
-startX
)==-1)
510 if ((endY
-startY
)==0)
513 else if ((endX
-startX
)==0)
515 if ((endY
-startY
)==1)
517 else if ((endY
-startY
)==-1)
522 nlassert (rotation
!= 4);
524 // Build the vertex array
525 vector
<CVector
> vertexArray
;
526 vertexArray
.resize (edge
.size());
531 mat
.rotateZ ((float)rotation
* (float)Pi
/ 2);
532 mat
.setPos (CVector (vertices
[edge
[0]].x
, vertices
[edge
[0]].y
, 0));
536 for (uint i
=0; i
<edge
.size(); i
++)
538 // Get the value on the edge
539 vertexArray
[i
] = mat
* vertices
[edge
[i
]];
543 _Edges
.resize (edgeIndex
+1);
545 // It must work without errors
547 if (!_Edges
[edgeIndex
].build (vertexArray
, edge
, rotation
, startX
, startY
, config
, errorBis
))
550 errors
.MainError
= CLigoError::FlatZone
;
559 if (vertIte
== firstIte
)
562 // Clear the temp edge
565 // Push back the last vertex
566 edge
.push_back (*vertIte
);
573 if (vertIte
== listVert
.end())
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
584 for (edgeId
=0; edgeId
<_Edges
.size(); edgeId
++)
588 _Edges
[edgeId
].buildMatrix (mat
, config
);
591 CVector pos
= mat
* _Edges
[edgeId
].getVertex (0);
594 sint32 x
= getSnappedIndex (pos
.x
, config
.CellSize
, config
.Snap
);
595 sint32 y
= getSnappedIndex (pos
.y
, config
.CellSize
, config
.Snap
);
598 if ((x
<bestX
)||((x
==bestX
)&&(y
>bestY
)))
600 // This edgeId is best
608 nlassert (bestEdge
!=0xffffffff);
611 std::vector
<CZoneEdge
> newEdge (_Edges
.size());
612 for (edgeId
=0; edgeId
<_Edges
.size(); edgeId
++)
615 newEdge
[edgeId
]=_Edges
[bestEdge
++];
618 if (bestEdge
==_Edges
.size())
622 // Copy the final array
634 // ***************************************************************************
636 void CZoneTemplate::serial (NLMISC::IStream
& s
)
639 s
.xmlPush ("LIGO_ZONE_TEMPLATE");
642 s
.serialCheck (string ("LigoZoneTemplate") );
644 // Node for the boundaries
647 // Serial the Vertices
648 s
.serialCont (_Edges
);
650 // Node for the boundaries
657 // ***************************************************************************
659 void CZoneTemplate::getMask (std::vector
<bool> &mask
, uint
&width
, uint
&height
)
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 };
670 sint32 xMax
= 0x80000000;
671 sint32 yMax
= 0x80000000;
675 for (edges
=0; edges
<_Edges
.size(); edges
++)
678 uint32 rot
= _Edges
[edges
].getRotation ();
681 // Get X and Y max coordinates
682 sint32 x
= _Edges
[edges
].getOffsetX () + addX
[rot
];
683 sint32 y
= _Edges
[edges
].getOffsetY () + addY
[rot
];
693 width
= (uint32
) xMax
;
694 height
= (uint32
) yMax
;
696 // Bit array for each cell
697 vector
<uint32
> edgeArray (xMax
*yMax
, 0);
700 mask
.resize (xMax
*yMax
, false);
702 // Set of the cells in the mask
703 set
<pair
<sint32
, sint32
> > setCell
;
706 for (edges
=0; edges
<_Edges
.size(); edges
++)
709 uint32 rot
= _Edges
[edges
].getRotation ();
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
);
720 setCell
.insert ( pair
<sint32
, sint32
> (x
, y
) );
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
745 setCell2
.insert ( pair
<sint32
, sint32
> (x
, y
) );
749 nlassert (x
<(sint32
)width
);
751 nlassert (y
<(sint32
)height
);
760 ite
= setCell2
.begin();
761 while (ite
!= setCell2
.end())
764 setCell
.insert (*ite
);
770 // Done, fill the array
771 ite
= setCell
.begin();
772 while (ite
!= setCell
.end())
775 mask
[ite
->first
+ite
->second
*width
] = true;
782 // ***************************************************************************