Browse Source

Update Recast/Detour to newest. Remove Navigation.cpp / Navigation.h in Navigation library; moved the library registration to NavigationMesh.cpp.

Lasse Öörni 11 years ago
parent
commit
d25872ca08

+ 1 - 1
Readme.txt

@@ -86,7 +86,7 @@ Urho3D uses the following third-party libraries:
 - MojoShader (http://icculus.org/mojoshader/)
 - MojoShader (http://icculus.org/mojoshader/)
 - Open Asset Import Library (http://assimp.sourceforge.net/)
 - Open Asset Import Library (http://assimp.sourceforge.net/)
 - pugixml 1.0 (http://pugixml.org/)
 - pugixml 1.0 (http://pugixml.org/)
-- Recast/Detour (http://code.google.com/p/recastnavigation/)
+- Recast/Detour (https://github.com/memononen/recastnavigation/)
 - SDL 2.0.1 (http://www.libsdl.org/)
 - SDL 2.0.1 (http://www.libsdl.org/)
 - StanHull (http://codesuppository.blogspot.com/2006/03/
 - StanHull (http://codesuppository.blogspot.com/2006/03/
   john-ratcliffs-code-suppository-blog.html)
   john-ratcliffs-code-suppository-blog.html)

+ 1 - 1
Source/Engine/Engine/Engine.cpp

@@ -32,7 +32,7 @@
 #include "Input.h"
 #include "Input.h"
 #include "InputEvents.h"
 #include "InputEvents.h"
 #include "Log.h"
 #include "Log.h"
-#include "Navigation.h"
+#include "NavigationMesh.h"
 #include "Network.h"
 #include "Network.h"
 #include "PackageFile.h"
 #include "PackageFile.h"
 #include "PhysicsWorld.h"
 #include "PhysicsWorld.h"

+ 0 - 42
Source/Engine/Navigation/Navigation.cpp

@@ -1,42 +0,0 @@
-//
-// Copyright (c) 2008-2014 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "Precompiled.h"
-#include "Navigable.h"
-#include "NavigationMesh.h"
-#include "OffMeshConnection.h"
-
-#include "DebugNew.h"
-
-namespace Urho3D
-{
-
-const char* NAVIGATION_CATEGORY = "Navigation";
-
-void RegisterNavigationLibrary(Context* context)
-{
-    Navigable::RegisterObject(context);
-    NavigationMesh::RegisterObject(context);
-    OffMeshConnection::RegisterObject(context);
-}
-
-}

+ 0 - 33
Source/Engine/Navigation/Navigation.h

@@ -1,33 +0,0 @@
-//
-// Copyright (c) 2008-2014 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#pragma once
-
-namespace Urho3D
-{
-
-class Context;
-
-/// Register Navigation library objects.
-void URHO3D_API RegisterNavigationLibrary(Context* context);
-
-}

+ 10 - 3
Source/Engine/Navigation/NavigationMesh.cpp

@@ -49,7 +49,7 @@
 namespace Urho3D
 namespace Urho3D
 {
 {
 
 
-extern const char* NAVIGATION_CATEGORY;
+const char* NAVIGATION_CATEGORY = "Navigation";
 
 
 static const int DEFAULT_TILE_SIZE = 128;
 static const int DEFAULT_TILE_SIZE = 128;
 static const float DEFAULT_CELL_SIZE = 0.3f;
 static const float DEFAULT_CELL_SIZE = 0.3f;
@@ -536,12 +536,12 @@ void NavigationMesh::FindPath(PODVector<Vector3>& dest, const Vector3& start, co
         MAX_POLYS);
         MAX_POLYS);
     if (!numPolys)
     if (!numPolys)
         return;
         return;
-    
+
     Vector3 actualLocalEnd = localEnd;
     Vector3 actualLocalEnd = localEnd;
     
     
     // If full path was not found, clamp end point to the end polygon
     // If full path was not found, clamp end point to the end polygon
     if (pathData_->polys_[numPolys - 1] != endRef)
     if (pathData_->polys_[numPolys - 1] != endRef)
-        navMeshQuery_->closestPointOnPoly(pathData_->polys_[numPolys - 1], &localEnd.x_, &actualLocalEnd.x_);
+        navMeshQuery_->closestPointOnPoly(pathData_->polys_[numPolys - 1], &localEnd.x_, &actualLocalEnd.x_, 0);
     
     
     navMeshQuery_->findStraightPath(&localStart.x_, &actualLocalEnd.x_, pathData_->polys_, numPolys,
     navMeshQuery_->findStraightPath(&localStart.x_, &actualLocalEnd.x_, pathData_->polys_, numPolys,
         &pathData_->pathPoints_[0].x_, pathData_->pathFlags_, pathData_->pathPolys_, &numPathPoints, MAX_POLYS);
         &pathData_->pathPoints_[0].x_, pathData_->pathFlags_, pathData_->pathPolys_, &numPathPoints, MAX_POLYS);
@@ -1271,4 +1271,11 @@ void NavigationMesh::ReleaseNavigationMesh()
     boundingBox_.defined_ = false;
     boundingBox_.defined_ = false;
 }
 }
 
 
+void RegisterNavigationLibrary(Context* context)
+{
+    Navigable::RegisterObject(context);
+    NavigationMesh::RegisterObject(context);
+    OffMeshConnection::RegisterObject(context);
+}
+
 }
 }

+ 3 - 0
Source/Engine/Navigation/NavigationMesh.h

@@ -220,4 +220,7 @@ private:
     BoundingBox boundingBox_;
     BoundingBox boundingBox_;
 };
 };
 
 
+/// Register Navigation library objects.
+void URHO3D_API RegisterNavigationLibrary(Context* context);
+
 }
 }

+ 5 - 0
Source/ThirdParty/Detour/include/DetourCommon.h

@@ -32,6 +32,11 @@ feature to find minor members.
 /// @name General helper functions
 /// @name General helper functions
 /// @{
 /// @{
 
 
+/// Used to ignore a function parameter.  VS complains about unused parameters
+/// and this silences the warning.
+///  @param [in] _ Unused parameter
+template<class T> void dtIgnoreUnused(const T&) { }
+
 /// Swaps the values of the two parameters.
 /// Swaps the values of the two parameters.
 ///  @param[in,out]	a	Value A
 ///  @param[in,out]	a	Value A
 ///  @param[in,out]	b	Value B
 ///  @param[in,out]	b	Value B

+ 21 - 0
Source/ThirdParty/Detour/include/DetourMath.h

@@ -0,0 +1,21 @@
+#ifndef DETOURMATH_H
+#define DETOURMATH_H
+
+/**
+@defgroup detour Detour
+
+Members in this module are wrappers around the standard math library
+
+*/
+
+#include <math.h>
+
+#define dtMathFabs(x) fabs(x)
+#define dtMathSqrtf(x) sqrtf(x)
+#define dtMathFloorf(x) floorf(x)
+#define dtMathCeilf(x) ceilf(x)
+#define dtMathCosf(x) cosf(x)
+#define dtMathSinf(x) sinf(x)
+#define dtMathAtan2f(y, x) atan2f(y, x)
+
+#endif

+ 54 - 2
Source/ThirdParty/Detour/include/DetourNavMesh.h

@@ -22,16 +22,39 @@
 #include "DetourAlloc.h"
 #include "DetourAlloc.h"
 #include "DetourStatus.h"
 #include "DetourStatus.h"
 
 
+// Undefine (or define in a build cofnig) the following line to use 64bit polyref.
+// Generally not needed, useful for very large worlds.
+// Note: tiles build using 32bit refs are not compatible with 64bit refs!
+//#define DT_POLYREF64 1
+
+#ifdef DT_POLYREF64
+// TODO: figure out a multiplatform version of uint64_t
+// - maybe: https://code.google.com/p/msinttypes/
+// - or: http://www.azillionmonkeys.com/qed/pstdint.h
+#include <stdint.h>
+#endif
+
 // Note: If you want to use 64-bit refs, change the types of both dtPolyRef & dtTileRef.
 // Note: If you want to use 64-bit refs, change the types of both dtPolyRef & dtTileRef.
 // It is also recommended that you change dtHashRef() to a proper 64-bit hash.
 // It is also recommended that you change dtHashRef() to a proper 64-bit hash.
 
 
 /// A handle to a polygon within a navigation mesh tile.
 /// A handle to a polygon within a navigation mesh tile.
 /// @ingroup detour
 /// @ingroup detour
+#ifdef DT_POLYREF64
+static const unsigned int DT_SALT_BITS = 16;
+static const unsigned int DT_TILE_BITS = 28;
+static const unsigned int DT_POLY_BITS = 20;
+typedef uint64_t dtPolyRef;
+#else
 typedef unsigned int dtPolyRef;
 typedef unsigned int dtPolyRef;
+#endif
 
 
 /// A handle to a tile within a navigation mesh.
 /// A handle to a tile within a navigation mesh.
 /// @ingroup detour
 /// @ingroup detour
+#ifdef DT_POLYREF64
+typedef uint64_t dtTileRef;
+#else
 typedef unsigned int dtTileRef;
 typedef unsigned int dtTileRef;
+#endif
 
 
 /// The maximum number of vertices per navigation polygon.
 /// The maximum number of vertices per navigation polygon.
 /// @ingroup detour
 /// @ingroup detour
@@ -469,7 +492,11 @@ public:
 	///  @param[in]	ip		The index of the polygon within the tile.
 	///  @param[in]	ip		The index of the polygon within the tile.
 	inline dtPolyRef encodePolyId(unsigned int salt, unsigned int it, unsigned int ip) const
 	inline dtPolyRef encodePolyId(unsigned int salt, unsigned int it, unsigned int ip) const
 	{
 	{
+#ifdef DT_POLYREF64
+		return ((dtPolyRef)salt << (DT_POLY_BITS+DT_TILE_BITS)) | ((dtPolyRef)it << DT_POLY_BITS) | (dtPolyRef)ip;
+#else
 		return ((dtPolyRef)salt << (m_polyBits+m_tileBits)) | ((dtPolyRef)it << m_polyBits) | (dtPolyRef)ip;
 		return ((dtPolyRef)salt << (m_polyBits+m_tileBits)) | ((dtPolyRef)it << m_polyBits) | (dtPolyRef)ip;
+#endif
 	}
 	}
 	
 	
 	/// Decodes a standard polygon reference.
 	/// Decodes a standard polygon reference.
@@ -481,12 +508,21 @@ public:
 	///  @see #encodePolyId
 	///  @see #encodePolyId
 	inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const
 	inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const
 	{
 	{
+#ifdef DT_POLYREF64
+		const dtPolyRef saltMask = ((dtPolyRef)1<<DT_SALT_BITS)-1;
+		const dtPolyRef tileMask = ((dtPolyRef)1<<DT_TILE_BITS)-1;
+		const dtPolyRef polyMask = ((dtPolyRef)1<<DT_POLY_BITS)-1;
+		salt = (unsigned int)((ref >> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask);
+		it = (unsigned int)((ref >> DT_POLY_BITS) & tileMask);
+		ip = (unsigned int)(ref & polyMask);
+#else
 		const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
 		const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
 		const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
 		const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
 		const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
 		const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
 		salt = (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
 		salt = (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
 		it = (unsigned int)((ref >> m_polyBits) & tileMask);
 		it = (unsigned int)((ref >> m_polyBits) & tileMask);
 		ip = (unsigned int)(ref & polyMask);
 		ip = (unsigned int)(ref & polyMask);
+#endif
 	}
 	}
 
 
 	/// Extracts a tile's salt value from the specified polygon reference.
 	/// Extracts a tile's salt value from the specified polygon reference.
@@ -495,8 +531,13 @@ public:
 	///  @see #encodePolyId
 	///  @see #encodePolyId
 	inline unsigned int decodePolyIdSalt(dtPolyRef ref) const
 	inline unsigned int decodePolyIdSalt(dtPolyRef ref) const
 	{
 	{
+#ifdef DT_POLYREF64
+		const dtPolyRef saltMask = ((dtPolyRef)1<<DT_SALT_BITS)-1;
+		return (unsigned int)((ref >> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask);
+#else
 		const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
 		const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
 		return (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
 		return (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
+#endif
 	}
 	}
 	
 	
 	/// Extracts the tile's index from the specified polygon reference.
 	/// Extracts the tile's index from the specified polygon reference.
@@ -505,8 +546,13 @@ public:
 	///  @see #encodePolyId
 	///  @see #encodePolyId
 	inline unsigned int decodePolyIdTile(dtPolyRef ref) const
 	inline unsigned int decodePolyIdTile(dtPolyRef ref) const
 	{
 	{
+#ifdef DT_POLYREF64
+		const dtPolyRef tileMask = ((dtPolyRef)1<<DT_TILE_BITS)-1;
+		return (unsigned int)((ref >> DT_POLY_BITS) & tileMask);
+#else
 		const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
 		const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
 		return (unsigned int)((ref >> m_polyBits) & tileMask);
 		return (unsigned int)((ref >> m_polyBits) & tileMask);
+#endif
 	}
 	}
 	
 	
 	/// Extracts the polygon's index (within its tile) from the specified polygon reference.
 	/// Extracts the polygon's index (within its tile) from the specified polygon reference.
@@ -515,8 +561,13 @@ public:
 	///  @see #encodePolyId
 	///  @see #encodePolyId
 	inline unsigned int decodePolyIdPoly(dtPolyRef ref) const
 	inline unsigned int decodePolyIdPoly(dtPolyRef ref) const
 	{
 	{
+#ifdef DT_POLYREF64
+		const dtPolyRef polyMask = ((dtPolyRef)1<<DT_POLY_BITS)-1;
+		return (unsigned int)(ref & polyMask);
+#else
 		const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
 		const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
 		return (unsigned int)(ref & polyMask);
 		return (unsigned int)(ref & polyMask);
+#endif
 	}
 	}
 
 
 	/// @}
 	/// @}
@@ -562,8 +613,7 @@ private:
 	dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center,
 	dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center,
 									const float* extents, float* nearestPt) const;
 									const float* extents, float* nearestPt) const;
 	/// Returns closest point on polygon.
 	/// Returns closest point on polygon.
-	void closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip,
-								  const float* pos, float* closest) const;
+	void closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
 	
 	
 	dtNavMeshParams m_params;			///< Current initialization params. TODO: do not store this info twice.
 	dtNavMeshParams m_params;			///< Current initialization params. TODO: do not store this info twice.
 	float m_orig[3];					///< Origin of the tile (0,0)
 	float m_orig[3];					///< Origin of the tile (0,0)
@@ -576,9 +626,11 @@ private:
 	dtMeshTile* m_nextFree;				///< Freelist of tiles.
 	dtMeshTile* m_nextFree;				///< Freelist of tiles.
 	dtMeshTile* m_tiles;				///< List of tiles.
 	dtMeshTile* m_tiles;				///< List of tiles.
 		
 		
+#ifndef DT_POLYREF64
 	unsigned int m_saltBits;			///< Number of salt bits in the tile ID.
 	unsigned int m_saltBits;			///< Number of salt bits in the tile ID.
 	unsigned int m_tileBits;			///< Number of tile bits in the tile ID.
 	unsigned int m_tileBits;			///< Number of tile bits in the tile ID.
 	unsigned int m_polyBits;			///< Number of poly bits in the tile ID.
 	unsigned int m_polyBits;			///< Number of poly bits in the tile ID.
+#endif
 };
 };
 
 
 /// Allocates a navigation mesh object using the Detour allocator.
 /// Allocates a navigation mesh object using the Detour allocator.

+ 5 - 9
Source/ThirdParty/Detour/include/DetourNavMeshQuery.h

@@ -200,8 +200,8 @@ public:
 	
 	
 	/// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest
 	/// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest
 	/// polygon on the existing path that was visited during the search.
 	/// polygon on the existing path that was visited during the search.
-	///  @param[out]	existing		An array of polygon references for the existing path.
-	///  @param[out]	existingSize	The number of polygon in the @p existing array.
+	///  @param[in]		existing		An array of polygon references for the existing path.
+	///  @param[in]		existingSize	The number of polygon in the @p existing array.
 	///  @param[out]	path			An ordered list of polygon references representing the path. (Start to end.) 
 	///  @param[out]	path			An ordered list of polygon references representing the path. (Start to end.) 
 	///  								[(polyRef) * @p pathCount]
 	///  								[(polyRef) * @p pathCount]
 	///  @param[out]	pathCount		The number of polygons returned in the @p path array.
 	///  @param[out]	pathCount		The number of polygons returned in the @p path array.
@@ -378,8 +378,9 @@ public:
 	///  @param[in]		ref			The reference id of the polygon.
 	///  @param[in]		ref			The reference id of the polygon.
 	///  @param[in]		pos			The position to check. [(x, y, z)]
 	///  @param[in]		pos			The position to check. [(x, y, z)]
 	///  @param[out]	closest		The closest point on the polygon. [(x, y, z)]
 	///  @param[out]	closest		The closest point on the polygon. [(x, y, z)]
+	///  @param[out]	posOverPoly	True of the position is over the polygon.
 	/// @returns The status flags for the query.
 	/// @returns The status flags for the query.
-	dtStatus closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest) const;
+	dtStatus closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
 	
 	
 	/// Returns a point on the boundary closest to the source point if the source point is outside the 
 	/// Returns a point on the boundary closest to the source point if the source point is outside the 
 	/// polygon's xz-bounds.
 	/// polygon's xz-bounds.
@@ -428,12 +429,7 @@ private:
 	/// Queries polygons within a tile.
 	/// Queries polygons within a tile.
 	int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax, const dtQueryFilter* filter,
 	int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax, const dtQueryFilter* filter,
 							dtPolyRef* polys, const int maxPolys) const;
 							dtPolyRef* polys, const int maxPolys) const;
-	/// Find nearest polygon within a tile.
-	dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center, const float* extents,
-									const dtQueryFilter* filter, float* nearestPt) const;
-	/// Returns closest point on polygon.
-	void closestPointOnPolyInTile(const dtMeshTile* tile, const dtPoly* poly, const float* pos, float* closest) const;
-	
+
 	/// Returns portal points between two polygons.
 	/// Returns portal points between two polygons.
 	dtStatus getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right,
 	dtStatus getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right,
 							 unsigned char& fromType, unsigned char& toType) const;
 							 unsigned char& fromType, unsigned char& toType) const;

