201 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			201 lines
		
	
	
		
			4.8 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 "DetourNode.h"
							 | 
						||
| 
								 | 
							
								#include "DetourAlloc.h"
							 | 
						||
| 
								 | 
							
								#include "DetourAssert.h"
							 | 
						||
| 
								 | 
							
								#include "DetourCommon.h"
							 | 
						||
| 
								 | 
							
								#include <string.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef DT_POLYREF64
							 | 
						||
| 
								 | 
							
								// From Thomas Wang, https://gist.github.com/badboy/6267743
							 | 
						||
| 
								 | 
							
								inline unsigned int dtHashRef(dtPolyRef a)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									a = (~a) + (a << 18); // a = (a << 18) - a - 1;
							 | 
						||
| 
								 | 
							
									a = a ^ (a >> 31);
							 | 
						||
| 
								 | 
							
									a = a * 21; // a = (a + (a << 2)) + (a << 4);
							 | 
						||
| 
								 | 
							
									a = a ^ (a >> 11);
							 | 
						||
| 
								 | 
							
									a = a + (a << 6);
							 | 
						||
| 
								 | 
							
									a = a ^ (a >> 22);
							 | 
						||
| 
								 | 
							
									return (unsigned int)a;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								inline unsigned int dtHashRef(dtPolyRef a)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									a += ~(a<<15);
							 | 
						||
| 
								 | 
							
									a ^=  (a>>10);
							 | 
						||
| 
								 | 
							
									a +=  (a<<3);
							 | 
						||
| 
								 | 
							
									a ^=  (a>>6);
							 | 
						||
| 
								 | 
							
									a += ~(a<<11);
							 | 
						||
| 
								 | 
							
									a ^=  (a>>16);
							 | 
						||
| 
								 | 
							
									return (unsigned int)a;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								dtNodePool::dtNodePool(int maxNodes, int hashSize) :
							 | 
						||
| 
								 | 
							
									m_nodes(0),
							 | 
						||
| 
								 | 
							
									m_first(0),
							 | 
						||
| 
								 | 
							
									m_next(0),
							 | 
						||
| 
								 | 
							
									m_maxNodes(maxNodes),
							 | 
						||
| 
								 | 
							
									m_hashSize(hashSize),
							 | 
						||
| 
								 | 
							
									m_nodeCount(0)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									dtAssert(dtNextPow2(m_hashSize) == (unsigned int)m_hashSize);
							 | 
						||
| 
								 | 
							
									// pidx is special as 0 means "none" and 1 is the first node. For that reason
							 | 
						||
| 
								 | 
							
									// we have 1 fewer nodes available than the number of values it can contain.
							 | 
						||
