// Ryzom - 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 . #ifndef NL_MOVE_GRID_H #define NL_MOVE_GRID_H #include "nel/misc/types_nl.h" #include "nel/misc/vector.h" #include "nel/misc/aabbox.h" #include "nel/misc/block_memory.h" /** * A list of object that must have Next and Previous pointers * \param T the type of item * \param TPtr a pointer to T to use in list (useful for smartpointer) */ template class CObjectList { public: TPtr Head; TPtr Tail; CObjectList() : Head(NULL), Tail(NULL) {} void insertAtHead(T *object) { nlassert(object->Next == NULL); nlassert(object->Previous == NULL); object->Next = Head; if (object->Next != NULL) object->Next->Previous = object; Head = object; } void insertAtTail(T *object) { nlassert(object->Next == NULL); nlassert(object->Previous == NULL); object->Previous = Tail; if (object->Previous != NULL) object->Previous->Next = object; Tail = object; } void remove(T *object) { // if object at head if (object->Previous == NULL) Head = object->Next; else object->Previous->Next = object->Next; // if object at tail if (object->Next == NULL) Tail = object->Previous; else object->Next->Previous = object->Previous; object->Previous = NULL; object->Next = NULL; } T *getHead() { return (T*)Head; } T *getTail() { return (T*)Tail; } }; /** * * \author Benjamin Legros * \author Nevrax France * \date 2001 */ template class CMoveGrid { public: class CIterator; friend class CIterator; protected: class CNode; public: /// Constructor CMoveGrid(); /// Destructor ~CMoveGrid(); /// Insert CIterator insert(const T &object, const NLMISC::CVector &position); /// Move void move(CIterator &it, const NLMISC::CVector &position); /// Remove void remove(CIterator &it); /// select void select(const NLMISC::CVector &position); /// select void select(const NLMISC::CAABBox &bbox); /// begin CIterator begin(); /// end CIterator end(); /// clearSelection void clearSelection(); protected: sint convert(float v) { const float INV = 1.0f / CSIZE; return (sint)(v*INV); } sint convertGrid(float v) { const float INV = 1.0f / CSIZE; return (sint)(v*INV)&(CELLS-1); } sint convertGrid(sint v) { return v&(CELLS-1); } void select(sint X, sint Y); protected: class CNode { public: sint X, Y; sint GridX, GridY; CNode *Previous, *Next; CNode *Selection; T Object; CNode() : X(0), Y(0), GridX(0), GridY(0), Previous(NULL), Next(NULL), Selection(NULL) {} }; typedef CObjectList TNodeList; TNodeList _Grid[CELLS][CELLS]; NLMISC::CBlockMemory _NodeAllocator; CNode *_Selection; public: class CIterator { friend class CMoveGrid; public: CIterator(CNode *node = NULL) : _Node(node) {} CIterator(const CIterator &it) : _Node(it._Node) {} T & operator * () { return _Node->Object; } CIterator & operator ++ () { _Node = _Node->Selection; return *this; } CIterator operator ++ (int) { CIterator ret(_Node); _Node = _Node->Selection; return ret; } bool operator == (const CIterator &it) { return it._Node == _Node; } bool operator != (const CIterator &it) { return !(*this == it); } CIterator operator = (const CIterator &it) { _Node = it._Node; return *this; } protected: CNode *_Node; }; }; // // TEMPLATE IMPLEMENTATION // // template CMoveGrid::CMoveGrid() { _Selection = NULL; } // template CMoveGrid::~CMoveGrid() { sint i, j; for (i=0; i CMoveGrid::CIterator CMoveGrid::insert(const T &object, const NLMISC::CVector &position) { CNode *node = _NodeAllocator.allocate(); node->Object = object; node->X = convert(position.x); node->Y = convert(position.y); node->GridX = convertGrid(node->X); node->GridY = convertGrid(node->Y); _Grid[node->GridX][node->GridY].insertAtHead(node); return CIterator(node); } template void CMoveGrid::move(CIterator &it, const NLMISC::CVector &position) { sint X, Y; CNode *node = it._Node; X = convert(position.x); Y = convert(position.y); if (X == node->X && Y == node->Y) return; _Grid[node->GridX][node->GridY].remove(node); node->X = X; node->Y = Y; node->GridX = convertGrid(X); node->GridY = convertGrid(Y); _Grid[node->GridX][node->GridY].insertAtHead(node); } template void CMoveGrid::remove(CIterator &it) { CNode *node = it._Node; _Grid[node->GridX][node->GridY].remove(node); it._Node = NULL; _NodeAllocator.free(node); } template void CMoveGrid::select(const NLMISC::CVector &position) { sint X, Y; select(convert(position.x), convert(position.y)); } template void CMoveGrid::select(const NLMISC::CAABBox &bbox) { sint x0, x1; sint y0, y1; x0 = convert(bbox.getCenter().x-bbox.getHalfSize().x); x1 = convert(bbox.getCenter().x+bbox.getHalfSize().x); y0 = convert(bbox.getCenter().y-bbox.getHalfSize().y); y1 = convert(bbox.getCenter().y+bbox.getHalfSize().y); sint x, y; for (y=y0; y<=y1; ++y) for (x=x0; x<=x1; ++x) select(x, y); } template void CMoveGrid::select(sint x, sint y) { sint gx = convertGrid(x), gy = convertGrid(y); CNode *node = _Grid[gx][gy].getHead(); while (node != NULL) { if (node->X == x && node->Y == y && node->Selection == NULL) { node->Selection = _Selection; _Selection = node; } node = node->Next; } } template CMoveGrid::CIterator CMoveGrid::begin() { return CIterator(_Selection); } template CMoveGrid::CIterator CMoveGrid::end() { return CIterator(NULL); } template void CMoveGrid::clearSelection() { CNode *node = _Selection; _Selection = NULL; while (node != NULL) { CNode *nd = node; node = node->Selection; nd->Selection = NULL; } } #endif // NL_MOVE_GRID_H /* End of move_grid.h */