+ 2 - 2
Source/ThirdParty/Detour/source/DetourCommon.cpp

@@ -16,14 +16,14 @@
 // 3. This notice may not be removed or altered from any source distribution.
 // 3. This notice may not be removed or altered from any source distribution.
 //
 //
 
 
-#include <math.h>
 #include "DetourCommon.h"
 #include "DetourCommon.h"
+#include "DetourMath.h"
 
 
 //////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////
 
 
 float dtSqrt(float x)
 float dtSqrt(float x)
 {
 {
-	return sqrtf(x);
+	return dtMathSqrtf(x);
 }
 }
 
 
 void dtClosestPtPointTriangle(float* closest, const float* p,
 void dtClosestPtPointTriangle(float* closest, const float* p,

+ 50 - 13
Source/ThirdParty/Detour/source/DetourNavMesh.cpp

@@ -16,13 +16,13 @@
 // 3. This notice may not be removed or altered from any source distribution.
 // 3. This notice may not be removed or altered from any source distribution.
 //
 //
 
 
-#include <math.h>
 #include <float.h>
 #include <float.h>
 #include <string.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdio.h>
 #include "DetourNavMesh.h"
 #include "DetourNavMesh.h"
 #include "DetourNode.h"
 #include "DetourNode.h"
 #include "DetourCommon.h"
 #include "DetourCommon.h"
+#include "DetourMath.h"
 #include "DetourAlloc.h"
 #include "DetourAlloc.h"
 #include "DetourAssert.h"
 #include "DetourAssert.h"
 #include <new>
 #include <new>
@@ -193,11 +193,13 @@ dtNavMesh::dtNavMesh() :
 	m_tileLutMask(0),
 	m_tileLutMask(0),
 	m_posLookup(0),
 	m_posLookup(0),
 	m_nextFree(0),
 	m_nextFree(0),
-	m_tiles(0),
-	m_saltBits(0),
-	m_tileBits(0),
-	m_polyBits(0)
+	m_tiles(0)
 {
 {
+#ifndef DT_POLYREF64
+	m_saltBits = 0;
+	m_tileBits = 0;
+	m_polyBits = 0;
+#endif
 	memset(&m_params, 0, sizeof(dtNavMeshParams));
 	memset(&m_params, 0, sizeof(dtNavMeshParams));
 	m_orig[0] = 0;
 	m_orig[0] = 0;
 	m_orig[1] = 0;
 	m_orig[1] = 0;
@@ -249,12 +251,15 @@ dtStatus dtNavMesh::init(const dtNavMeshParams* params)
 	}
 	}
 	
 	
 	// Init ID generator values.
 	// Init ID generator values.
+#ifndef DT_POLYREF64
 	m_tileBits = dtIlog2(dtNextPow2((unsigned int)params->maxTiles));
 	m_tileBits = dtIlog2(dtNextPow2((unsigned int)params->maxTiles));
 	m_polyBits = dtIlog2(dtNextPow2((unsigned int)params->maxPolys));
 	m_polyBits = dtIlog2(dtNextPow2((unsigned int)params->maxPolys));
 	// Only allow 31 salt bits, since the salt mask is calculated using 32bit uint and it will overflow.
 	// Only allow 31 salt bits, since the salt mask is calculated using 32bit uint and it will overflow.
 	m_saltBits = dtMin((unsigned int)31, 32 - m_tileBits - m_polyBits);
 	m_saltBits = dtMin((unsigned int)31, 32 - m_tileBits - m_polyBits);
+
 	if (m_saltBits < 10)
 	if (m_saltBits < 10)
 		return DT_FAILURE | DT_INVALID_PARAM;
 		return DT_FAILURE | DT_INVALID_PARAM;
+#endif
 	
 	
 	return DT_SUCCESS;
 	return DT_SUCCESS;
 }
 }
