1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
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/>.
19 #ifndef NL_MOVE_GRID_H
20 #define NL_MOVE_GRID_H
22 #include "nel/misc/types_nl.h"
23 #include "nel/misc/vector.h"
24 #include "nel/misc/aabbox.h"
25 #include "nel/misc/block_memory.h"
26 #include "nel/misc/stream.h"
29 * A list of object that must have Next and Previous pointers
30 * \param T the type of item
31 * \param TPtr a pointer to T to use in list (useful for smartpointer)
34 class CMoveGridObjectList
40 CMoveGridObjectList() : Head(NULL
), Tail(NULL
) {}
42 void insertAtHead(TT
*object
)
44 nlassert(object
->Next
== NULL
);
45 nlassert(object
->Previous
== NULL
);
48 if (object
->Next
!= NULL
)
49 object
->Next
->Previous
= object
;
55 void insertAtTail(TT
*object
)
57 nlassert(object
->Next
== NULL
);
58 nlassert(object
->Previous
== NULL
);
60 object
->Previous
= Tail
;
61 if (object
->Previous
!= NULL
)
62 object
->Previous
->Next
= object
;
68 void remove(TT
*object
)
71 if (object
->Previous
== NULL
)
74 object
->Previous
->Next
= object
->Next
;
77 if (object
->Next
== NULL
)
78 Tail
= object
->Previous
;
80 object
->Next
->Previous
= object
->Previous
;
82 object
->Previous
= NULL
;
86 TT
*getHead() { return (TT
*)Head
; }
87 TT
*getTail() { return (TT
*)Tail
; }
91 * Move grid, allows to select moving entities fast (template parameter CSIZE is in millimeter)
92 * \author Benjamin Legros
93 * \author Nevrax France
96 template<typename T
, int CELLS
, int CSIZE
>
101 friend class CIterator
;
119 /// Insert an element in move grid. Return an iterator towards the inserted object
120 CIterator
insert(const T
&object
, const NLMISC::CVector
&position
);
123 /// Move an object in grid.
124 void move(CIterator
&it
, const NLMISC::CVector
&position
);
128 void remove(CIterator
&it
);
129 void insertNode(CIterator
&it
, sint x
, sint y
);
130 void removeNode(CIterator
&it
);
134 void select(const NLMISC::CVector
&position
);
137 void select(const NLMISC::CAABBox
&bbox
);
146 void clearSelection();
148 /// round value so it is a half of a segment
149 double round(double v
)
151 const double INV
= 1000.0 / (double)CSIZE
;
152 return (floor(v
*INV
)+0.5)*(double)CSIZE
*0.001;
156 void serial(NLMISC::IStream
&f
);
159 sint
convert(float v
)
161 const float INV
= 1000.0f
/ (float)CSIZE
;
162 return (sint
)(v
*INV
);
165 sint
convertGrid(float v
)
167 const float INV
= 1000.0f
/ (float)CSIZE
;
168 return (sint
)(v
*INV
)&(CELLS
-1);
171 sint
convertGrid(sint v
)
176 void select(sint X
, sint Y
);
181 /// A node that contains an objects.
182 typedef CMoveGridObjectList
<CNode
> TNodeList
;
183 /// A node that is a cell, containing a list of node inside this cell.
184 typedef CMoveGridObjectList
<CCellNode
> TCellNodeList
;
194 CCellNode
*Previous
, *Next
;
195 CCellNode
*Selection
;
197 CCellNode() : X(0), Y(0), GridX(0), GridY(0), Previous(NULL
), Next(NULL
), Selection(NULL
) {}
199 void serial(NLMISC::IStream
&f
)
201 f
.serial(X
, Y
, GridX
, GridY
);
208 CNode
*Previous
, *Next
;
212 CNode() : Previous(NULL
), Next(NULL
), Root(NULL
) {}
214 void serial(NLMISC::IStream
&f
)
220 /// The map of cell nodes
221 TCellNodeList _Grid
[CELLS
][CELLS
];
223 /// The first selected cell node
224 CCellNode
*_Selection
;
226 /// The allocator of nodes
227 NLMISC::CBlockMemory
<CNode
> _NodeAllocator
;
228 /// The allocator of cell nodes
229 NLMISC::CBlockMemory
<CCellNode
> _CellNodeAllocator
;
234 friend class CMoveGrid
<T
, CELLS
, CSIZE
>;
236 CIterator(CNode
*node
= NULL
) : _Node(node
) {}
237 CIterator(const CIterator
&it
) : _Node(it
._Node
) {}
239 T
& operator * () { return _Node
->Object
; }
241 CIterator
& operator ++ ()
243 if (_Node
->Next
!= NULL
)
249 CCellNode
*nextCell
= _Node
->Root
->Selection
;
251 // iterate till we have a non empty selected cell
252 while (nextCell
!= NULL
&& (_Node
= nextCell
->NodeList
.getHead()) == NULL
)
253 nextCell
= nextCell
->Selection
;
257 CIterator
operator ++ (int)
259 CIterator
ret(_Node
);
264 bool operator == (const CIterator
&it
) const { return it
._Node
== _Node
; }
265 bool operator != (const CIterator
&it
) const { return !(*this == it
); }
267 CIterator
operator = (const CIterator
&it
) { _Node
= it
._Node
; return *this; }
275 // TEMPLATE IMPLEMENTATION
281 template<typename T
, int CELLS
, int CSIZE
>
282 void CMoveGrid
<T
, CELLS
, CSIZE
>::serial(NLMISC::IStream
&f
)
284 sint version
= f
.serialVersion(0);
285 f
.serialCheck((sint32
)CELLS
);
286 f
.serialCheck((sint32
)CSIZE
);
294 for (i
=0; i
<CELLS
; ++i
)
296 for (j
=0; j
<CELLS
; ++j
)
298 TCellNodeList
&list
= _Grid
[i
][j
];
305 cellNode
= _CellNodeAllocator
.allocate();
307 list
.insertAtTail(cellNode
);
312 node
= _NodeAllocator
.allocate();
314 cellNode
->NodeList
.insertAtTail(node
);
315 node
->Root
= cellNode
;
326 for (i
=0; i
<CELLS
; ++i
)
328 for (j
=0; j
<CELLS
; ++j
)
330 TCellNodeList
&list
= _Grid
[i
][j
];
334 cellNode
= list
.getHead();
336 while (cellNode
!= NULL
)
337 ++nc
, cellNode
= cellNode
->Next
;
340 cellNode
= list
.getHead();
341 while (cellNode
!= NULL
)
345 node
= cellNode
->NodeList
.getHead();
348 ++nn
, node
= node
->Next
;
351 node
= cellNode
->NodeList
.getHead();
358 cellNode
= cellNode
->Next
;
367 template<typename T
, int CELLS
, int CSIZE
>
368 void CMoveGrid
<T
, CELLS
, CSIZE
>::clear()
372 for (i
=0; i
<CELLS
; ++i
)
374 for (j
=0; j
<CELLS
; ++j
)
376 TCellNodeList
&list
= _Grid
[i
][j
];
379 while ((cellNode
= list
.getHead()) != NULL
)
381 while ((node
= cellNode
->NodeList
.getHead()) != NULL
)
383 cellNode
->NodeList
.remove(node
);
384 _NodeAllocator
.freeBlock(node
);
386 list
.remove(cellNode
);
387 _CellNodeAllocator
.freeBlock(cellNode
);
396 template<typename T
, int CELLS
, int CSIZE
>
397 CMoveGrid
<T
, CELLS
, CSIZE
>::CMoveGrid()
404 template<typename T
, int CELLS
, int CSIZE
>
405 CMoveGrid
<T
, CELLS
, CSIZE
>::~CMoveGrid()
411 template<typename T
, int CELLS
, int CSIZE
>
412 void CMoveGrid
<T
, CELLS
, CSIZE
>::insertNode(CIterator
&it
, sint x
, sint y
)
415 gridX
= convertGrid(x
);
416 gridY
= convertGrid(y
);
418 CCellNode
*cellNode
= _Grid
[gridX
][gridY
].getHead();
419 while (cellNode
!= NULL
&& (cellNode
->X
!= x
|| cellNode
->Y
!= y
))
420 cellNode
= cellNode
->Next
;
422 if (cellNode
== NULL
)
424 cellNode
= _CellNodeAllocator
.allocate();
425 _Grid
[gridX
][gridY
].insertAtHead(cellNode
);
428 cellNode
->GridX
= gridX
;
429 cellNode
->GridY
= gridY
;
432 it
._Node
->Root
= cellNode
;
433 cellNode
->NodeList
.insertAtHead(it
._Node
);
437 template<typename T
, int CELLS
, int CSIZE
>
438 void CMoveGrid
<T
, CELLS
, CSIZE
>::removeNode(CIterator
&it
)
440 it
._Node
->Root
->NodeList
.remove(it
._Node
);
444 template<typename T
, int CELLS
, int CSIZE
>
445 typename::CMoveGrid
<T
, CELLS
, CSIZE
>::CIterator CMoveGrid
<T
, CELLS
, CSIZE
>::insert(const T
&object
, const NLMISC::CVector
&position
)
447 CNode
*node
= _NodeAllocator
.allocate();
451 X
= convert(position
.x
);
452 Y
= convert(position
.y
);
453 node
->Object
= object
;
456 insertNode(it
, X
, Y
);
458 return CIterator(node
);
461 template<typename T
, int CELLS
, int CSIZE
>
462 void CMoveGrid
<T
, CELLS
, CSIZE
>::move(CIterator
&it
, const NLMISC::CVector
&position
)
465 X
= convert(position
.x
);
466 Y
= convert(position
.y
);
468 CNode
*node
= it
._Node
;
470 if (X
== node
->Root
->X
&& Y
== node
->Root
->Y
)
474 insertNode(it
, X
, Y
);
477 template<typename T
, int CELLS
, int CSIZE
>
478 void CMoveGrid
<T
, CELLS
, CSIZE
>::remove(CIterator
&it
)
480 CNode
*node
= it
._Node
;
485 _NodeAllocator
.freeBlock(node
);
489 template<typename T
, int CELLS
, int CSIZE
>
490 void CMoveGrid
<T
, CELLS
, CSIZE
>::select(const NLMISC::CVector
&position
)
492 select(convert(position
.x
), convert(position
.y
));
495 template<typename T
, int CELLS
, int CSIZE
>
496 void CMoveGrid
<T
, CELLS
, CSIZE
>::select(const NLMISC::CAABBox
&bbox
)
501 x0
= convert(bbox
.getCenter().x
-bbox
.getHalfSize().x
);
502 x1
= convert(bbox
.getCenter().x
+bbox
.getHalfSize().x
);
504 y0
= convert(bbox
.getCenter().y
-bbox
.getHalfSize().y
);
505 y1
= convert(bbox
.getCenter().y
+bbox
.getHalfSize().y
);
509 for (y
=y0
; y
<=y1
; ++y
)
510 for (x
=x0
; x
<=x1
; ++x
)
514 template<typename T
, int CELLS
, int CSIZE
>
515 void CMoveGrid
<T
, CELLS
, CSIZE
>::select(sint x
, sint y
)
517 sint gx
= convertGrid(x
),
520 CCellNode
*cellNode
= _Grid
[gx
][gy
].getHead();
521 while (cellNode
!= NULL
&& (cellNode
->X
!= x
|| cellNode
->Y
!= y
))
522 cellNode
= cellNode
->Next
;
524 if (cellNode
!= NULL
&& cellNode
->NodeList
.getHead() != NULL
)
526 cellNode
->Selection
= _Selection
;
527 _Selection
= cellNode
;
531 template<typename T
, int CELLS
, int CSIZE
>
532 typename::CMoveGrid
<T
, CELLS
, CSIZE
>::CIterator CMoveGrid
<T
, CELLS
, CSIZE
>::begin()
534 return (_Selection
!= NULL
) ? CIterator(_Selection
->NodeList
.getHead()) : CIterator(NULL
);
537 template<typename T
, int CELLS
, int CSIZE
>
538 typename::CMoveGrid
<T
, CELLS
, CSIZE
>::CIterator CMoveGrid
<T
, CELLS
, CSIZE
>::end()
540 return CIterator(NULL
);
543 template<typename T
, int CELLS
, int CSIZE
>
544 void CMoveGrid
<T
, CELLS
, CSIZE
>::clearSelection()
546 CCellNode
*cellNode
= _Selection
;
549 while (cellNode
!= NULL
)
551 CCellNode
*nd
= cellNode
;
552 cellNode
= cellNode
->Selection
;
553 nd
->Selection
= NULL
;
558 #endif // NL_MOVE_GRID_H
560 /* End of move_grid.h */