mirror of https://github.com/axmolengine/axmol.git
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;
|
|
}
|