@@ -612,10 +617,12 @@ void dtNavMesh::baseOffMeshLinks(dtMeshTile* tile)
 	}
 	}
 }
 }
 
 
-void dtNavMesh::closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip,
-										 const float* pos, float* closest) const
+void dtNavMesh::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const
 {
 {
-	const dtPoly* poly = &tile->polys[ip];
+	const dtMeshTile* tile = 0;
+	const dtPoly* poly = 0;
+	getTileAndPolyByRefUnsafe(ref, &tile, &poly);
+	
 	// Off-mesh connections don't have detail polygons.
 	// Off-mesh connections don't have detail polygons.
 	if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
 	if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
 	{
 	{
@@ -625,11 +632,14 @@ void dtNavMesh::closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip
 		const float d1 = dtVdist(pos, v1);
 		const float d1 = dtVdist(pos, v1);
 		const float u = d0 / (d0+d1);
 		const float u = d0 / (d0+d1);
 		dtVlerp(closest, v0, v1, u);
 		dtVlerp(closest, v0, v1, u);
+		if (posOverPoly)
+			*posOverPoly = false;
 		return;
 		return;
 	}
 	}
 	
 	
+	const unsigned int ip = (unsigned int)(poly - tile->polys);
 	const dtPolyDetail* pd = &tile->detailMeshes[ip];
 	const dtPolyDetail* pd = &tile->detailMeshes[ip];
-
+	
 	// Clamp point to be inside the polygon.
 	// Clamp point to be inside the polygon.
 	float verts[DT_VERTS_PER_POLYGON*3];	
 	float verts[DT_VERTS_PER_POLYGON*3];	
 	float edged[DT_VERTS_PER_POLYGON];
 	float edged[DT_VERTS_PER_POLYGON];
@@ -655,6 +665,14 @@ void dtNavMesh::closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip
 		const float* va = &verts[imin*3];
 		const float* va = &verts[imin*3];
 		const float* vb = &verts[((imin+1)%nv)*3];
 		const float* vb = &verts[((imin+1)%nv)*3];
 		dtVlerp(closest, va, vb, edget[imin]);
 		dtVlerp(closest, va, vb, edget[imin]);
+		
+		if (posOverPoly)
+			*posOverPoly = false;
+	}
+	else
+	{
+		if (posOverPoly)
+			*posOverPoly = true;
 	}
 	}
 	
 	
 	// Find height at the location.
 	// Find height at the location.
@@ -697,12 +715,27 @@ dtPolyRef dtNavMesh::findNearestPolyInTile(const dtMeshTile* tile,
 	{
 	{
 		dtPolyRef ref = polys[i];
 		dtPolyRef ref = polys[i];
 		float closestPtPoly[3];
 		float closestPtPoly[3];
-		closestPointOnPolyInTile(tile, decodePolyIdPoly(ref), center, closestPtPoly);
-		float d = dtVdistSqr(center, closestPtPoly);
+		float diff[3];
+		bool posOverPoly = false;
+		float d = 0;
+		closestPointOnPoly(ref, center, closestPtPoly, &posOverPoly);
+
+		// If a point is directly over a polygon and closer than
+		// climb height, favor that instead of straight line nearest point.
+		dtVsub(diff, center, closestPtPoly);
+		if (posOverPoly)
+		{
+			d = dtAbs(diff[1]) - tile->header->walkableClimb;
+			d = d > 0 ? d*d : 0;			
+		}
+		else
+		{
+			d = dtVlenSqr(diff);
+		}
+		
 		if (d < nearestDistanceSqr)
 		if (d < nearestDistanceSqr)
 		{
 		{
-			if (nearestPt)
-				dtVcopy(nearestPt, closestPtPoly);
+			dtVcopy(nearestPt, closestPtPoly);
 			nearestDistanceSqr = d;
 			nearestDistanceSqr = d;
 			nearest = ref;
 			nearest = ref;
 		}
 		}
@@ -1209,7 +1242,11 @@ dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSiz
 	tile->offMeshCons = 0;
 	tile->offMeshCons = 0;
 
 
 	// Update salt, salt should never be zero.
 	// Update salt, salt should never be zero.
+#ifdef DT_POLYREF64
+	tile->salt = (tile->salt+1) & ((1<<DT_SALT_BITS)-1);
+#else
 	tile->salt = (tile->salt+1) & ((1<<m_saltBits)-1);
 	tile->salt = (tile->salt+1) & ((1<<m_saltBits)-1);
+#endif
 	if (tile->salt == 0)
 	if (tile->salt == 0)
 		tile->salt++;
 		tile->salt++;
 
 

+ 3 - 3
Source/ThirdParty/Detour/source/DetourNavMeshBuilder.cpp

@@ -16,13 +16,13 @@
 // 3. This notice may not be removed or altered from any source distribution.
 // 3. This notice may not be removed or altered from any source distribution.
 //
 //
 
 
-#include <math.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 #include <float.h>
 #include <float.h>
 #include "DetourNavMesh.h"
 #include "DetourNavMesh.h"
 #include "DetourCommon.h"
 #include "DetourCommon.h"
+#include "DetourMath.h"
 #include "DetourNavMeshBuilder.h"
 #include "DetourNavMeshBuilder.h"
 #include "DetourAlloc.h"
 #include "DetourAlloc.h"
 #include "DetourAssert.h"
 #include "DetourAssert.h"
@@ -202,8 +202,8 @@ static int createBVTree(const unsigned short* verts, const int /*nverts*/,
 			if (z > it.bmax[2]) it.bmax[2] = z;
 			if (z > it.bmax[2]) it.bmax[2] = z;
 		}
 		}
 		// Remap y
 		// Remap y
-		it.bmin[1] = (unsigned short)floorf((float)it.bmin[1]*ch/cs);
-		it.bmax[1] = (unsigned short)ceilf((float)it.bmax[1]*ch/cs);
+		it.bmin[1] = (unsigned short)dtMathFloorf((float)it.bmin[1]*ch/cs);
+		it.bmax[1] = (unsigned short)dtMathCeilf((float)it.bmax[1]*ch/cs);
 	}
 	}
 	
 	
 	int curNode = 0;
 	int curNode = 0;