| 
								 | 
							
									dtAssert(m_maxNodes > 0 && m_maxNodes <= DT_NULL_IDX && m_maxNodes <= (1 << DT_NODE_PARENT_BITS) - 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									m_nodes = (dtNode*)dtAlloc(sizeof(dtNode)*m_maxNodes, DT_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
									m_next = (dtNodeIndex*)dtAlloc(sizeof(dtNodeIndex)*m_maxNodes, DT_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
									m_first = (dtNodeIndex*)dtAlloc(sizeof(dtNodeIndex)*hashSize, DT_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									dtAssert(m_nodes);
							 | 
						||
| 
								 | 
							
									dtAssert(m_next);
							 | 
						||
| 
								 | 
							
									dtAssert(m_first);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									memset(m_first, 0xff, sizeof(dtNodeIndex)*m_hashSize);
							 | 
						||
| 
								 | 
							
									memset(m_next, 0xff, sizeof(dtNodeIndex)*m_maxNodes);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								dtNodePool::~dtNodePool()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									dtFree(m_nodes);
							 | 
						||
| 
								 | 
							
									dtFree(m_next);
							 | 
						||
| 
								 | 
							
									dtFree(m_first);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void dtNodePool::clear()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									memset(m_first, 0xff, sizeof(dtNodeIndex)*m_hashSize);
							 | 
						||
| 
								 | 
							
									m_nodeCount = 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								unsigned int dtNodePool::findNodes(dtPolyRef id, dtNode** nodes, const int maxNodes)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int n = 0;
							 | 
						||
| 
								 | 
							
									unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
							 | 
						||
| 
								 | 
							
									dtNodeIndex i = m_first[bucket];
							 | 
						||
| 
								 | 
							
									while (i != DT_NULL_IDX)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										if (m_nodes[i].id == id)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											if (n >= maxNodes)
							 | 
						||
| 
								 | 
							
												return n;
							 | 
						||
| 
								 | 
							
											nodes[n++] = &m_nodes[i];
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										i = m_next[i];
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return n;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								dtNode* dtNodePool::findNode(dtPolyRef id, unsigned char state)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
							 | 
						||
| 
								 | 
							
									dtNodeIndex i = m_first[bucket];
							 | 
						||
| 
								 | 
							
									while (i != DT_NULL_IDX)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										if (m_nodes[i].id == id && m_nodes[i].state == state)
							 | 
						||
| 
								 | 
							
											return &m_nodes[i];
							 | 
						||
| 
								 | 
							
										i = m_next[i];
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								dtNode* dtNodePool::getNode(dtPolyRef id, unsigned char state)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
							 | 
						||
| 
								 | 
							
									dtNodeIndex i = m_first[bucket];
							 | 
						||
| 
								 | 
							
									dtNode* node = 0;
							 | 
						||
| 
								 | 
							
									while (i != DT_NULL_IDX)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										if (m_nodes[i].id == id && m_nodes[i].state == state)
							 | 
						||
| 
								 | 
							
											return &m_nodes[i];
							 | 
						||
| 
								 | 
							
										i = m_next[i];
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									if (m_nodeCount >= m_maxNodes)
							 | 
						||
| 
								 | 
							
										return 0;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									i = (dtNodeIndex)m_nodeCount;
							 | 
						||
| 
								 | 
							
									m_nodeCount++;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// Init node
							 | 
						||
| 
								 | 
							
									node = &m_nodes[i];
							 | 
						||
| 
								 | 
							
									node->pidx = 0;
							 | 
						||
| 
								 | 
							
									node->cost = 0;
							 | 
						||
| 
								 | 
							
									node->total = 0;
							 | 
						||
| 
								 | 
							
									node->id = id;
							 | 
						||
| 
								 | 
							
									node->state = state;
							 | 
						||
| 
								 | 
							
									node->flags = 0;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									m_next[i] = m_first[bucket];
							 | 
						||
| 
								 | 
							
									m_first[bucket] = i;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									return node;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								dtNodeQueue::dtNodeQueue(int n) :
							 | 
						||
| 
								 | 
							
									m_heap(0),
							 | 
						||
| 
								 | 
							
									m_capacity(n),
							 | 
						||
| 
								 | 
							
									m_size(0)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									dtAssert(m_capacity > 0);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									m_heap = (dtNode**)dtAlloc(sizeof(dtNode*)*(m_capacity+1), DT_ALLOC_PERM);
							 | 
						||
| 
								 | 
							
									dtAssert(m_heap);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								dtNodeQueue::~dtNodeQueue()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									dtFree(m_heap);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void dtNodeQueue::bubbleUp(int i, dtNode* node)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int parent = (i-1)/2;
							 | 
						||
| 
								 | 
							
									// note: (index > 0) means there is a parent
							 | 
						||
| 
								 | 
							
									while ((i > 0) && (m_heap[parent]->total > node->total))
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										m_heap[i] = m_heap[parent];
							 | 
						||
| 
								 | 
							
										i = parent;
							 | 
						||
| 
								 | 
							
										parent = (i-1)/2;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									m_heap[i] = node;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void dtNodeQueue::trickleDown(int i, dtNode* node)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int child = (i*2)+1;
							 | 
						||
| 
								 | 
							
									while (child < m_size)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										if (((child+1) < m_size) && 
							 | 
						||
| 
								 | 
							
											(m_heap[child]->total > m_heap[child+1]->total))
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											child++;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										m_heap[i] = m_heap[child];
							 | 
						||
| 
								 | 
							
										i = child;
							 | 
						||
| 
								 | 
							
										child = (i*2)+1;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									bubbleUp(i, node);
							 | 
						||
| 
								 | 
							
								}
							 |