195 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			195 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// This software is provided 'as-is', without any express or implied
							 | 
						||
| 
								 | 
							
								// warranty.  In no event will the authors be held liable for any damages
							 | 
						||
| 
								 | 
							
								// arising from the use of this software.
							 | 
						||
| 
								 | 
							
								// Permission is granted to anyone to use this software for any purpose,
							 | 
						||
| 
								 | 
							
								// including commercial applications, and to alter it and redistribute it
							 | 
						||
| 
								 | 
							
								// freely, subject to the following restrictions:
							 | 
						||
| 
								 | 
							
								// 1. The origin of this software must not be misrepresented; you must not
							 | 
						||
| 
								 | 
							
								//    claim that you wrote the original software. If you use this software
							 | 
						||
| 
								 | 
							
								//    in a product, an acknowledgment in the product documentation would be
							 | 
						||
| 
								 | 
							
								//    appreciated but is not required.
							 | 
						||
| 
								 | 
							
								// 2. Altered source versions must be plainly marked as such, and must not be
							 | 
						||
| 
								 | 
							
								//    misrepresented as being the original software.
							 | 
						||
| 
								 | 
							
								// 3. This notice may not be removed or altered from any source distribution.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <string.h>
							 | 
						||
| 
								 | 
							
								#include <new>
							 | 
						||
| 
								 | 
							
								#include "DetourProximityGrid.h"
							 | 
						||
| 
								 | 
							
								#include "DetourCommon.h"
							 | 
						||
| 
								 | 
							
								#include "DetourMath.h"
							 | 
						||
| 
								 | 
							
								#include "DetourAlloc.h"
							 | 
						||
| 
								 | 
							
								#include "DetourAssert.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								dtProximityGrid* dtAllocProximityGrid()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									void* mem = dtAlloc(sizeof(dtProximityGrid), DT_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
									if (!mem) return 0;
							 | 
						||
| 
								 | 
							
									return new(mem) dtProximityGrid;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void dtFreeProximityGrid(dtProximityGrid* ptr)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (!ptr) return;
							 | 
						||
| 
								 | 
							
									ptr->~dtProximityGrid();
							 | 
						||
| 
								 | 
							
									dtFree(ptr);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								inline int hashPos2(int x, int y, int n)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return ((x*73856093) ^ (y*19349663)) & (n-1);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								dtProximityGrid::dtProximityGrid() :
							 | 
						||
| 
								 | 
							
									m_cellSize(0),
							 | 
						||
| 
								 | 
							
									m_invCellSize(0),
							 | 
						||
| 
								 | 
							
									m_pool(0),
							 | 
						||
| 
								 | 
							
									m_poolHead(0),
							 | 
						||
| 
								 | 
							
									m_poolSize(0),
							 | 
						||
| 
								 | 
							
									m_buckets(0),
							 | 
						||
| 
								 | 
							
									m_bucketsSize(0)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								dtProximityGrid::~dtProximityGrid()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									dtFree(m_buckets);
							 | 
						||
| 
								 | 
							
									dtFree(m_pool);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bool dtProximityGrid::init(const int poolSize, const float cellSize)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									dtAssert(poolSize > 0);
							 | 
						||
| 
								 | 
							
									dtAssert(cellSize > 0.0f);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									m_cellSize = cellSize;
							 | 
						||
| 
								 | 
							
									m_invCellSize = 1.0f / m_cellSize;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// Allocate hashs buckets
							 | 
						||
| 
								 | 
							
									m_bucketsSize = dtNextPow2(poolSize);
							 | 
						||