+ 39 - 76
Source/ThirdParty/Detour/source/DetourNavMeshQuery.cpp

@@ -16,13 +16,13 @@
 // 3. This notice may not be removed or altered from any source distribution.
 // 3. This notice may not be removed or altered from any source distribution.
 //
 //
 
 
-#include <math.h>
 #include <float.h>
 #include <float.h>
 #include <string.h>
 #include <string.h>
 #include "DetourNavMeshQuery.h"
 #include "DetourNavMeshQuery.h"
 #include "DetourNavMesh.h"
 #include "DetourNavMesh.h"
 #include "DetourNode.h"
 #include "DetourNode.h"
 #include "DetourCommon.h"
 #include "DetourCommon.h"
+#include "DetourMath.h"
 #include "DetourAlloc.h"
 #include "DetourAlloc.h"
 #include "DetourAssert.h"
 #include "DetourAssert.h"
 #include <new>
 #include <new>
@@ -501,7 +501,7 @@ dtStatus dtNavMeshQuery::findRandomPointAroundCircle(dtPolyRef startRef, const f
 ///
 ///
 /// See closestPointOnPolyBoundary() for a limited but faster option.
 /// See closestPointOnPolyBoundary() for a limited but faster option.
 ///
 ///
-dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest) const
+dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const
 {
 {
 	dtAssert(m_nav);
 	dtAssert(m_nav);
 	const dtMeshTile* tile = 0;
 	const dtMeshTile* tile = 0;
@@ -511,14 +511,6 @@ dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, flo
 	if (!tile)
 	if (!tile)
 		return DT_FAILURE | DT_INVALID_PARAM;
 		return DT_FAILURE | DT_INVALID_PARAM;
 	
 	
-	closestPointOnPolyInTile(tile, poly, pos, closest);
-	
-	return DT_SUCCESS;
-}
-
-void dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPoly* poly,
-											  const float* pos, float* closest) const
-{
 	// Off-mesh connections don't have detail polygons.
 	// Off-mesh connections don't have detail polygons.
 	if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
 	if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
 	{
 	{
@@ -528,7 +520,9 @@ void dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPo
 		const float d1 = dtVdist(pos, v1);
 		const float d1 = dtVdist(pos, v1);
 		const float u = d0 / (d0+d1);
 		const float u = d0 / (d0+d1);
 		dtVlerp(closest, v0, v1, u);
 		dtVlerp(closest, v0, v1, u);
-		return;
+		if (posOverPoly)
+			*posOverPoly = false;
+		return DT_SUCCESS;
 	}
 	}
 
 
 	const unsigned int ip = (unsigned int)(poly - tile->polys);
 	const unsigned int ip = (unsigned int)(poly - tile->polys);
@@ -559,6 +553,14 @@ void dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPo
 		const float* va = &verts[imin*3];
 		const float* va = &verts[imin*3];
 		const float* vb = &verts[((imin+1)%nv)*3];
 		const float* vb = &verts[((imin+1)%nv)*3];
 		dtVlerp(closest, va, vb, edget[imin]);
 		dtVlerp(closest, va, vb, edget[imin]);
+
+		if (posOverPoly)
+			*posOverPoly = false;
+	}
+	else
+	{
+		if (posOverPoly)
+			*posOverPoly = true;
 	}
 	}
 
 
 	// Find height at the location.
 	// Find height at the location.
@@ -580,30 +582,8 @@ void dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPo
 			break;
 			break;
 		}
 		}
 	}
 	}
-
-/*	float closestDistSqr = FLT_MAX;
-	for (int j = 0; j < pd->triCount; ++j)
-	{
-		const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4];
-		const float* v[3];
-		for (int k = 0; k < 3; ++k)
-		{
-			if (t[k] < poly->vertCount)
-				v[k] = &tile->verts[poly->verts[t[k]]*3];
-			else
-				v[k] = &tile->detailVerts[(pd->vertBase+(t[k]-poly->vertCount))*3];
-		}
-
-		float pt[3];
-		dtClosestPtPointTriangle(pt, pos, v[0], v[1], v[2]);
-		float d = dtVdistSqr(pos, pt);
-		
-		if (d < closestDistSqr)
-		{
-			dtVcopy(closest, pt);
-			closestDistSqr = d;
-		}
-	}*/
+	
+	return DT_SUCCESS;
 }
 }
 
 
 /// @par
 /// @par
