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;
 | 
						|
}
 |