| 
								 | 
							
									m_buckets = (unsigned short*)dtAlloc(sizeof(unsigned short)*m_bucketsSize, DT_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
									if (!m_buckets)
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// Allocate pool of items.
							 | 
						||
| 
								 | 
							
									m_poolSize = poolSize;
							 | 
						||
| 
								 | 
							
									m_poolHead = 0;
							 | 
						||
| 
								 | 
							
									m_pool = (Item*)dtAlloc(sizeof(Item)*m_poolSize, DT_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
									if (!m_pool)
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									clear();
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									return true;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void dtProximityGrid::clear()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									memset(m_buckets, 0xff, sizeof(unsigned short)*m_bucketsSize);
							 | 
						||
| 
								 | 
							
									m_poolHead = 0;
							 | 
						||
| 
								 | 
							
									m_bounds[0] = 0xffff;
							 | 
						||
| 
								 | 
							
									m_bounds[1] = 0xffff;
							 | 
						||
| 
								 | 
							
									m_bounds[2] = -0xffff;
							 | 
						||
| 
								 | 
							
									m_bounds[3] = -0xffff;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void dtProximityGrid::addItem(const unsigned short id,
							 | 
						||
| 
								 | 
							
															  const float minx, const float miny,
							 | 
						||
| 
								 | 
							
															  const float maxx, const float maxy)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									const int iminx = (int)dtMathFloorf(minx * m_invCellSize);
							 | 
						||
| 
								 | 
							
									const int iminy = (int)dtMathFloorf(miny * m_invCellSize);
							 | 
						||
| 
								 | 
							
									const int imaxx = (int)dtMathFloorf(maxx * m_invCellSize);
							 | 
						||
| 
								 | 
							
									const int imaxy = (int)dtMathFloorf(maxy * m_invCellSize);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									m_bounds[0] = dtMin(m_bounds[0], iminx);
							 | 
						||
| 
								 | 
							
									m_bounds[1] = dtMin(m_bounds[1], iminy);
							 | 
						||
| 
								 | 
							
									m_bounds[2] = dtMax(m_bounds[2], imaxx);
							 | 
						||
| 
								 | 
							
									m_bounds[3] = dtMax(m_bounds[3], imaxy);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									for (int y = iminy; y <= imaxy; ++y)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										for (int x = iminx; x <= imaxx; ++x)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											if (m_poolHead < m_poolSize)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												const int h = hashPos2(x, y, m_bucketsSize);
							 | 
						||
| 
								 | 
							
												const unsigned short idx = (unsigned short)m_poolHead;
							 | 
						||
| 
								 | 
							
												m_poolHead++;
							 | 
						||
| 
								 | 
							
												Item& item = m_pool[idx];
							 | 
						||
| 
								 | 
							
												item.x = (short)x;
							 | 
						||
| 
								 | 
							
												item.y = (short)y;
							 | 
						||
| 
								 | 
							
												item.id = id;
							 | 
						||
| 
								 | 
							
												item.next = m_buckets[h];
							 | 
						||
| 
								 | 
							
												m_buckets[h] = idx;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int dtProximityGrid::queryItems(const float minx, const float miny,
							 | 
						||
| 
								 | 
							
																const float maxx, const float maxy,
							 | 
						||
| 
								 | 
							
																unsigned short* ids, const int maxIds) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									const int iminx = (int)dtMathFloorf(minx * m_invCellSize);
							 | 
						||
| 
								 | 
							
									const int iminy = (int)dtMathFloorf(miny * m_invCellSize);
							 | 
						||
| 
								 | 
							
									const int imaxx = (int)dtMathFloorf(maxx * m_invCellSize);
							 | 
						||
| 
								 | 
							
									const int imaxy = (int)dtMathFloorf(maxy * m_invCellSize);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									int n = 0;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									for (int y = iminy; y <= imaxy; ++y)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										for (int x = iminx; x <= imaxx; ++x)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											const int h = hashPos2(x, y, m_bucketsSize);
							 | 
						||
| 
								 | 
							
											unsigned short idx = m_buckets[h];
							 | 
						||
| 
								 | 
							
											while (idx != 0xffff)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												Item& item = m_pool[idx];
							 | 
						||
| 
								 | 
							
												if ((int)item.x == x && (int)item.y == y)
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													// Check if the id exists already.
							 | 
						||
| 
								 | 
							
													const unsigned short* end = ids + n;
							 | 
						||
| 
								 | 
							
													unsigned short* i = ids;
							 | 
						||
| 
								 | 
							
													while (i != end && *i != item.id)
							 | 
						||
| 
								 | 
							
														++i;
							 | 
						||
| 
								 | 
							
													// Item not found, add it.
							 | 
						||
| 
								 | 
							
													if (i == end)
							 | 
						||
| 
								 | 
							
													{
							 | 
						||
| 
								 | 
							
														if (n >= maxIds)
							 | 
						||
| 
								 | 
							
															return n;
							 | 
						||
| 
								 | 
							
														ids[n++] = item.id;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												idx = item.next;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									return n;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int dtProximityGrid::getItemCountAt(const int x, const int y) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int n = 0;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									const int h = hashPos2(x, y, m_bucketsSize);
							 | 
						||
| 
								 | 
							
									unsigned short idx = m_buckets[h];
							 | 
						||
| 
								 | 
							
									while (idx != 0xffff)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										Item& item = m_pool[idx];
							 | 
						||
| 
								 | 
							
										if ((int)item.x == x && (int)item.y == y)
							 | 
						||
| 
								 | 
							
											n++;
							 | 
						||
| 
								 | 
							
										idx = item.next;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									return n;
							 | 
						||
| 
								 | 
							
								}
							 |