@@ -682,8 +662,8 @@ dtStatus dtNavMeshQuery::getPolyHeight(dtPolyRef ref, const float* pos, float* h
 	{
 	{
 		const float* v0 = &tile->verts[poly->verts[0]*3];
 		const float* v0 = &tile->verts[poly->verts[0]*3];
 		const float* v1 = &tile->verts[poly->verts[1]*3];
 		const float* v1 = &tile->verts[poly->verts[1]*3];
-		const float d0 = dtVdist(pos, v0);
-		const float d1 = dtVdist(pos, v1);
+		const float d0 = dtVdist2D(pos, v0);
+		const float d1 = dtVdist2D(pos, v1);
 		const float u = d0 / (d0+d1);
 		const float u = d0 / (d0+d1);
 		if (height)
 		if (height)
 			*height = v0[1] + (v1[1] - v0[1]) * u;
 			*height = v0[1] + (v1[1] - v0[1]) * u;
@@ -747,8 +727,27 @@ dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* exten
 	{
 	{
 		dtPolyRef ref = polys[i];
 		dtPolyRef ref = polys[i];
 		float closestPtPoly[3];
 		float closestPtPoly[3];
-		closestPointOnPoly(ref, center, closestPtPoly);
-		float d = dtVdistSqr(center, closestPtPoly);
+		float diff[3];
+		bool posOverPoly = false;
+		float d = 0;
+		closestPointOnPoly(ref, center, closestPtPoly, &posOverPoly);
+
+		// If a point is directly over a polygon and closer than
+		// climb height, favor that instead of straight line nearest point.
+		dtVsub(diff, center, closestPtPoly);
+		if (posOverPoly)
+		{
+			const dtMeshTile* tile = 0;
+			const dtPoly* poly = 0;
+			m_nav->getTileAndPolyByRefUnsafe(polys[i], &tile, &poly);
+			d = dtAbs(diff[1]) - tile->header->walkableClimb;
+			d = d > 0 ? d*d : 0;			
+		}
+		else
+		{
+			d = dtVlenSqr(diff);
+		}
+		
 		if (d < nearestDistanceSqr)
 		if (d < nearestDistanceSqr)
 		{
 		{
 			if (nearestPt)
 			if (nearestPt)
@@ -764,42 +763,6 @@ dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* exten
 	return DT_SUCCESS;
 	return DT_SUCCESS;
 }
 }
 
 
-dtPolyRef dtNavMeshQuery::findNearestPolyInTile(const dtMeshTile* tile, const float* center, const float* extents,
-												const dtQueryFilter* filter, float* nearestPt) const
-{
-	dtAssert(m_nav);
-	
-	float bmin[3], bmax[3];
-	dtVsub(bmin, center, extents);
-	dtVadd(bmax, center, extents);
-	
-	// Get nearby polygons from proximity grid.
-	dtPolyRef polys[128];
-	int polyCount = queryPolygonsInTile(tile, bmin, bmax, filter, polys, 128);
-	
-	// Find nearest polygon amongst the nearby polygons.
-	dtPolyRef nearest = 0;
-	float nearestDistanceSqr = FLT_MAX;
-	for (int i = 0; i < polyCount; ++i)
-	{
-		dtPolyRef ref = polys[i];
-		const dtPoly* poly = &tile->polys[m_nav->decodePolyIdPoly(ref)];
-		float closestPtPoly[3];
-		closestPointOnPolyInTile(tile, poly, center, closestPtPoly);
-			
-		float d = dtVdistSqr(center, closestPtPoly);
-		if (d < nearestDistanceSqr)
-		{
-			if (nearestPt)
-				dtVcopy(nearestPt, closestPtPoly);
-			nearestDistanceSqr = d;
-			nearest = ref;
-		}
-	}
-	
-	return nearest;
-}
-
 int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
 int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
 										const dtQueryFilter* filter,
 										const dtQueryFilter* filter,
 										dtPolyRef* polys, const int maxPolys) const
 										dtPolyRef* polys, const int maxPolys) const
@@ -3342,7 +3305,7 @@ dtStatus dtNavMeshQuery::findDistanceToWall(dtPolyRef startRef, const float* cen
 	dtVsub(hitNormal, centerPos, hitPos);
 	dtVsub(hitNormal, centerPos, hitPos);
 	dtVnormalize(hitNormal);
 	dtVnormalize(hitNormal);
 	
 	
-	*hitDist = sqrtf(radiusSqr);
+	*hitDist = dtMathSqrtf(radiusSqr);
 	
 	
 	return status;
 	return status;
 }
 }

+ 14 - 0
Source/ThirdParty/Detour/source/DetourNode.cpp

@@ -22,6 +22,19 @@
 #include "DetourCommon.h"
 #include "DetourCommon.h"
 #include <string.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)
 inline unsigned int dtHashRef(dtPolyRef a)
 {
 {
 	a += ~(a<<15);
 	a += ~(a<<15);
@@ -32,6 +45,7 @@ inline unsigned int dtHashRef(dtPolyRef a)
 	a ^=  (a>>16);
 	a ^=  (a>>16);
 	return (unsigned int)a;
 	return (unsigned int)a;
 }
 }
+#endif
 
 
 //////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////
 dtNodePool::dtNodePool(int maxNodes, int hashSize) :
 dtNodePool::dtNodePool(int maxNodes, int hashSize) :

+ 6 - 1
Source/ThirdParty/Recast/include/Recast.h

@@ -219,7 +219,7 @@ struct rcConfig
 	int maxEdgeLen;
 	int maxEdgeLen;
 	
 	
 	/// The maximum distance a simplfied contour's border edges should deviate 
 	/// The maximum distance a simplfied contour's border edges should deviate 
-	/// the original raw contour. [Limit: >=0] [Units: wu]
+	/// the original raw contour. [Limit: >=0] [Units: vx]
 	float maxSimplificationError;
 	float maxSimplificationError;
 	
 	
 	/// The minimum number of cells allowed to form isolated island areas. [Limit: >=0] [Units: vx] 
 	/// The minimum number of cells allowed to form isolated island areas. [Limit: >=0] [Units: vx] 
@@ -549,6 +549,11 @@ static const int RC_NOT_CONNECTED = 0x3f;
 /// @name General helper functions
 /// @name General helper functions
 /// @{
 /// @{
 
 
+/// Used to ignore a function parameter.  VS complains about unused parameters
+/// and this silences the warning.
+///  @param [in] _ Unused parameter
+template<class T> void rcIgnoreUnused(const T&) { }
+
 /// Swaps the values of the two parameters.
 /// Swaps the values of the two parameters.
 ///  @param[in,out]	a	Value A
 ///  @param[in,out]	a	Value A
 ///  @param[in,out]	b	Value B
 ///  @param[in,out]	b	Value B

+ 8 - 12
Source/ThirdParty/Recast/source/Recast.cpp

@@ -208,12 +208,11 @@ void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int*
 /// See the #rcConfig documentation for more information on the configuration parameters.
 /// See the #rcConfig documentation for more information on the configuration parameters.
 /// 
 /// 
 /// @see rcAllocHeightfield, rcHeightfield 
 /// @see rcAllocHeightfield, rcHeightfield 
-bool rcCreateHeightfield(rcContext* /*ctx*/, rcHeightfield& hf, int width, int height,
+bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height,
 						 const float* bmin, const float* bmax,
 						 const float* bmin, const float* bmax,
 						 float cs, float ch)
 						 float cs, float ch)
 {
 {
-	// TODO: VC complains about unref formal variable, figure out a way to handle this better.
-//	rcAssert(ctx);
+	rcIgnoreUnused(ctx);
 	
 	
 	hf.width = width;
 	hf.width = width;
 	hf.height = height;
 	hf.height = height;
@@ -245,13 +244,12 @@ static void calcTriNormal(const float* v0, const float* v1, const float* v2, flo
 /// See the #rcConfig documentation for more information on the configuration parameters.
 /// See the #rcConfig documentation for more information on the configuration parameters.
 /// 
 /// 
 /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
 /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
-void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
+void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
 							 const float* verts, int /*nv*/,
 							 const float* verts, int /*nv*/,
 							 const int* tris, int nt,
 							 const int* tris, int nt,
 							 unsigned char* areas)
 							 unsigned char* areas)
 {
 {
-	// TODO: VC complains about unref formal variable, figure out a way to handle this better.
-//	rcAssert(ctx);
+	rcIgnoreUnused(ctx);
 	
 	
 	const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
 	const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
 
 
@@ -275,13 +273,12 @@ void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
 /// See the #rcConfig documentation for more information on the configuration parameters.
 /// See the #rcConfig documentation for more information on the configuration parameters.
 /// 
 /// 
 /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
 /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
-void rcClearUnwalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
+void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
 								const float* verts, int /*nv*/,
 								const float* verts, int /*nv*/,
 								const int* tris, int nt,
 								const int* tris, int nt,
 								unsigned char* areas)
 								unsigned char* areas)
 {
 {
-	// TODO: VC complains about unref formal variable, figure out a way to handle this better.
-//	rcAssert(ctx);
+	rcIgnoreUnused(ctx);
 	
 	
 	const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
 	const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
 	
 	
@@ -297,10 +294,9 @@ void rcClearUnwalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAng
 	}
 	}
 }
 }
 
 
-int rcGetHeightFieldSpanCount(rcContext* /*ctx*/, rcHeightfield& hf)
+int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf)
 {
 {
-	// TODO: VC complains about unref formal variable, figure out a way to handle this better.
-//	rcAssert(ctx);
+	rcIgnoreUnused(ctx);
 	
 	
 	const int w = hf.width;
 	const int w = hf.width;
 	const int h = hf.height;
 	const int h = hf.height;

+ 2 - 2
Source/ThirdParty/Recast/source/RecastLayers.cpp

@@ -325,7 +325,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
 					continue;
 					continue;
 				// Skip if the height range would become too large.
 				// Skip if the height range would become too large.
 				const int ymin = rcMin(root.ymin, regn.ymin);
 				const int ymin = rcMin(root.ymin, regn.ymin);
-				const int ymax = rcMin(root.ymax, regn.ymax);
+				const int ymax = rcMax(root.ymax, regn.ymax);
 				if ((ymax - ymin) >= 255)
 				if ((ymax - ymin) >= 255)
 					 continue;
 					 continue;
 
 
@@ -373,7 +373,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
 					continue;
 					continue;
 				// Skip if the height range would become too large.
 				// Skip if the height range would become too large.
 				const int ymin = rcMin(ri.ymin, rj.ymin);
 				const int ymin = rcMin(ri.ymin, rj.ymin);
-				const int ymax = rcMin(ri.ymax, rj.ymax);
+				const int ymax = rcMax(ri.ymax, rj.ymax);
 				if ((ymax - ymin) >= 255)
 				if ((ymax - ymin) >= 255)
 				  continue;
 				  continue;
 						  
 						  

+ 44 - 3
Source/ThirdParty/Recast/source/RecastMesh.cpp

@@ -661,7 +661,8 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
 			}
 			}
 			// Remove the polygon.
 			// Remove the polygon.
 			unsigned short* p2 = &mesh.polys[(mesh.npolys-1)*nvp*2];
 			unsigned short* p2 = &mesh.polys[(mesh.npolys-1)*nvp*2];
-			memcpy(p,p2,sizeof(unsigned short)*nvp);
+			if (p != p2)
+				memcpy(p,p2,sizeof(unsigned short)*nvp);
 			memset(p+nvp,0xff,sizeof(unsigned short)*nvp);
 			memset(p+nvp,0xff,sizeof(unsigned short)*nvp);
 			mesh.regs[i] = mesh.regs[mesh.npolys-1];
 			mesh.regs[i] = mesh.regs[mesh.npolys-1];
 			mesh.areas[i] = mesh.areas[mesh.npolys-1];
 			mesh.areas[i] = mesh.areas[mesh.npolys-1];
@@ -861,7 +862,9 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
 				unsigned short* pa = &polys[bestPa*nvp];
 				unsigned short* pa = &polys[bestPa*nvp];
 				unsigned short* pb = &polys[bestPb*nvp];
 				unsigned short* pb = &polys[bestPb*nvp];
 				mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp);
 				mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp);
-				memcpy(pb, &polys[(npolys-1)*nvp], sizeof(unsigned short)*nvp);
+				unsigned short* last = &polys[(npolys-1)*nvp];
+				if (pb != last)
+					memcpy(pb, last, sizeof(unsigned short)*nvp);
 				pregs[bestPb] = pregs[npolys-1];
 				pregs[bestPb] = pregs[npolys-1];
 				pareas[bestPb] = pareas[npolys-1];
 				pareas[bestPb] = pareas[npolys-1];
 				npolys--;
 				npolys--;
@@ -1105,7 +1108,9 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
 					unsigned short* pa = &polys[bestPa*nvp];
 					unsigned short* pa = &polys[bestPa*nvp];
 					unsigned short* pb = &polys[bestPb*nvp];
 					unsigned short* pb = &polys[bestPb*nvp];
 					mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp);
 					mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp);
-					memcpy(pb, &polys[(npolys-1)*nvp], sizeof(unsigned short)*nvp);
+					unsigned short* lastPoly = &polys[(npolys-1)*nvp];
+					if (pb != lastPoly)
+						memcpy(pb, lastPoly, sizeof(unsigned short)*nvp);
 					npolys--;
 					npolys--;
 				}
 				}
 				else
 				else
@@ -1319,6 +1324,12 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
 		const unsigned short ox = (unsigned short)floorf((pmesh->bmin[0]-mesh.bmin[0])/mesh.cs+0.5f);
 		const unsigned short ox = (unsigned short)floorf((pmesh->bmin[0]-mesh.bmin[0])/mesh.cs+0.5f);
 		const unsigned short oz = (unsigned short)floorf((pmesh->bmin[2]-mesh.bmin[2])/mesh.cs+0.5f);
 		const unsigned short oz = (unsigned short)floorf((pmesh->bmin[2]-mesh.bmin[2])/mesh.cs+0.5f);
 		
 		
+		bool isMinX = (ox == 0);
+		bool isMinZ = (oz == 0);
+		bool isMaxX = ((unsigned short)floorf((mesh.bmax[0] - pmesh->bmax[0]) / mesh.cs + 0.5f)) == 0;
+		bool isMaxZ = ((unsigned short)floorf((mesh.bmax[2] - pmesh->bmax[2]) / mesh.cs + 0.5f)) == 0;
+		bool isOnBorder = (isMinX || isMinZ || isMaxX || isMaxZ);
+
 		for (int j = 0; j < pmesh->nverts; ++j)
 		for (int j = 0; j < pmesh->nverts; ++j)
 		{
 		{
 			unsigned short* v = &pmesh->verts[j*3];
 			unsigned short* v = &pmesh->verts[j*3];
@@ -1339,6 +1350,36 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
 				if (src[k] == RC_MESH_NULL_IDX) break;
 				if (src[k] == RC_MESH_NULL_IDX) break;
 				tgt[k] = vremap[src[k]];
 				tgt[k] = vremap[src[k]];
 			}
 			}
+
+			if (isOnBorder)
+			{
+				for (int k = mesh.nvp; k < mesh.nvp * 2; ++k)
+				{
+					if (src[k] & 0x8000 && src[k] != 0xffff)
+					{
+						unsigned short dir = src[k] & 0xf;
+						switch (dir)
+						{
+							case 0: // Portal x-
+								if (isMinX)
+									tgt[k] = src[k];
+								break;
+							case 1: // Portal z+
+								if (isMaxZ)
+									tgt[k] = src[k];
+								break;
+							case 2: // Portal x+
+								if (isMaxX)
+									tgt[k] = src[k];
+								break;
+							case 3: // Portal z-
+								if (isMinZ)
+									tgt[k] = src[k];
+								break;
+						}
+					}
+				}
+			}
 		}
 		}
 	}
 	}
 
 

+ 87 - 13
Source/ThirdParty/Recast/source/RecastMeshDetail.cpp

@@ -200,8 +200,8 @@ static unsigned short getHeight(const float fx, const float fy, const float fz,
 {
 {
 	int ix = (int)floorf(fx*ics + 0.01f);
 	int ix = (int)floorf(fx*ics + 0.01f);
 	int iz = (int)floorf(fz*ics + 0.01f);
 	int iz = (int)floorf(fz*ics + 0.01f);
-	ix = rcClamp(ix-hp.xmin, 0, hp.width);
-	iz = rcClamp(iz-hp.ymin, 0, hp.height);
+	ix = rcClamp(ix-hp.xmin, 0, hp.width - 1);
+	iz = rcClamp(iz-hp.ymin, 0, hp.height - 1);
 	unsigned short h = hp.data[ix+iz*hp.width];
 	unsigned short h = hp.data[ix+iz*hp.width];
 	if (h == RC_UNSET_HEIGHT)
 	if (h == RC_UNSET_HEIGHT)
 	{
 	{
@@ -741,7 +741,8 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
 	return true;
 	return true;
 }
 }
 
 
-static void getHeightData(const rcCompactHeightfield& chf,
+
+static void getHeightDataSeedsFromVertices(const rcCompactHeightfield& chf,
 						  const unsigned short* poly, const int npoly,
 						  const unsigned short* poly, const int npoly,
 						  const unsigned short* verts, const int bs,
 						  const unsigned short* verts, const int bs,
 						  rcHeightPatch& hp, rcIntArray& stack)
 						  rcHeightPatch& hp, rcIntArray& stack)
@@ -869,8 +870,83 @@ static void getHeightData(const rcCompactHeightfield& chf,
 		int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width;
 		int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width;
 		const rcCompactSpan& cs = chf.spans[ci];
 		const rcCompactSpan& cs = chf.spans[ci];
 		hp.data[idx] = cs.y;
 		hp.data[idx] = cs.y;
+
+		// getHeightData seeds are given in coordinates with borders 
+		stack[i+0] += bs;
+		stack[i+1] += bs;
 	}
 	}
 	
 	
+}
+
+
+
+static void getHeightData(const rcCompactHeightfield& chf,
+						  const unsigned short* poly, const int npoly,
+						  const unsigned short* verts, const int bs,
+						  rcHeightPatch& hp, rcIntArray& stack,
+						  int region)
+{
+	// Note: Reads to the compact heightfield are offset by border size (bs)
+	// since border size offset is already removed from the polymesh vertices.
+
+	stack.resize(0);
+	memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height);
+	
+	bool empty = true;
+
+	// Copy the height from the same region, and mark region borders
+	// as seed points to fill the rest.
+	for (int hy = 0; hy < hp.height; hy++)
+	{
+		int y = hp.ymin + hy + bs;
+		for (int hx = 0; hx < hp.width; hx++)
+		{
+			int x = hp.xmin + hx + bs;
+			const rcCompactCell& c = chf.cells[x+y*chf.width];
+			for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
+			{
+				const rcCompactSpan& s = chf.spans[i];
+				if (s.reg == region)
+				{
+					// Store height
+					hp.data[hx + hy*hp.width] = s.y;
+					empty = false;
+
+					// If any of the neighbours is not in same region,
+					// add the current location as flood fill start
+					bool border = false;
+					for (int dir = 0; dir < 4; ++dir)
+					{
+						if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
+						{
+							const int ax = x + rcGetDirOffsetX(dir);
+							const int ay = y + rcGetDirOffsetY(dir);
+							const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir);
+							const rcCompactSpan& as = chf.spans[ai];
+							if (as.reg != region)
+							{
+								border = true;
+								break;
+							}
+						}
+					}
+					if (border)
+					{
+						stack.push(x);
+						stack.push(y);
+						stack.push(i);
+					}
+					break;
+				}
+			}
+		}
+	}	
+
+	// if the polygon does not contian any points from the current region (rare, but happens)
+	// then use the cells closest to the polygon vertices as seeds to fill the height field
+	if (empty)
+		getHeightDataSeedsFromVertices(chf, poly, npoly, verts, bs, hp, stack);
+	
 	static const int RETRACT_SIZE = 256;
 	static const int RETRACT_SIZE = 256;
 	int head = 0;
 	int head = 0;
 	
 	
@@ -895,26 +971,25 @@ static void getHeightData(const rcCompactHeightfield& chf,
 			
 			
 			const int ax = cx + rcGetDirOffsetX(dir);
 			const int ax = cx + rcGetDirOffsetX(dir);
 			const int ay = cy + rcGetDirOffsetY(dir);
 			const int ay = cy + rcGetDirOffsetY(dir);
+			const int hx = ax - hp.xmin - bs;
+			const int hy = ay - hp.ymin - bs;
 			
 			
-			if (ax < hp.xmin || ax >= (hp.xmin+hp.width) ||
-				ay < hp.ymin || ay >= (hp.ymin+hp.height))
+			if (hx < 0 || hx >= hp.width || hy < 0 || hy >= hp.height)
 				continue;
 				continue;
 			
 			
-			if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != RC_UNSET_HEIGHT)
+			if (hp.data[hx + hy*hp.width] != RC_UNSET_HEIGHT)
 				continue;
 				continue;
 			
 			
-			const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir);
-			
+			const int ai = (int)chf.cells[ax + ay*chf.width].index + rcGetCon(cs, dir);
 			const rcCompactSpan& as = chf.spans[ai];
 			const rcCompactSpan& as = chf.spans[ai];
-			int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width;
-			hp.data[idx] = as.y;
+
+			hp.data[hx + hy*hp.width] = as.y;
 
 
 			stack.push(ax);
 			stack.push(ax);
 			stack.push(ay);
 			stack.push(ay);
 			stack.push(ai);
 			stack.push(ai);
 		}
 		}
 	}
 	}
-	
 }
 }
 
 
 static unsigned char getEdgeFlags(const float* va, const float* vb,
 static unsigned char getEdgeFlags(const float* va, const float* vb,
@@ -1072,7 +1147,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
 		hp.ymin = bounds[i*4+2];
 		hp.ymin = bounds[i*4+2];
 		hp.width = bounds[i*4+1]-bounds[i*4+0];
 		hp.width = bounds[i*4+1]-bounds[i*4+0];
 		hp.height = bounds[i*4+3]-bounds[i*4+2];
 		hp.height = bounds[i*4+3]-bounds[i*4+2];
-		getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack);
+		getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack, mesh.regs[i]);
 		
 		
 		// Build detail mesh.
 		// Build detail mesh.
 		int nverts = 0;
 		int nverts = 0;
@@ -1242,4 +1317,3 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
 	
 	
 	return true;
 	return true;
 }
 }
-

+ 75 - 38
Source/ThirdParty/Recast/source/RecastRasterization.cpp

@@ -95,7 +95,7 @@ static void addSpan(rcHeightfield& hf, const int x, const int y,
 	s->area = area;
 	s->area = area;
 	s->next = 0;
 	s->next = 0;
 	
 	
-	// Empty cell, add he first span.
+	// Empty cell, add the first span.
 	if (!hf.spans[idx])
 	if (!hf.spans[idx])
 	{
 	{
 		hf.spans[idx] = s;
 		hf.spans[idx] = s;
@@ -169,36 +169,64 @@ void rcAddSpan(rcContext* /*ctx*/, rcHeightfield& hf, const int x, const int y,
 	addSpan(hf, x,y, smin, smax, area, flagMergeThr);
 	addSpan(hf, x,y, smin, smax, area, flagMergeThr);
 }
 }
 
 
-static int clipPoly(const float* in, int n, float* out, float pnx, float pnz, float pd)
+// divides a convex polygons into two convex polygons on both sides of a line
+static void dividePoly(const float* in, int nin,
+					  float* out1, int* nout1,
+					  float* out2, int* nout2,
+					  float x, int axis)
 {
 {
 	float d[12];
 	float d[12];
-	for (int i = 0; i < n; ++i)
-		d[i] = pnx*in[i*3+0] + pnz*in[i*3+2] + pd;
-	
-	int m = 0;
-	for (int i = 0, j = n-1; i < n; j=i, ++i)
+	for (int i = 0; i < nin; ++i)
+		d[i] = x - in[i*3+axis];
+
+	int m = 0, n = 0;
+	for (int i = 0, j = nin-1; i < nin; j=i, ++i)
 	{
 	{
 		bool ina = d[j] >= 0;
 		bool ina = d[j] >= 0;
 		bool inb = d[i] >= 0;
 		bool inb = d[i] >= 0;
 		if (ina != inb)
 		if (ina != inb)
 		{
 		{
 			float s = d[j] / (d[j] - d[i]);
 			float s = d[j] / (d[j] - d[i]);
-			out[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
-			out[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
-			out[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
+			out1[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
+			out1[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
+			out1[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
+			rcVcopy(out2 + n*3, out1 + m*3);
 			m++;
 			m++;
+			n++;
+			// add the i'th point to the right polygon. Do NOT add points that are on the dividing line
+			// since these were already added above
+			if (d[i] > 0)
+			{
+				rcVcopy(out1 + m*3, in + i*3);
+				m++;
+			}
+			else if (d[i] < 0)
+			{
+				rcVcopy(out2 + n*3, in + i*3);
+				n++;
+			}
 		}
 		}
-		if (inb)
+		else // same side
 		{
 		{
-			out[m*3+0] = in[i*3+0];
-			out[m*3+1] = in[i*3+1];
-			out[m*3+2] = in[i*3+2];
-			m++;
+			// add the i'th point to the right polygon. Addition is done even for points on the dividing line
+			if (d[i] >= 0)
+			{
+				rcVcopy(out1 + m*3, in + i*3);
+				m++;
+				if (d[i] != 0)
+					continue;
+			}
+			rcVcopy(out2 + n*3, in + i*3);
+			n++;
 		}
 		}
 	}
 	}
-	return m;
+
+	*nout1 = m;
+	*nout2 = n;
 }
 }
 
 
+
+
 static void rasterizeTri(const float* v0, const float* v1, const float* v2,
 static void rasterizeTri(const float* v0, const float* v1, const float* v2,
 						 const unsigned char area, rcHeightfield& hf,
 						 const unsigned char area, rcHeightfield& hf,
 						 const float* bmin, const float* bmax,
 						 const float* bmin, const float* bmax,
@@ -222,48 +250,57 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2,
 	if (!overlapBounds(bmin, bmax, tmin, tmax))
 	if (!overlapBounds(bmin, bmax, tmin, tmax))
 		return;
 		return;
 	
 	
-	// Calculate the footpring of the triangle on the grid.
-	int x0 = (int)((tmin[0] - bmin[0])*ics);
+	// Calculate the footprint of the triangle on the grid's y-axis
 	int y0 = (int)((tmin[2] - bmin[2])*ics);
 	int y0 = (int)((tmin[2] - bmin[2])*ics);
-	int x1 = (int)((tmax[0] - bmin[0])*ics);
 	int y1 = (int)((tmax[2] - bmin[2])*ics);
 	int y1 = (int)((tmax[2] - bmin[2])*ics);
-	x0 = rcClamp(x0, 0, w-1);
 	y0 = rcClamp(y0, 0, h-1);
 	y0 = rcClamp(y0, 0, h-1);
-	x1 = rcClamp(x1, 0, w-1);
 	y1 = rcClamp(y1, 0, h-1);
 	y1 = rcClamp(y1, 0, h-1);
 	
 	
 	// Clip the triangle into all grid cells it touches.
 	// Clip the triangle into all grid cells it touches.
-	float in[7*3], out[7*3], inrow[7*3];
+	float buf[7*3*4];
+	float *in = buf, *inrow = buf+7*3, *p1 = inrow+7*3, *p2 = p1+7*3;
+
+	rcVcopy(&in[0], v0);
+	rcVcopy(&in[1*3], v1);
+	rcVcopy(&in[2*3], v2);
+	int nvrow, nvIn = 3;
 	
 	
 	for (int y = y0; y <= y1; ++y)
 	for (int y = y0; y <= y1; ++y)
 	{
 	{
-		// Clip polygon to row.
-		rcVcopy(&in[0], v0);
-		rcVcopy(&in[1*3], v1);
-		rcVcopy(&in[2*3], v2);
-		int nvrow = 3;
+		// Clip polygon to row. Store the remaining polygon as well
 		const float cz = bmin[2] + y*cs;
 		const float cz = bmin[2] + y*cs;
-		nvrow = clipPoly(in, nvrow, out, 0, 1, -cz);
-		if (nvrow < 3) continue;
-		nvrow = clipPoly(out, nvrow, inrow, 0, -1, cz+cs);
+		dividePoly(in, nvIn, inrow, &nvrow, p1, &nvIn, cz+cs, 2);
+		rcSwap(in, p1);
 		if (nvrow < 3) continue;
 		if (nvrow < 3) continue;
 		
 		
+		// find the horizontal bounds in the row
+		float minX = inrow[0], maxX = inrow[0];
+		for (int i=1; i<nvrow; ++i)
+		{
+			if (minX > inrow[i*3])	minX = inrow[i*3];
+			if (maxX < inrow[i*3])	maxX = inrow[i*3];
+		}
+		int x0 = (int)((minX - bmin[0])*ics);
+		int x1 = (int)((maxX - bmin[0])*ics);
+		x0 = rcClamp(x0, 0, w-1);
+		x1 = rcClamp(x1, 0, w-1);
+
+		int nv, nv2 = nvrow;
+
 		for (int x = x0; x <= x1; ++x)
 		for (int x = x0; x <= x1; ++x)
 		{
 		{
-			// Clip polygon to column.
-			int nv = nvrow;
+			// Clip polygon to column. store the remaining polygon as well
 			const float cx = bmin[0] + x*cs;
 			const float cx = bmin[0] + x*cs;
-			nv = clipPoly(inrow, nv, out, 1, 0, -cx);
-			if (nv < 3) continue;
-			nv = clipPoly(out, nv, in, -1, 0, cx+cs);
+			dividePoly(inrow, nv2, p1, &nv, p2, &nv2, cx+cs, 0);
+			rcSwap(inrow, p2);
 			if (nv < 3) continue;
 			if (nv < 3) continue;
 			
 			
 			// Calculate min and max of the span.
 			// Calculate min and max of the span.
-			float smin = in[1], smax = in[1];
+			float smin = p1[1], smax = p1[1];
 			for (int i = 1; i < nv; ++i)
 			for (int i = 1; i < nv; ++i)
 			{
 			{
-				smin = rcMin(smin, in[i*3+1]);
-				smax = rcMax(smax, in[i*3+1]);
+				smin = rcMin(smin, p1[i*3+1]);
+				smax = rcMax(smax, p1[i*3+1]);
 			}
 			}
 			smin -= bmin[1];
 			smin -= bmin[1];
 			smax -= bmin[1];
 			smax -= bmin[1];

+ 115 - 26
Source/ThirdParty/Recast/source/RecastRegion.cpp

@@ -286,7 +286,10 @@ static bool floodRegion(int x, int y, int i,
 				if (nr & RC_BORDER_REG) // Do not take borders into account.
 				if (nr & RC_BORDER_REG) // Do not take borders into account.
 					continue;
 					continue;
 				if (nr != 0 && nr != r)
 				if (nr != 0 && nr != r)
+				{
 					ar = nr;
 					ar = nr;
+					break;
+				}
 				
 				
 				const rcCompactSpan& as = chf.spans[ai];
 				const rcCompactSpan& as = chf.spans[ai];
 				
 				
@@ -300,7 +303,10 @@ static bool floodRegion(int x, int y, int i,
 						continue;
 						continue;
 					unsigned short nr2 = srcReg[ai2];
 					unsigned short nr2 = srcReg[ai2];
 					if (nr2 != 0 && nr2 != r)
 					if (nr2 != 0 && nr2 != r)
+					{
 						ar = nr2;
 						ar = nr2;
+						break;
+					}
 				}				
 				}				
 			}
 			}
 		}
 		}
@@ -340,30 +346,44 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
 									 rcCompactHeightfield& chf,
 									 rcCompactHeightfield& chf,
 									 unsigned short* srcReg, unsigned short* srcDist,
 									 unsigned short* srcReg, unsigned short* srcDist,
 									 unsigned short* dstReg, unsigned short* dstDist, 
 									 unsigned short* dstReg, unsigned short* dstDist, 
-									 rcIntArray& stack)
+									 rcIntArray& stack,
+									 bool fillStack)
 {
 {
 	const int w = chf.width;
 	const int w = chf.width;
 	const int h = chf.height;
 	const int h = chf.height;
 
 
-	// Find cells revealed by the raised level.
-	stack.resize(0);
-	for (int y = 0; y < h; ++y)
+	if (fillStack)
 	{
 	{
-		for (int x = 0; x < w; ++x)
+		// Find cells revealed by the raised level.
+		stack.resize(0);
+		for (int y = 0; y < h; ++y)
 		{
 		{
-			const rcCompactCell& c = chf.cells[x+y*w];
-			for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
+			for (int x = 0; x < w; ++x)
 			{
 			{
-				if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
+				const rcCompactCell& c = chf.cells[x+y*w];
+				for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
 				{
 				{
-					stack.push(x);
-					stack.push(y);
-					stack.push(i);
+					if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
+					{
+						stack.push(x);
+						stack.push(y);
+						stack.push(i);
+					}
 				}
 				}
 			}
 			}
 		}
 		}
 	}
 	}
-	
+	else // use cells in the input stack
+	{
+		// mark all cells which already have a region
+		for (int j=0; j<stack.size(); j+=3)
+		{
+			int i = stack[j+2];
+			if (srcReg[i] != 0)
+				stack[j+2] = -1;
+		}
+	}
+
 	int iter = 0;
 	int iter = 0;
 	while (stack.size() > 0)
 	while (stack.size() > 0)
 	{
 	{
@@ -434,6 +454,61 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
 }
 }
 
 
 
 
+
+static void sortCellsByLevel(unsigned short startLevel,
+							  rcCompactHeightfield& chf,
+							  unsigned short* srcReg,
+							  unsigned int nbStacks, rcIntArray* stacks,
+							  unsigned short loglevelsPerStack) // the levels per stack (2 in our case) as a bit shift
+{
+	const int w = chf.width;
+	const int h = chf.height;
+	startLevel = startLevel >> loglevelsPerStack;
+
+	for (unsigned int j=0; j<nbStacks; ++j)
+		stacks[j].resize(0);
+
+	// put all cells in the level range into the appropriate stacks
+	for (int y = 0; y < h; ++y)
+	{
+		for (int x = 0; x < w; ++x)
+		{
+			const rcCompactCell& c = chf.cells[x+y*w];
+			for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
+			{
+				if (chf.areas[i] == RC_NULL_AREA || srcReg[i] != 0)
+					continue;
+
+				int level = chf.dist[i] >> loglevelsPerStack;
+				int sId = startLevel - level;
+				if (sId >= (int)nbStacks)
+					continue;
+				if (sId < 0)
+					sId = 0;
+
+				stacks[sId].push(x);
+				stacks[sId].push(y);
+				stacks[sId].push(i);
+			}
+		}
+	}
+}
+
+
+static void appendStacks(rcIntArray& srcStack, rcIntArray& dstStack,
+						 unsigned short* srcReg)
+{
+	for (int j=0; j<srcStack.size(); j+=3)
+	{
+		int i = srcStack[j+2];
+		if ((i < 0) || (srcReg[i] != 0))
+			continue;
+		dstStack.push(srcStack[j]);
+		dstStack.push(srcStack[j+1]);
+		dstStack.push(srcStack[j+2]);
+	}
+}
+
 struct rcRegion
 struct rcRegion
 {
 {
 	inline rcRegion(unsigned short i) :
 	inline rcRegion(unsigned short i) :
@@ -1236,7 +1311,13 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
 	}
 	}
 	
 	
 	ctx->startTimer(RC_TIMER_BUILD_REGIONS_WATERSHED);
 	ctx->startTimer(RC_TIMER_BUILD_REGIONS_WATERSHED);
-	
+
+	const int LOG_NB_STACKS = 3;
+	const int NB_STACKS = 1 << LOG_NB_STACKS;
+	rcIntArray lvlStacks[NB_STACKS];
+	for (int i=0; i<NB_STACKS; ++i)
+		lvlStacks[i].resize(1024);
+
 	rcIntArray stack(1024);
 	rcIntArray stack(1024);
 	rcIntArray visited(1024);
 	rcIntArray visited(1024);
 	
 	
@@ -1271,14 +1352,25 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
 		chf.borderSize = borderSize;
 		chf.borderSize = borderSize;
 	}
 	}
 	
 	
+	int sId = -1;
 	while (level > 0)
 	while (level > 0)
 	{
 	{
 		level = level >= 2 ? level-2 : 0;
 		level = level >= 2 ? level-2 : 0;
-		
+		sId = (sId+1) & (NB_STACKS-1);
+
+//		ctx->startTimer(RC_TIMER_DIVIDE_TO_LEVELS);
+
+		if (sId == 0)
+			sortCellsByLevel(level, chf, srcReg, NB_STACKS, lvlStacks, 1);
+		else 
+			appendStacks(lvlStacks[sId-1], lvlStacks[sId], srcReg); // copy left overs from last level
+
+//		ctx->stopTimer(RC_TIMER_DIVIDE_TO_LEVELS);
+
 		ctx->startTimer(RC_TIMER_BUILD_REGIONS_EXPAND);
 		ctx->startTimer(RC_TIMER_BUILD_REGIONS_EXPAND);
 		
 		
 		// Expand current regions until no empty connected cells found.
 		// Expand current regions until no empty connected cells found.
-		if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg)
+		if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, lvlStacks[sId], false) != srcReg)
 		{
 		{
 			rcSwap(srcReg, dstReg);
 			rcSwap(srcReg, dstReg);
 			rcSwap(srcDist, dstDist);
 			rcSwap(srcDist, dstDist);
@@ -1289,18 +1381,15 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
 		ctx->startTimer(RC_TIMER_BUILD_REGIONS_FLOOD);
 		ctx->startTimer(RC_TIMER_BUILD_REGIONS_FLOOD);
 		
 		
 		// Mark new regions with IDs.
 		// Mark new regions with IDs.
-		for (int y = 0; y < h; ++y)
+		for (int j=0; j<lvlStacks[sId].size(); j+=3)
 		{
 		{
-			for (int x = 0; x < w; ++x)
+			int x = lvlStacks[sId][j];
+			int y = lvlStacks[sId][j+1];
+			int i = lvlStacks[sId][j+2];
+			if (i >= 0 && srcReg[i] == 0)
 			{
 			{
-				const rcCompactCell& c = chf.cells[x+y*w];
-				for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
-				{
-					if (chf.dist[i] < level || srcReg[i] != 0 || chf.areas[i] == RC_NULL_AREA)
-						continue;
-					if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
-						regionId++;
-				}
+				if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
+					regionId++;
 			}
 			}
 		}
 		}
 		
 		
@@ -1308,7 +1397,7 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
 	}
 	}
 	
 	
 	// Expand current regions until no empty connected cells found.
 	// Expand current regions until no empty connected cells found.
-	if (expandRegions(expandIters*8, 0, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg)
+	if (expandRegions(expandIters*8, 0, chf, srcReg, srcDist, dstReg, dstDist, stack, true) != srcReg)
 	{
 	{
 		rcSwap(srcReg, dstReg);
 		rcSwap(srcReg, dstReg);
 		rcSwap(srcDist, dstDist);
 		rcSwap(srcDist, dstDist);