mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 10:37:03 +00:00
[Build] More Project build cleanup
This commit is contained in:
parent
d258cc922a
commit
4613154144
565 changed files with 26862 additions and 109982 deletions
43
dep/recastnavigation/.gitignore
vendored
Normal file
43
dep/recastnavigation/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
## Compiled source #
|
||||||
|
*.com
|
||||||
|
*.class
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
*.ilk
|
||||||
|
*.o
|
||||||
|
*.pdb
|
||||||
|
*.so
|
||||||
|
|
||||||
|
## Linux exes have no extension
|
||||||
|
RecastDemo/Bin/RecastDemo
|
||||||
|
|
||||||
|
# Build directory
|
||||||
|
RecastDemo/Build
|
||||||
|
|
||||||
|
# Ignore some meshes based on name
|
||||||
|
RecastDemo/Bin/Meshes/_*
|
||||||
|
|
||||||
|
## Logs and databases #
|
||||||
|
*.log
|
||||||
|
*.sql
|
||||||
|
*.sqlite
|
||||||
|
|
||||||
|
## OS generated files #
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
## xcode specific
|
||||||
|
*xcuserdata*
|
||||||
|
|
||||||
|
## SDL contrib
|
||||||
|
RecastDemo/Contrib/SDL/*
|
||||||
|
|
||||||
|
## Generated doc files
|
||||||
|
Docs/html
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
|
# MaNGOS is a full featured server for World of Warcraft, supporting
|
||||||
|
# the following clients: 1.12.x, 2.4.3, 3.2.5a, 4.2.3 and 5.4.8
|
||||||
|
#
|
||||||
|
# Copyright (C) 2005-2014 MaNGOS project <http://getmangos.eu>
|
||||||
|
#
|
||||||
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|
@ -13,6 +18,11 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# ***** END GPL LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
# World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||||
|
# and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||||
|
|
||||||
add_subdirectory(Detour)
|
add_subdirectory(Detour)
|
||||||
#add_subdirectory(Recast)
|
add_subdirectory(Recast)
|
||||||
|
|
|
||||||
46
dep/recastnavigation/DebugUtils/CMakeLists.txt
Normal file
46
dep/recastnavigation/DebugUtils/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
# MaNGOS is a full featured server for World of Warcraft, supporting
|
||||||
|
# the following clients: 1.12.x, 2.4.3, 3.2.5a, 4.2.3 and 5.4.8
|
||||||
|
#
|
||||||
|
# Copyright (C) 2005-2014 MaNGOS project <http://getmangos.eu>
|
||||||
|
#
|
||||||
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# ***** END GPL LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
# World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||||
|
# and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||||
|
|
||||||
|
include(MacroMangosSourceGroup)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# Define the DebugUtils library
|
||||||
|
file(GLOB sources Source/*.cpp)
|
||||||
|
file(GLOB headers Include/*.h)
|
||||||
|
|
||||||
|
set(DebugUtils_LIB_SRCS ${sources} ${headers})
|
||||||
|
|
||||||
|
mangos_source_group(${DebugUtils_LIB_SRCS})
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Include
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../Detour/Include/
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../Recast/Include/
|
||||||
|
)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# Build the DebugUtils library
|
||||||
|
add_library(DebugUtils STATIC ${DebugUtils_LIB_SRCS})
|
||||||
|
|
@ -30,33 +30,41 @@ enum duDebugDrawPrimitives
|
||||||
DU_DRAW_QUADS,
|
DU_DRAW_QUADS,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Abstrace debug draw interface.
|
/// Abstract debug draw interface.
|
||||||
struct duDebugDraw
|
struct duDebugDraw
|
||||||
{
|
{
|
||||||
virtual ~duDebugDraw() = 0;
|
virtual ~duDebugDraw() = 0;
|
||||||
|
|
||||||
virtual void depthMask(bool state) = 0;
|
virtual void depthMask(bool state) = 0;
|
||||||
|
|
||||||
// Begin drawing primitives.
|
virtual void texture(bool state) = 0;
|
||||||
// Params:
|
|
||||||
// prim - (in) primitive type to draw, one of rcDebugDrawPrimitives.
|
/// Begin drawing primitives.
|
||||||
// nverts - (in) number of vertices to be submitted.
|
/// @param prim [in] primitive type to draw, one of rcDebugDrawPrimitives.
|
||||||
// size - (in) size of a primitive, applies to point size and line width only.
|
/// @param size [in] size of a primitive, applies to point size and line width only.
|
||||||
virtual void begin(duDebugDrawPrimitives prim, float size = 1.0f) = 0;
|
virtual void begin(duDebugDrawPrimitives prim, float size = 1.0f) = 0;
|
||||||
|
|
||||||
// Submit a vertex
|
/// Submit a vertex
|
||||||
// Params:
|
/// @param pos [in] position of the verts.
|
||||||
// pos - (in) position of the verts.
|
/// @param color [in] color of the verts.
|
||||||
// color - (in) color of the verts.
|
|
||||||
virtual void vertex(const float* pos, unsigned int color) = 0;
|
virtual void vertex(const float* pos, unsigned int color) = 0;
|
||||||
|
|
||||||
// Submit a vertex
|
/// Submit a vertex
|
||||||
// Params:
|
/// @param x,y,z [in] position of the verts.
|
||||||
// x,y,z - (in) position of the verts.
|
/// @param color [in] color of the verts.
|
||||||
// color - (in) color of the verts.
|
|
||||||
virtual void vertex(const float x, const float y, const float z, unsigned int color) = 0;
|
virtual void vertex(const float x, const float y, const float z, unsigned int color) = 0;
|
||||||
|
|
||||||
// End drawing primitives.
|
/// Submit a vertex
|
||||||
|
/// @param pos [in] position of the verts.
|
||||||
|
/// @param color [in] color of the verts.
|
||||||
|
virtual void vertex(const float* pos, unsigned int color, const float* uv) = 0;
|
||||||
|
|
||||||
|
/// Submit a vertex
|
||||||
|
/// @param x,y,z [in] position of the verts.
|
||||||
|
/// @param color [in] color of the verts.
|
||||||
|
virtual void vertex(const float x, const float y, const float z, unsigned int color, const float u, const float v) = 0;
|
||||||
|
|
||||||
|
/// End drawing primitives.
|
||||||
virtual void end() = 0;
|
virtual void end() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,13 @@
|
||||||
|
|
||||||
#include "DetourNavMesh.h"
|
#include "DetourNavMesh.h"
|
||||||
#include "DetourNavMeshQuery.h"
|
#include "DetourNavMeshQuery.h"
|
||||||
|
#include "DetourTileCacheBuilder.h"
|
||||||
|
|
||||||
enum DrawNavMeshFlags
|
enum DrawNavMeshFlags
|
||||||
{
|
{
|
||||||
DU_DRAWNAVMESH_OFFMESHCONS = 0x01,
|
DU_DRAWNAVMESH_OFFMESHCONS = 0x01,
|
||||||
DU_DRAWNAVMESH_CLOSEDLIST = 0x02,
|
DU_DRAWNAVMESH_CLOSEDLIST = 0x02,
|
||||||
|
DU_DRAWNAVMESH_COLOR_TILES = 0x04,
|
||||||
};
|
};
|
||||||
|
|
||||||
void duDebugDrawNavMesh(struct duDebugDraw* dd, const dtNavMesh& mesh, unsigned char flags);
|
void duDebugDrawNavMesh(struct duDebugDraw* dd, const dtNavMesh& mesh, unsigned char flags);
|
||||||
|
|
@ -33,6 +35,14 @@ void duDebugDrawNavMeshWithClosedList(struct duDebugDraw* dd, const dtNavMesh& m
|
||||||
void duDebugDrawNavMeshNodes(struct duDebugDraw* dd, const dtNavMeshQuery& query);
|
void duDebugDrawNavMeshNodes(struct duDebugDraw* dd, const dtNavMeshQuery& query);
|
||||||
void duDebugDrawNavMeshBVTree(struct duDebugDraw* dd, const dtNavMesh& mesh);
|
void duDebugDrawNavMeshBVTree(struct duDebugDraw* dd, const dtNavMesh& mesh);
|
||||||
void duDebugDrawNavMeshPortals(struct duDebugDraw* dd, const dtNavMesh& mesh);
|
void duDebugDrawNavMeshPortals(struct duDebugDraw* dd, const dtNavMesh& mesh);
|
||||||
|
void duDebugDrawNavMeshPolysWithFlags(struct duDebugDraw* dd, const dtNavMesh& mesh, const unsigned short polyFlags, const unsigned int col);
|
||||||
void duDebugDrawNavMeshPoly(struct duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef ref, const unsigned int col);
|
void duDebugDrawNavMeshPoly(struct duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef ref, const unsigned int col);
|
||||||
|
|
||||||
|
void duDebugDrawTileCacheLayerAreas(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch);
|
||||||
|
void duDebugDrawTileCacheLayerRegions(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch);
|
||||||
|
void duDebugDrawTileCacheContours(duDebugDraw* dd, const struct dtTileCacheContourSet& lcset,
|
||||||
|
const float* orig, const float cs, const float ch);
|
||||||
|
void duDebugDrawTileCachePolyMesh(duDebugDraw* dd, const struct dtTileCachePolyMesh& lmesh,
|
||||||
|
const float* orig, const float cs, const float ch);
|
||||||
|
|
||||||
#endif // DETOURDEBUGDRAW_H
|
#endif // DETOURDEBUGDRAW_H
|
||||||
|
|
@ -19,8 +19,8 @@
|
||||||
#ifndef RECAST_DEBUGDRAW_H
|
#ifndef RECAST_DEBUGDRAW_H
|
||||||
#define RECAST_DEBUGDRAW_H
|
#define RECAST_DEBUGDRAW_H
|
||||||
|
|
||||||
void duDebugDrawTriMesh(struct duDebugDraw* dd, const float* verts, int nverts, const int* tris, const float* normals, int ntris, const unsigned char* flags);
|
void duDebugDrawTriMesh(struct duDebugDraw* dd, const float* verts, int nverts, const int* tris, const float* normals, int ntris, const unsigned char* flags, const float texScale);
|
||||||
void duDebugDrawTriMeshSlope(struct duDebugDraw* dd, const float* verts, int nverts, const int* tris, const float* normals, int ntris, const float walkableSlopeAngle);
|
void duDebugDrawTriMeshSlope(struct duDebugDraw* dd, const float* verts, int nverts, const int* tris, const float* normals, int ntris, const float walkableSlopeAngle, const float texScale);
|
||||||
|
|
||||||
void duDebugDrawHeightfieldSolid(struct duDebugDraw* dd, const struct rcHeightfield& hf);
|
void duDebugDrawHeightfieldSolid(struct duDebugDraw* dd, const struct rcHeightfield& hf);
|
||||||
void duDebugDrawHeightfieldWalkable(struct duDebugDraw* dd, const struct rcHeightfield& hf);
|
void duDebugDrawHeightfieldWalkable(struct duDebugDraw* dd, const struct rcHeightfield& hf);
|
||||||
|
|
@ -29,6 +29,10 @@ void duDebugDrawCompactHeightfieldSolid(struct duDebugDraw* dd, const struct rcC
|
||||||
void duDebugDrawCompactHeightfieldRegions(struct duDebugDraw* dd, const struct rcCompactHeightfield& chf);
|
void duDebugDrawCompactHeightfieldRegions(struct duDebugDraw* dd, const struct rcCompactHeightfield& chf);
|
||||||
void duDebugDrawCompactHeightfieldDistance(struct duDebugDraw* dd, const struct rcCompactHeightfield& chf);
|
void duDebugDrawCompactHeightfieldDistance(struct duDebugDraw* dd, const struct rcCompactHeightfield& chf);
|
||||||
|
|
||||||
|
void duDebugDrawHeightfieldLayer(duDebugDraw* dd, const struct rcHeightfieldLayer& layer, const int idx);
|
||||||
|
void duDebugDrawHeightfieldLayers(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset);
|
||||||
|
void duDebugDrawHeightfieldLayersRegions(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset);
|
||||||
|
|
||||||
void duDebugDrawRegionConnections(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f);
|
void duDebugDrawRegionConnections(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f);
|
||||||
void duDebugDrawRawContours(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f);
|
void duDebugDrawRawContours(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f);
|
||||||
void duDebugDrawContours(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f);
|
void duDebugDrawContours(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f);
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#define _USE_MATH_DEFINES
|
#define _USE_MATH_DEFINES
|
||||||
#include <math.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "DebugDraw.h"
|
#include "DebugDraw.h"
|
||||||
|
#include "DetourMath.h"
|
||||||
|
|
||||||
|
|
||||||
duDebugDraw::~duDebugDraw()
|
duDebugDraw::~duDebugDraw()
|
||||||
|
|
@ -130,7 +130,7 @@ void duDebugDrawBox(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||||
{
|
{
|
||||||
if (!dd) return;
|
if (!dd) return;
|
||||||
|
|
||||||
dd->begin(DU_DRAW_TRIS);
|
dd->begin(DU_DRAW_QUADS);
|
||||||
duAppendBox(dd, minx,miny,minz, maxx,maxy,maxz, fcol);
|
duAppendBox(dd, minx,miny,minz, maxx,maxy,maxz, fcol);
|
||||||
dd->end();
|
dd->end();
|
||||||
}
|
}
|
||||||
|
|
@ -180,8 +180,8 @@ void duAppendCylinderWire(struct duDebugDraw* dd, float minx, float miny, float
|
||||||
for (int i = 0; i < NUM_SEG; ++i)
|
for (int i = 0; i < NUM_SEG; ++i)
|
||||||
{
|
{
|
||||||
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
|
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
|
||||||
dir[i*2] = cosf(a);
|
dir[i*2] = dtMathCosf(a);
|
||||||
dir[i*2+1] = sinf(a);
|
dir[i*2+1] = dtMathSinf(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,12 @@
|
||||||
// 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 "DebugDraw.h"
|
#include "DebugDraw.h"
|
||||||
#include "DetourDebugDraw.h"
|
#include "DetourDebugDraw.h"
|
||||||
#include "DetourNavMesh.h"
|
#include "DetourNavMesh.h"
|
||||||
#include "DetourCommon.h"
|
#include "DetourCommon.h"
|
||||||
#include "DetourNode.h"
|
#include "DetourNode.h"
|
||||||
|
|
||||||
#include "../../RecastDemo/Include/Debug.h"
|
|
||||||
|
|
||||||
static float distancePtLine2d(const float* pt, const float* p, const float* q)
|
static float distancePtLine2d(const float* pt, const float* p, const float* q)
|
||||||
{
|
{
|
||||||
|
|
@ -73,7 +71,7 @@ static void drawPolyBoundaries(duDebugDraw* dd, const dtMeshTile* tile,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (con)
|
if (con)
|
||||||
c = duRGBA(255,255,255,24);
|
c = duRGBA(255,255,255,48);
|
||||||
else
|
else
|
||||||
c = duRGBA(0,0,0,48);
|
c = duRGBA(0,0,0,48);
|
||||||
}
|
}
|
||||||
|
|
@ -122,6 +120,8 @@ static void drawMeshTile(duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMesh
|
||||||
{
|
{
|
||||||
dtPolyRef base = mesh.getPolyRefBase(tile);
|
dtPolyRef base = mesh.getPolyRefBase(tile);
|
||||||
|
|
||||||
|
int tileNum = mesh.decodePolyIdTile(base);
|
||||||
|
|
||||||
dd->depthMask(false);
|
dd->depthMask(false);
|
||||||
|
|
||||||
dd->begin(DU_DRAW_TRIS);
|
dd->begin(DU_DRAW_TRIS);
|
||||||
|
|
@ -137,27 +137,17 @@ static void drawMeshTile(duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMesh
|
||||||
if (query && query->isInClosedList(base | (dtPolyRef)i))
|
if (query && query->isInClosedList(base | (dtPolyRef)i))
|
||||||
col = duRGBA(255,196,0,64);
|
col = duRGBA(255,196,0,64);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (flags & DU_DRAWNAVMESH_COLOR_TILES)
|
||||||
|
{
|
||||||
|
col = duIntToCol(tileNum, 128);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (p->getArea() == 0) // Treat zero area type as default.
|
if (p->getArea() == 0) // Treat zero area type as default.
|
||||||
col = duRGBA(0,192,255,64);
|
col = duRGBA(0,192,255,64);
|
||||||
else
|
else
|
||||||
switch(p->getArea())
|
col = duIntToCol(p->getArea(), 64);
|
||||||
{
|
|
||||||
case NAV_GROUND:
|
|
||||||
col = duRGBA(160,128,40,64);
|
|
||||||
break;
|
|
||||||
case NAV_MAGMA:
|
|
||||||
col = duRGBA(240,95,50,64);
|
|
||||||
break;
|
|
||||||
case NAV_SLIME:
|
|
||||||
col = duRGBA(85,225,85,64);
|
|
||||||
break;
|
|
||||||
case NAV_WATER:
|
|
||||||
col = duRGBA(160,160,245,64);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
col = duRGBA(0,192,255,64);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,7 +180,7 @@ static void drawMeshTile(duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMesh
|
||||||
if (p->getType() != DT_POLYTYPE_OFFMESH_CONNECTION) // Skip regular polys.
|
if (p->getType() != DT_POLYTYPE_OFFMESH_CONNECTION) // Skip regular polys.
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
unsigned int col;
|
unsigned int col, col2;
|
||||||
if (query && query->isInClosedList(base | (dtPolyRef)i))
|
if (query && query->isInClosedList(base | (dtPolyRef)i))
|
||||||
col = duRGBA(255,196,0,220);
|
col = duRGBA(255,196,0,220);
|
||||||
else
|
else
|
||||||
|
|
@ -212,18 +202,15 @@ static void drawMeshTile(duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMesh
|
||||||
}
|
}
|
||||||
|
|
||||||
// End points and their on-mesh locations.
|
// End points and their on-mesh locations.
|
||||||
if (startSet)
|
|
||||||
{
|
|
||||||
dd->vertex(va[0],va[1],va[2], col);
|
dd->vertex(va[0],va[1],va[2], col);
|
||||||
dd->vertex(con->pos[0],con->pos[1],con->pos[2], col);
|
dd->vertex(con->pos[0],con->pos[1],con->pos[2], col);
|
||||||
duAppendCircle(dd, con->pos[0],con->pos[1]+0.1f,con->pos[2], con->rad, duRGBA(0,48,64,196));
|
col2 = startSet ? col : duRGBA(220,32,16,196);
|
||||||
}
|
duAppendCircle(dd, con->pos[0],con->pos[1]+0.1f,con->pos[2], con->rad, col2);
|
||||||
if (endSet)
|
|
||||||
{
|
|
||||||
dd->vertex(vb[0],vb[1],vb[2], col);
|
dd->vertex(vb[0],vb[1],vb[2], col);
|
||||||
dd->vertex(con->pos[3],con->pos[4],con->pos[5], col);
|
dd->vertex(con->pos[3],con->pos[4],con->pos[5], col);
|
||||||
duAppendCircle(dd, con->pos[3],con->pos[4]+0.1f,con->pos[5], con->rad, duRGBA(0,48,64,196));
|
col2 = endSet ? col : duRGBA(220,32,16,196);
|
||||||
}
|
duAppendCircle(dd, con->pos[3],con->pos[4]+0.1f,con->pos[5], con->rad, col2);
|
||||||
|
|
||||||
// End point vertices.
|
// End point vertices.
|
||||||
dd->vertex(con->pos[0],con->pos[1],con->pos[2], duRGBA(0,48,64,196));
|
dd->vertex(con->pos[0],con->pos[1],con->pos[2], duRGBA(0,48,64,196));
|
||||||
|
|
@ -288,7 +275,7 @@ void duDebugDrawNavMeshNodes(struct duDebugDraw* dd, const dtNavMeshQuery& query
|
||||||
dd->begin(DU_DRAW_POINTS, 4.0f);
|
dd->begin(DU_DRAW_POINTS, 4.0f);
|
||||||
for (int i = 0; i < pool->getHashSize(); ++i)
|
for (int i = 0; i < pool->getHashSize(); ++i)
|
||||||
{
|
{
|
||||||
for (unsigned short j = pool->getFirst(i); j != DT_NULL_IDX; j = pool->getNext(j))
|
for (dtNodeIndex j = pool->getFirst(i); j != DT_NULL_IDX; j = pool->getNext(j))
|
||||||
{
|
{
|
||||||
const dtNode* node = pool->getNodeAtIdx(j+1);
|
const dtNode* node = pool->getNodeAtIdx(j+1);
|
||||||
if (!node) continue;
|
if (!node) continue;
|
||||||
|
|
@ -300,7 +287,7 @@ void duDebugDrawNavMeshNodes(struct duDebugDraw* dd, const dtNavMeshQuery& query
|
||||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||||
for (int i = 0; i < pool->getHashSize(); ++i)
|
for (int i = 0; i < pool->getHashSize(); ++i)
|
||||||
{
|
{
|
||||||
for (unsigned short j = pool->getFirst(i); j != DT_NULL_IDX; j = pool->getNext(j))
|
for (dtNodeIndex j = pool->getFirst(i); j != DT_NULL_IDX; j = pool->getNext(j))
|
||||||
{
|
{
|
||||||
const dtNode* node = pool->getNodeAtIdx(j+1);
|
const dtNode* node = pool->getNodeAtIdx(j+1);
|
||||||
if (!node) continue;
|
if (!node) continue;
|
||||||
|
|
@ -352,7 +339,7 @@ void duDebugDrawNavMeshBVTree(duDebugDraw* dd, const dtNavMesh& mesh)
|
||||||
static void drawMeshTilePortal(duDebugDraw* dd, const dtMeshTile* tile)
|
static void drawMeshTilePortal(duDebugDraw* dd, const dtMeshTile* tile)
|
||||||
{
|
{
|
||||||
// Draw portals
|
// Draw portals
|
||||||
const float padx = 0.02f;
|
const float padx = 0.04f;
|
||||||
const float pady = tile->header->walkableClimb;
|
const float pady = tile->header->walkableClimb;
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||||
|
|
@ -433,13 +420,33 @@ void duDebugDrawNavMeshPortals(duDebugDraw* dd, const dtNavMesh& mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void duDebugDrawNavMeshPolysWithFlags(struct duDebugDraw* dd, const dtNavMesh& mesh,
|
||||||
|
const unsigned short polyFlags, const unsigned int col)
|
||||||
|
{
|
||||||
|
if (!dd) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
||||||
|
{
|
||||||
|
const dtMeshTile* tile = mesh.getTile(i);
|
||||||
|
if (!tile->header) continue;
|
||||||
|
dtPolyRef base = mesh.getPolyRefBase(tile);
|
||||||
|
|
||||||
|
for (int j = 0; j < tile->header->polyCount; ++j)
|
||||||
|
{
|
||||||
|
const dtPoly* p = &tile->polys[j];
|
||||||
|
if ((p->flags & polyFlags) == 0) continue;
|
||||||
|
duDebugDrawNavMeshPoly(dd, mesh, base|(dtPolyRef)j, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void duDebugDrawNavMeshPoly(duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef ref, const unsigned int col)
|
void duDebugDrawNavMeshPoly(duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef ref, const unsigned int col)
|
||||||
{
|
{
|
||||||
if (!dd) return;
|
if (!dd) return;
|
||||||
|
|
||||||
const dtMeshTile* tile = 0;
|
const dtMeshTile* tile = 0;
|
||||||
const dtPoly* poly = 0;
|
const dtPoly* poly = 0;
|
||||||
if (mesh.getTileAndPolyByRef(ref, &tile, &poly) != DT_SUCCESS)
|
if (dtStatusFailed(mesh.getTileAndPolyByRef(ref, &tile, &poly)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dd->depthMask(false);
|
dd->depthMask(false);
|
||||||
|
|
@ -482,3 +489,379 @@ void duDebugDrawNavMeshPoly(duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef re
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void debugDrawTileCachePortals(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
|
||||||
|
{
|
||||||
|
const int w = (int)layer.header->width;
|
||||||
|
const int h = (int)layer.header->height;
|
||||||
|
const float* bmin = layer.header->bmin;
|
||||||
|
|
||||||
|
// Portals
|
||||||
|
unsigned int pcol = duRGBA(255,255,255,255);
|
||||||
|
|
||||||
|
const int segs[4*4] = {0,0,0,1, 0,1,1,1, 1,1,1,0, 1,0,0,0};
|
||||||
|
|
||||||
|
// Layer portals
|
||||||
|
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||||
|
for (int y = 0; y < h; ++y)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < w; ++x)
|
||||||
|
{
|
||||||
|
const int idx = x+y*w;
|
||||||
|
const int lh = (int)layer.heights[idx];
|
||||||
|
if (lh == 0xff) continue;
|
||||||
|
|
||||||
|
for (int dir = 0; dir < 4; ++dir)
|
||||||
|
{
|
||||||
|
if (layer.cons[idx] & (1<<(dir+4)))
|
||||||
|
{
|
||||||
|
const int* seg = &segs[dir*4];
|
||||||
|
const float ax = bmin[0] + (x+seg[0])*cs;
|
||||||
|
const float ay = bmin[1] + (lh+2)*ch;
|
||||||
|
const float az = bmin[2] + (y+seg[1])*cs;
|
||||||
|
const float bx = bmin[0] + (x+seg[2])*cs;
|
||||||
|
const float by = bmin[1] + (lh+2)*ch;
|
||||||
|
const float bz = bmin[2] + (y+seg[3])*cs;
|
||||||
|
dd->vertex(ax, ay, az, pcol);
|
||||||
|
dd->vertex(bx, by, bz, pcol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void duDebugDrawTileCacheLayerAreas(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
|
||||||
|
{
|
||||||
|
const int w = (int)layer.header->width;
|
||||||
|
const int h = (int)layer.header->height;
|
||||||
|
const float* bmin = layer.header->bmin;
|
||||||
|
const float* bmax = layer.header->bmax;
|
||||||
|
const int idx = layer.header->tlayer;
|
||||||
|
|
||||||
|
unsigned int color = duIntToCol(idx+1, 255);
|
||||||
|
|
||||||
|
// Layer bounds
|
||||||
|
float lbmin[3], lbmax[3];
|
||||||
|
lbmin[0] = bmin[0] + layer.header->minx*cs;
|
||||||
|
lbmin[1] = bmin[1];
|
||||||
|
lbmin[2] = bmin[2] + layer.header->miny*cs;
|
||||||
|
lbmax[0] = bmin[0] + (layer.header->maxx+1)*cs;
|
||||||
|
lbmax[1] = bmax[1];
|
||||||
|
lbmax[2] = bmin[2] + (layer.header->maxy+1)*cs;
|
||||||
|
duDebugDrawBoxWire(dd, lbmin[0],lbmin[1],lbmin[2], lbmax[0],lbmax[1],lbmax[2], duTransCol(color,128), 2.0f);
|
||||||
|
|
||||||
|
// Layer height
|
||||||
|
dd->begin(DU_DRAW_QUADS);
|
||||||
|
for (int y = 0; y < h; ++y)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < w; ++x)
|
||||||
|
{
|
||||||
|
const int lidx = x+y*w;
|
||||||
|
const int lh = (int)layer.heights[lidx];
|
||||||
|
if (lh == 0xff) continue;
|
||||||
|
const unsigned char area = layer.areas[lidx];
|
||||||
|
|
||||||
|
unsigned int col;
|
||||||
|
if (area == 63)
|
||||||
|
col = duLerpCol(color, duRGBA(0,192,255,64), 32);
|
||||||
|
else if (area == 0)
|
||||||
|
col = duLerpCol(color, duRGBA(0,0,0,64), 32);
|
||||||
|
else
|
||||||
|
col = duLerpCol(color, duIntToCol(area, 255), 32);
|
||||||
|
|
||||||
|
const float fx = bmin[0] + x*cs;
|
||||||
|
const float fy = bmin[1] + (lh+1)*ch;
|
||||||
|
const float fz = bmin[2] + y*cs;
|
||||||
|
|
||||||
|
dd->vertex(fx, fy, fz, col);
|
||||||
|
dd->vertex(fx, fy, fz+cs, col);
|
||||||
|
dd->vertex(fx+cs, fy, fz+cs, col);
|
||||||
|
dd->vertex(fx+cs, fy, fz, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
|
||||||
|
debugDrawTileCachePortals(dd, layer, cs, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void duDebugDrawTileCacheLayerRegions(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
|
||||||
|
{
|
||||||
|
const int w = (int)layer.header->width;
|
||||||
|
const int h = (int)layer.header->height;
|
||||||
|
const float* bmin = layer.header->bmin;
|
||||||
|
const float* bmax = layer.header->bmax;
|
||||||
|
const int idx = layer.header->tlayer;
|
||||||
|
|
||||||
|
unsigned int color = duIntToCol(idx+1, 255);
|
||||||
|
|
||||||
|
// Layer bounds
|
||||||
|
float lbmin[3], lbmax[3];
|
||||||
|
lbmin[0] = bmin[0] + layer.header->minx*cs;
|
||||||
|
lbmin[1] = bmin[1];
|
||||||
|
lbmin[2] = bmin[2] + layer.header->miny*cs;
|
||||||
|
lbmax[0] = bmin[0] + (layer.header->maxx+1)*cs;
|
||||||
|
lbmax[1] = bmax[1];
|
||||||
|
lbmax[2] = bmin[2] + (layer.header->maxy+1)*cs;
|
||||||
|
duDebugDrawBoxWire(dd, lbmin[0],lbmin[1],lbmin[2], lbmax[0],lbmax[1],lbmax[2], duTransCol(color,128), 2.0f);
|
||||||
|
|
||||||
|
// Layer height
|
||||||
|
dd->begin(DU_DRAW_QUADS);
|
||||||
|
for (int y = 0; y < h; ++y)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < w; ++x)
|
||||||
|
{
|
||||||
|
const int lidx = x+y*w;
|
||||||
|
const int lh = (int)layer.heights[lidx];
|
||||||
|
if (lh == 0xff) continue;
|
||||||
|
const unsigned char reg = layer.regs[lidx];
|
||||||
|
|
||||||
|
unsigned int col = duLerpCol(color, duIntToCol(reg, 255), 192);
|
||||||
|
|
||||||
|
const float fx = bmin[0] + x*cs;
|
||||||
|
const float fy = bmin[1] + (lh+1)*ch;
|
||||||
|
const float fz = bmin[2] + y*cs;
|
||||||
|
|
||||||
|
dd->vertex(fx, fy, fz, col);
|
||||||
|
dd->vertex(fx, fy, fz+cs, col);
|
||||||
|
dd->vertex(fx+cs, fy, fz+cs, col);
|
||||||
|
dd->vertex(fx+cs, fy, fz, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
|
||||||
|
debugDrawTileCachePortals(dd, layer, cs, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*struct dtTileCacheContour
|
||||||
|
{
|
||||||
|
int nverts;
|
||||||
|
unsigned char* verts;
|
||||||
|
unsigned char reg;
|
||||||
|
unsigned char area;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtTileCacheContourSet
|
||||||
|
{
|
||||||
|
int nconts;
|
||||||
|
dtTileCacheContour* conts;
|
||||||
|
};*/
|
||||||
|
|
||||||
|
void duDebugDrawTileCacheContours(duDebugDraw* dd, const struct dtTileCacheContourSet& lcset,
|
||||||
|
const float* orig, const float cs, const float ch)
|
||||||
|
{
|
||||||
|
if (!dd) return;
|
||||||
|
|
||||||
|
const unsigned char a = 255;// (unsigned char)(alpha*255.0f);
|
||||||
|
|
||||||
|
const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
|
||||||
|
|
||||||
|
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||||
|
|
||||||
|
for (int i = 0; i < lcset.nconts; ++i)
|
||||||
|
{
|
||||||
|
const dtTileCacheContour& c = lcset.conts[i];
|
||||||
|
unsigned int color = 0;
|
||||||
|
|
||||||
|
color = duIntToCol(i, a);
|
||||||
|
|
||||||
|
for (int j = 0; j < c.nverts; ++j)
|
||||||
|
{
|
||||||
|
const int k = (j+1) % c.nverts;
|
||||||
|
const unsigned char* va = &c.verts[j*4];
|
||||||
|
const unsigned char* vb = &c.verts[k*4];
|
||||||
|
const float ax = orig[0] + va[0]*cs;
|
||||||
|
const float ay = orig[1] + (va[1]+1+(i&1))*ch;
|
||||||
|
const float az = orig[2] + va[2]*cs;
|
||||||
|
const float bx = orig[0] + vb[0]*cs;
|
||||||
|
const float by = orig[1] + (vb[1]+1+(i&1))*ch;
|
||||||
|
const float bz = orig[2] + vb[2]*cs;
|
||||||
|
unsigned int col = color;
|
||||||
|
if ((va[3] & 0xf) != 0xf)
|
||||||
|
{
|
||||||
|
// Portal segment
|
||||||
|
col = duRGBA(255,255,255,128);
|
||||||
|
int d = va[3] & 0xf;
|
||||||
|
|
||||||
|
const float cx = (ax+bx)*0.5f;
|
||||||
|
const float cy = (ay+by)*0.5f;
|
||||||
|
const float cz = (az+bz)*0.5f;
|
||||||
|
|
||||||
|
const float dx = cx + offs[d*2+0]*2*cs;
|
||||||
|
const float dy = cy;
|
||||||
|
const float dz = cz + offs[d*2+1]*2*cs;
|
||||||
|
|
||||||
|
dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
|
||||||
|
dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
|
||||||
|
}
|
||||||
|
|
||||||
|
duAppendArrow(dd, ax,ay,az, bx,by,bz, 0.0f, cs*0.5f, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
|
||||||
|
dd->begin(DU_DRAW_POINTS, 4.0f);
|
||||||
|
|
||||||
|
for (int i = 0; i < lcset.nconts; ++i)
|
||||||
|
{
|
||||||
|
const dtTileCacheContour& c = lcset.conts[i];
|
||||||
|
unsigned int color = 0;
|
||||||
|
|
||||||
|
for (int j = 0; j < c.nverts; ++j)
|
||||||
|
{
|
||||||
|
const unsigned char* va = &c.verts[j*4];
|
||||||
|
|
||||||
|
color = duDarkenCol(duIntToCol(i, a));
|
||||||
|
if (va[3] & 0x80)
|
||||||
|
{
|
||||||
|
// Border vertex
|
||||||
|
color = duRGBA(255,0,0,255);
|
||||||
|
}
|
||||||
|
|
||||||
|
float fx = orig[0] + va[0]*cs;
|
||||||
|
float fy = orig[1] + (va[1]+1+(i&1))*ch;
|
||||||
|
float fz = orig[2] + va[2]*cs;
|
||||||
|
dd->vertex(fx,fy,fz, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void duDebugDrawTileCachePolyMesh(duDebugDraw* dd, const struct dtTileCachePolyMesh& lmesh,
|
||||||
|
const float* orig, const float cs, const float ch)
|
||||||
|
{
|
||||||
|
if (!dd) return;
|
||||||
|
|
||||||
|
const int nvp = lmesh.nvp;
|
||||||
|
|
||||||
|
const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
|
||||||
|
|
||||||
|
dd->begin(DU_DRAW_TRIS);
|
||||||
|
|
||||||
|
for (int i = 0; i < lmesh.npolys; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
||||||
|
|
||||||
|
unsigned int color;
|
||||||
|
if (lmesh.areas[i] == DT_TILECACHE_WALKABLE_AREA)
|
||||||
|
color = duRGBA(0,192,255,64);
|
||||||
|
else if (lmesh.areas[i] == DT_TILECACHE_NULL_AREA)
|
||||||
|
color = duRGBA(0,0,0,64);
|
||||||
|
else
|
||||||
|
color = duIntToCol(lmesh.areas[i], 255);
|
||||||
|
|
||||||
|
unsigned short vi[3];
|
||||||
|
for (int j = 2; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == DT_TILECACHE_NULL_IDX) break;
|
||||||
|
vi[0] = p[0];
|
||||||
|
vi[1] = p[j-1];
|
||||||
|
vi[2] = p[j];
|
||||||
|
for (int k = 0; k < 3; ++k)
|
||||||
|
{
|
||||||
|
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
||||||
|
const float x = orig[0] + v[0]*cs;
|
||||||
|
const float y = orig[1] + (v[1]+1)*ch;
|
||||||
|
const float z = orig[2] + v[2]*cs;
|
||||||
|
dd->vertex(x,y,z, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
|
||||||
|
// Draw neighbours edges
|
||||||
|
const unsigned int coln = duRGBA(0,48,64,32);
|
||||||
|
dd->begin(DU_DRAW_LINES, 1.5f);
|
||||||
|
for (int i = 0; i < lmesh.npolys; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
||||||
|
for (int j = 0; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == DT_TILECACHE_NULL_IDX) break;
|
||||||
|
if (p[nvp+j] & 0x8000) continue;
|
||||||
|
const int nj = (j+1 >= nvp || p[j+1] == DT_TILECACHE_NULL_IDX) ? 0 : j+1;
|
||||||
|
int vi[2] = {p[j], p[nj]};
|
||||||
|
|
||||||
|
for (int k = 0; k < 2; ++k)
|
||||||
|
{
|
||||||
|
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
||||||
|
const float x = orig[0] + v[0]*cs;
|
||||||
|
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||||
|
const float z = orig[2] + v[2]*cs;
|
||||||
|
dd->vertex(x, y, z, coln);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
|
||||||
|
// Draw boundary edges
|
||||||
|
const unsigned int colb = duRGBA(0,48,64,220);
|
||||||
|
dd->begin(DU_DRAW_LINES, 2.5f);
|
||||||
|
for (int i = 0; i < lmesh.npolys; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
||||||
|
for (int j = 0; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == DT_TILECACHE_NULL_IDX) break;
|
||||||
|
if ((p[nvp+j] & 0x8000) == 0) continue;
|
||||||
|
const int nj = (j+1 >= nvp || p[j+1] == DT_TILECACHE_NULL_IDX) ? 0 : j+1;
|
||||||
|
int vi[2] = {p[j], p[nj]};
|
||||||
|
|
||||||
|
unsigned int col = colb;
|
||||||
|
if ((p[nvp+j] & 0xf) != 0xf)
|
||||||
|
{
|
||||||
|
const unsigned short* va = &lmesh.verts[vi[0]*3];
|
||||||
|
const unsigned short* vb = &lmesh.verts[vi[1]*3];
|
||||||
|
|
||||||
|
const float ax = orig[0] + va[0]*cs;
|
||||||
|
const float ay = orig[1] + (va[1]+1+(i&1))*ch;
|
||||||
|
const float az = orig[2] + va[2]*cs;
|
||||||
|
const float bx = orig[0] + vb[0]*cs;
|
||||||
|
const float by = orig[1] + (vb[1]+1+(i&1))*ch;
|
||||||
|
const float bz = orig[2] + vb[2]*cs;
|
||||||
|
|
||||||
|
const float cx = (ax+bx)*0.5f;
|
||||||
|
const float cy = (ay+by)*0.5f;
|
||||||
|
const float cz = (az+bz)*0.5f;
|
||||||
|
|
||||||
|
int d = p[nvp+j] & 0xf;
|
||||||
|
|
||||||
|
const float dx = cx + offs[d*2+0]*2*cs;
|
||||||
|
const float dy = cy;
|
||||||
|
const float dz = cz + offs[d*2+1]*2*cs;
|
||||||
|
|
||||||
|
dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
|
||||||
|
dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
|
||||||
|
|
||||||
|
col = duRGBA(255,255,255,128);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int k = 0; k < 2; ++k)
|
||||||
|
{
|
||||||
|
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
||||||
|
const float x = orig[0] + v[0]*cs;
|
||||||
|
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||||
|
const float z = orig[2] + v[2]*cs;
|
||||||
|
dd->vertex(x, y, z, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
|
||||||
|
dd->begin(DU_DRAW_POINTS, 3.0f);
|
||||||
|
const unsigned int colv = duRGBA(0,0,0,220);
|
||||||
|
for (int i = 0; i < lmesh.nverts; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* v = &lmesh.verts[i*3];
|
||||||
|
const float x = orig[0] + v[0]*cs;
|
||||||
|
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||||
|
const float z = orig[2] + v[2]*cs;
|
||||||
|
dd->vertex(x,y,z, colv);
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,33 +24,62 @@
|
||||||
|
|
||||||
void duDebugDrawTriMesh(duDebugDraw* dd, const float* verts, int /*nverts*/,
|
void duDebugDrawTriMesh(duDebugDraw* dd, const float* verts, int /*nverts*/,
|
||||||
const int* tris, const float* normals, int ntris,
|
const int* tris, const float* normals, int ntris,
|
||||||
const unsigned char* flags)
|
const unsigned char* flags, const float texScale)
|
||||||
{
|
{
|
||||||
if (!dd) return;
|
if (!dd) return;
|
||||||
if (!verts) return;
|
if (!verts) return;
|
||||||
if (!tris) return;
|
if (!tris) return;
|
||||||
if (!normals) return;
|
if (!normals) return;
|
||||||
|
|
||||||
|
float uva[2];
|
||||||
|
float uvb[2];
|
||||||
|
float uvc[2];
|
||||||
|
|
||||||
|
const unsigned int unwalkable = duRGBA(192,128,0,255);
|
||||||
|
|
||||||
|
dd->texture(true);
|
||||||
|
|
||||||
dd->begin(DU_DRAW_TRIS);
|
dd->begin(DU_DRAW_TRIS);
|
||||||
for (int i = 0; i < ntris*3; i += 3)
|
for (int i = 0; i < ntris*3; i += 3)
|
||||||
{
|
{
|
||||||
|
const float* norm = &normals[i];
|
||||||
unsigned int color;
|
unsigned int color;
|
||||||
unsigned char a = (unsigned char)(150*(2+normals[i+0]+normals[i+1])/4);
|
unsigned char a = (unsigned char)(220*(2+norm[0]+norm[1])/4);
|
||||||
if (flags && !flags[i/3])
|
if (flags && !flags[i/3])
|
||||||
color = duRGBA(a,a/4,a/16,255);
|
color = duLerpCol(duRGBA(a,a,a,255), unwalkable, 64);
|
||||||
else
|
else
|
||||||
color = duRGBA(a,a,a,255);
|
color = duRGBA(a,a,a,255);
|
||||||
|
|
||||||
dd->vertex(&verts[tris[i+0]*3], color);
|
const float* va = &verts[tris[i+0]*3];
|
||||||
dd->vertex(&verts[tris[i+1]*3], color);
|
const float* vb = &verts[tris[i+1]*3];
|
||||||
dd->vertex(&verts[tris[i+2]*3], color);
|
const float* vc = &verts[tris[i+2]*3];
|
||||||
|
|
||||||
|
int ax = 0, ay = 0;
|
||||||
|
if (rcAbs(norm[1]) > rcAbs(norm[ax]))
|
||||||
|
ax = 1;
|
||||||
|
if (rcAbs(norm[2]) > rcAbs(norm[ax]))
|
||||||
|
ax = 2;
|
||||||
|
ax = (1<<ax)&3; // +1 mod 3
|
||||||
|
ay = (1<<ax)&3; // +1 mod 3
|
||||||
|
|
||||||
|
uva[0] = va[ax]*texScale;
|
||||||
|
uva[1] = va[ay]*texScale;
|
||||||
|
uvb[0] = vb[ax]*texScale;
|
||||||
|
uvb[1] = vb[ay]*texScale;
|
||||||
|
uvc[0] = vc[ax]*texScale;
|
||||||
|
uvc[1] = vc[ay]*texScale;
|
||||||
|
|
||||||
|
dd->vertex(va, color, uva);
|
||||||
|
dd->vertex(vb, color, uvb);
|
||||||
|
dd->vertex(vc, color, uvc);
|
||||||
}
|
}
|
||||||
dd->end();
|
dd->end();
|
||||||
|
dd->texture(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void duDebugDrawTriMeshSlope(duDebugDraw* dd, const float* verts, int /*nverts*/,
|
void duDebugDrawTriMeshSlope(duDebugDraw* dd, const float* verts, int /*nverts*/,
|
||||||
const int* tris, const float* normals, int ntris,
|
const int* tris, const float* normals, int ntris,
|
||||||
const float walkableSlopeAngle)
|
const float walkableSlopeAngle, const float texScale)
|
||||||
{
|
{
|
||||||
if (!dd) return;
|
if (!dd) return;
|
||||||
if (!verts) return;
|
if (!verts) return;
|
||||||
|
|
@ -59,22 +88,51 @@ void duDebugDrawTriMeshSlope(duDebugDraw* dd, const float* verts, int /*nverts*/
|
||||||
|
|
||||||
const float walkableThr = cosf(walkableSlopeAngle/180.0f*DU_PI);
|
const float walkableThr = cosf(walkableSlopeAngle/180.0f*DU_PI);
|
||||||
|
|
||||||
|
float uva[2];
|
||||||
|
float uvb[2];
|
||||||
|
float uvc[2];
|
||||||
|
|
||||||
|
dd->texture(true);
|
||||||
|
|
||||||
|
const unsigned int unwalkable = duRGBA(192,128,0,255);
|
||||||
|
|
||||||
dd->begin(DU_DRAW_TRIS);
|
dd->begin(DU_DRAW_TRIS);
|
||||||
for (int i = 0; i < ntris*3; i += 3)
|
for (int i = 0; i < ntris*3; i += 3)
|
||||||
{
|
{
|
||||||
const float* norm = &normals[i];
|
const float* norm = &normals[i];
|
||||||
unsigned int color;
|
unsigned int color;
|
||||||
unsigned char a = (unsigned char)(255*(2+normals[i+0]+normals[i+1])/4);
|
unsigned char a = (unsigned char)(220*(2+norm[0]+norm[1])/4);
|
||||||
if (norm[1] < walkableThr)
|
if (norm[1] < walkableThr)
|
||||||
color = duRGBA(a,a/4,a/16,255);
|
color = duLerpCol(duRGBA(a,a,a,255), unwalkable, 64);
|
||||||
else
|
else
|
||||||
color = duRGBA(a,a,a,255);
|
color = duRGBA(a,a,a,255);
|
||||||
|
|
||||||
dd->vertex(&verts[tris[i+0]*3], color);
|
const float* va = &verts[tris[i+0]*3];
|
||||||
dd->vertex(&verts[tris[i+1]*3], color);
|
const float* vb = &verts[tris[i+1]*3];
|
||||||
dd->vertex(&verts[tris[i+2]*3], color);
|
const float* vc = &verts[tris[i+2]*3];
|
||||||
|
|
||||||
|
int ax = 0, ay = 0;
|
||||||
|
if (rcAbs(norm[1]) > rcAbs(norm[ax]))
|
||||||
|
ax = 1;
|
||||||
|
if (rcAbs(norm[2]) > rcAbs(norm[ax]))
|
||||||
|
ax = 2;
|
||||||
|
ax = (1<<ax)&3; // +1 mod 3
|
||||||
|
ay = (1<<ax)&3; // +1 mod 3
|
||||||
|
|
||||||
|
uva[0] = va[ax]*texScale;
|
||||||
|
uva[1] = va[ay]*texScale;
|
||||||
|
uvb[0] = vb[ax]*texScale;
|
||||||
|
uvb[1] = vb[ay]*texScale;
|
||||||
|
uvc[0] = vc[ax]*texScale;
|
||||||
|
uvc[1] = vc[ay]*texScale;
|
||||||
|
|
||||||
|
dd->vertex(va, color, uva);
|
||||||
|
dd->vertex(vb, color, uvb);
|
||||||
|
dd->vertex(vc, color, uvc);
|
||||||
}
|
}
|
||||||
dd->end();
|
dd->end();
|
||||||
|
|
||||||
|
dd->texture(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void duDebugDrawHeightfieldSolid(duDebugDraw* dd, const rcHeightfield& hf)
|
void duDebugDrawHeightfieldSolid(duDebugDraw* dd, const rcHeightfield& hf)
|
||||||
|
|
@ -268,6 +326,325 @@ void duDebugDrawCompactHeightfieldDistance(duDebugDraw* dd, const rcCompactHeigh
|
||||||
dd->end();
|
dd->end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drawLayerPortals(duDebugDraw* dd, const rcHeightfieldLayer* layer)
|
||||||
|
{
|
||||||
|
const float cs = layer->cs;
|
||||||
|
const float ch = layer->ch;
|
||||||
|
const int w = layer->width;
|
||||||
|
const int h = layer->height;
|
||||||
|
|
||||||
|
unsigned int pcol = duRGBA(255,255,255,255);
|
||||||
|
|
||||||
|
const int segs[4*4] = {0,0,0,1, 0,1,1,1, 1,1,1,0, 1,0,0,0};
|
||||||
|
|
||||||
|
// Layer portals
|
||||||
|
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||||
|
for (int y = 0; y < h; ++y)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < w; ++x)
|
||||||
|
{
|
||||||
|
const int idx = x+y*w;
|
||||||
|
const int lh = (int)layer->heights[idx];
|
||||||
|
if (lh == 255) continue;
|
||||||
|
|
||||||
|
for (int dir = 0; dir < 4; ++dir)
|
||||||
|
{
|
||||||
|
if (layer->cons[idx] & (1<<(dir+4)))
|
||||||
|
{
|
||||||
|
const int* seg = &segs[dir*4];
|
||||||
|
const float ax = layer->bmin[0] + (x+seg[0])*cs;
|
||||||
|
const float ay = layer->bmin[1] + (lh+2)*ch;
|
||||||
|
const float az = layer->bmin[2] + (y+seg[1])*cs;
|
||||||
|
const float bx = layer->bmin[0] + (x+seg[2])*cs;
|
||||||
|
const float by = layer->bmin[1] + (lh+2)*ch;
|
||||||
|
const float bz = layer->bmin[2] + (y+seg[3])*cs;
|
||||||
|
dd->vertex(ax, ay, az, pcol);
|
||||||
|
dd->vertex(bx, by, bz, pcol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void duDebugDrawHeightfieldLayer(duDebugDraw* dd, const struct rcHeightfieldLayer& layer, const int idx)
|
||||||
|
{
|
||||||
|
const float cs = layer.cs;
|
||||||
|
const float ch = layer.ch;
|
||||||
|
const int w = layer.width;
|
||||||
|
const int h = layer.height;
|
||||||
|
|
||||||
|
unsigned int color = duIntToCol(idx+1, 255);
|
||||||
|
|
||||||
|
// Layer bounds
|
||||||
|
float bmin[3], bmax[3];
|
||||||
|
bmin[0] = layer.bmin[0] + layer.minx*cs;
|
||||||
|
bmin[1] = layer.bmin[1];
|
||||||
|
bmin[2] = layer.bmin[2] + layer.miny*cs;
|
||||||
|
bmax[0] = layer.bmin[0] + (layer.maxx+1)*cs;
|
||||||
|
bmax[1] = layer.bmax[1];
|
||||||
|
bmax[2] = layer.bmin[2] + (layer.maxy+1)*cs;
|
||||||
|
duDebugDrawBoxWire(dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duTransCol(color,128), 2.0f);
|
||||||
|
|
||||||
|
// Layer height
|
||||||
|
dd->begin(DU_DRAW_QUADS);
|
||||||
|
for (int y = 0; y < h; ++y)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < w; ++x)
|
||||||
|
{
|
||||||
|
const int lidx = x+y*w;
|
||||||
|
const int lh = (int)layer.heights[lidx];
|
||||||
|
if (h == 0xff) continue;
|
||||||
|
const unsigned char area = layer.areas[lidx];
|
||||||
|
|
||||||
|
unsigned int col;
|
||||||
|
if (area == RC_WALKABLE_AREA)
|
||||||
|
col = duLerpCol(color, duRGBA(0,192,255,64), 32);
|
||||||
|
else if (area == RC_NULL_AREA)
|
||||||
|
col = duLerpCol(color, duRGBA(0,0,0,64), 32);
|
||||||
|
else
|
||||||
|
col = duLerpCol(color, duIntToCol(area, 255), 32);
|
||||||
|
|
||||||
|
const float fx = layer.bmin[0] + x*cs;
|
||||||
|
const float fy = layer.bmin[1] + (lh+1)*ch;
|
||||||
|
const float fz = layer.bmin[2] + y*cs;
|
||||||
|
|
||||||
|
dd->vertex(fx, fy, fz, col);
|
||||||
|
dd->vertex(fx, fy, fz+cs, col);
|
||||||
|
dd->vertex(fx+cs, fy, fz+cs, col);
|
||||||
|
dd->vertex(fx+cs, fy, fz, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
|
||||||
|
// Portals
|
||||||
|
drawLayerPortals(dd, &layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void duDebugDrawHeightfieldLayers(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset)
|
||||||
|
{
|
||||||
|
if (!dd) return;
|
||||||
|
for (int i = 0; i < lset.nlayers; ++i)
|
||||||
|
duDebugDrawHeightfieldLayer(dd, lset.layers[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void duDebugDrawLayerContours(duDebugDraw* dd, const struct rcLayerContourSet& lcset)
|
||||||
|
{
|
||||||
|
if (!dd) return;
|
||||||
|
|
||||||
|
const float* orig = lcset.bmin;
|
||||||
|
const float cs = lcset.cs;
|
||||||
|
const float ch = lcset.ch;
|
||||||
|
|
||||||
|
const unsigned char a = 255;// (unsigned char)(alpha*255.0f);
|
||||||
|
|
||||||
|
const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
|
||||||
|
|
||||||
|
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||||
|
|
||||||
|
for (int i = 0; i < lcset.nconts; ++i)
|
||||||
|
{
|
||||||
|
const rcLayerContour& c = lcset.conts[i];
|
||||||
|
unsigned int color = 0;
|
||||||
|
|
||||||
|
color = duIntToCol(i, a);
|
||||||
|
|
||||||
|
for (int j = 0; j < c.nverts; ++j)
|
||||||
|
{
|
||||||
|
const int k = (j+1) % c.nverts;
|
||||||
|
const unsigned char* va = &c.verts[j*4];
|
||||||
|
const unsigned char* vb = &c.verts[k*4];
|
||||||
|
const float ax = orig[0] + va[0]*cs;
|
||||||
|
const float ay = orig[1] + (va[1]+1+(i&1))*ch;
|
||||||
|
const float az = orig[2] + va[2]*cs;
|
||||||
|
const float bx = orig[0] + vb[0]*cs;
|
||||||
|
const float by = orig[1] + (vb[1]+1+(i&1))*ch;
|
||||||
|
const float bz = orig[2] + vb[2]*cs;
|
||||||
|
unsigned int col = color;
|
||||||
|
if ((va[3] & 0xf) != 0xf)
|
||||||
|
{
|
||||||
|
col = duRGBA(255,255,255,128);
|
||||||
|
int d = va[3] & 0xf;
|
||||||
|
|
||||||
|
const float cx = (ax+bx)*0.5f;
|
||||||
|
const float cy = (ay+by)*0.5f;
|
||||||
|
const float cz = (az+bz)*0.5f;
|
||||||
|
|
||||||
|
const float dx = cx + offs[d*2+0]*2*cs;
|
||||||
|
const float dy = cy;
|
||||||
|
const float dz = cz + offs[d*2+1]*2*cs;
|
||||||
|
|
||||||
|
dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
|
||||||
|
dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
|
||||||
|
}
|
||||||
|
|
||||||
|
duAppendArrow(dd, ax,ay,az, bx,by,bz, 0.0f, cs*0.5f, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
|
||||||
|
dd->begin(DU_DRAW_POINTS, 4.0f);
|
||||||
|
|
||||||
|
for (int i = 0; i < lcset.nconts; ++i)
|
||||||
|
{
|
||||||
|
const rcLayerContour& c = lcset.conts[i];
|
||||||
|
unsigned int color = 0;
|
||||||
|
|
||||||
|
for (int j = 0; j < c.nverts; ++j)
|
||||||
|
{
|
||||||
|
const unsigned char* va = &c.verts[j*4];
|
||||||
|
|
||||||
|
color = duDarkenCol(duIntToCol(i, a));
|
||||||
|
if (va[3] & 0x80)
|
||||||
|
color = duRGBA(255,0,0,255);
|
||||||
|
|
||||||
|
float fx = orig[0] + va[0]*cs;
|
||||||
|
float fy = orig[1] + (va[1]+1+(i&1))*ch;
|
||||||
|
float fz = orig[2] + va[2]*cs;
|
||||||
|
dd->vertex(fx,fy,fz, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void duDebugDrawLayerPolyMesh(duDebugDraw* dd, const struct rcLayerPolyMesh& lmesh)
|
||||||
|
{
|
||||||
|
if (!dd) return;
|
||||||
|
|
||||||
|
const int nvp = lmesh.nvp;
|
||||||
|
const float cs = lmesh.cs;
|
||||||
|
const float ch = lmesh.ch;
|
||||||
|
const float* orig = lmesh.bmin;
|
||||||
|
|
||||||
|
const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
|
||||||
|
|
||||||
|
dd->begin(DU_DRAW_TRIS);
|
||||||
|
|
||||||
|
for (int i = 0; i < lmesh.npolys; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
||||||
|
|
||||||
|
unsigned int color;
|
||||||
|
if (lmesh.areas[i] == RC_WALKABLE_AREA)
|
||||||
|
color = duRGBA(0,192,255,64);
|
||||||
|
else if (lmesh.areas[i] == RC_NULL_AREA)
|
||||||
|
color = duRGBA(0,0,0,64);
|
||||||
|
else
|
||||||
|
color = duIntToCol(lmesh.areas[i], 255);
|
||||||
|
|
||||||
|
unsigned short vi[3];
|
||||||
|
for (int j = 2; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == RC_MESH_NULL_IDX) break;
|
||||||
|
vi[0] = p[0];
|
||||||
|
vi[1] = p[j-1];
|
||||||
|
vi[2] = p[j];
|
||||||
|
for (int k = 0; k < 3; ++k)
|
||||||
|
{
|
||||||
|
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
||||||
|
const float x = orig[0] + v[0]*cs;
|
||||||
|
const float y = orig[1] + (v[1]+1)*ch;
|
||||||
|
const float z = orig[2] + v[2]*cs;
|
||||||
|
dd->vertex(x,y,z, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
|
||||||
|
// Draw neighbours edges
|
||||||
|
const unsigned int coln = duRGBA(0,48,64,32);
|
||||||
|
dd->begin(DU_DRAW_LINES, 1.5f);
|
||||||
|
for (int i = 0; i < lmesh.npolys; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
||||||
|
for (int j = 0; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == RC_MESH_NULL_IDX) break;
|
||||||
|
if (p[nvp+j] & 0x8000) continue;
|
||||||
|
const int nj = (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX) ? 0 : j+1;
|
||||||
|
int vi[2] = {p[j], p[nj]};
|
||||||
|
|
||||||
|
for (int k = 0; k < 2; ++k)
|
||||||
|
{
|
||||||
|
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
||||||
|
const float x = orig[0] + v[0]*cs;
|
||||||
|
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||||
|
const float z = orig[2] + v[2]*cs;
|
||||||
|
dd->vertex(x, y, z, coln);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
|
||||||
|
// Draw boundary edges
|
||||||
|
const unsigned int colb = duRGBA(0,48,64,220);
|
||||||
|
dd->begin(DU_DRAW_LINES, 2.5f);
|
||||||
|
for (int i = 0; i < lmesh.npolys; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
||||||
|
for (int j = 0; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == RC_MESH_NULL_IDX) break;
|
||||||
|
if ((p[nvp+j] & 0x8000) == 0) continue;
|
||||||
|
const int nj = (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX) ? 0 : j+1;
|
||||||
|
int vi[2] = {p[j], p[nj]};
|
||||||
|
|
||||||
|
unsigned int col = colb;
|
||||||
|
if ((p[nvp+j] & 0xf) != 0xf)
|
||||||
|
{
|
||||||
|
const unsigned short* va = &lmesh.verts[vi[0]*3];
|
||||||
|
const unsigned short* vb = &lmesh.verts[vi[1]*3];
|
||||||
|
|
||||||
|
const float ax = orig[0] + va[0]*cs;
|
||||||
|
const float ay = orig[1] + (va[1]+1+(i&1))*ch;
|
||||||
|
const float az = orig[2] + va[2]*cs;
|
||||||
|
const float bx = orig[0] + vb[0]*cs;
|
||||||
|
const float by = orig[1] + (vb[1]+1+(i&1))*ch;
|
||||||
|
const float bz = orig[2] + vb[2]*cs;
|
||||||
|
|
||||||
|
const float cx = (ax+bx)*0.5f;
|
||||||
|
const float cy = (ay+by)*0.5f;
|
||||||
|
const float cz = (az+bz)*0.5f;
|
||||||
|
|
||||||
|
int d = p[nvp+j] & 0xf;
|
||||||
|
|
||||||
|
const float dx = cx + offs[d*2+0]*2*cs;
|
||||||
|
const float dy = cy;
|
||||||
|
const float dz = cz + offs[d*2+1]*2*cs;
|
||||||
|
|
||||||
|
dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
|
||||||
|
dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
|
||||||
|
|
||||||
|
col = duRGBA(255,255,255,128);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int k = 0; k < 2; ++k)
|
||||||
|
{
|
||||||
|
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
||||||
|
const float x = orig[0] + v[0]*cs;
|
||||||
|
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||||
|
const float z = orig[2] + v[2]*cs;
|
||||||
|
dd->vertex(x, y, z, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
|
||||||
|
dd->begin(DU_DRAW_POINTS, 3.0f);
|
||||||
|
const unsigned int colv = duRGBA(0,0,0,220);
|
||||||
|
for (int i = 0; i < lmesh.nverts; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* v = &lmesh.verts[i*3];
|
||||||
|
const float x = orig[0] + v[0]*cs;
|
||||||
|
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||||
|
const float z = orig[2] + v[2]*cs;
|
||||||
|
dd->vertex(x,y,z, colv);
|
||||||
|
}
|
||||||
|
dd->end();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
static void getContourCenter(const rcContour* cont, const float* orig, float cs, float ch, float* center)
|
static void getContourCenter(const rcContour* cont, const float* orig, float cs, float ch, float* center)
|
||||||
{
|
{
|
||||||
center[0] = 0;
|
center[0] = 0;
|
||||||
|
|
@ -342,9 +719,9 @@ void duDebugDrawRegionConnections(duDebugDraw* dd, const rcContourSet& cset, con
|
||||||
for (int i = 0; i < cset.nconts; ++i)
|
for (int i = 0; i < cset.nconts; ++i)
|
||||||
{
|
{
|
||||||
const rcContour* cont = &cset.conts[i];
|
const rcContour* cont = &cset.conts[i];
|
||||||
unsigned int color = duDarkenCol(duIntToCol(cont->reg,a));
|
unsigned int col = duDarkenCol(duIntToCol(cont->reg,a));
|
||||||
getContourCenter(cont, orig, cs, ch, pos);
|
getContourCenter(cont, orig, cs, ch, pos);
|
||||||
dd->vertex(pos, color);
|
dd->vertex(pos, col);
|
||||||
}
|
}
|
||||||
dd->end();
|
dd->end();
|
||||||
}
|
}
|
||||||
|
|
@ -429,24 +806,23 @@ void duDebugDrawContours(duDebugDraw* dd, const rcContourSet& cset, const float
|
||||||
const rcContour& c = cset.conts[i];
|
const rcContour& c = cset.conts[i];
|
||||||
if (!c.nverts)
|
if (!c.nverts)
|
||||||
continue;
|
continue;
|
||||||
unsigned int color = duIntToCol(c.reg, a);
|
const unsigned int color = duIntToCol(c.reg, a);
|
||||||
|
const unsigned int bcolor = duLerpCol(color,duRGBA(255,255,255,a),128);
|
||||||
for (int j = 0; j < c.nverts; ++j)
|
for (int j = 0, k = c.nverts-1; j < c.nverts; k=j++)
|
||||||
{
|
{
|
||||||
const int* v = &c.verts[j*4];
|
const int* va = &c.verts[k*4];
|
||||||
float fx = orig[0] + v[0]*cs;
|
const int* vb = &c.verts[j*4];
|
||||||
float fy = orig[1] + (v[1]+1+(i&1))*ch;
|
unsigned int col = (va[3] & RC_AREA_BORDER) ? bcolor : color;
|
||||||
float fz = orig[2] + v[2]*cs;
|
float fx,fy,fz;
|
||||||
dd->vertex(fx,fy,fz, color);
|
fx = orig[0] + va[0]*cs;
|
||||||
if (j > 0)
|
fy = orig[1] + (va[1]+1+(i&1))*ch;
|
||||||
dd->vertex(fx,fy,fz, color);
|
fz = orig[2] + va[2]*cs;
|
||||||
|
dd->vertex(fx,fy,fz, col);
|
||||||
|
fx = orig[0] + vb[0]*cs;
|
||||||
|
fy = orig[1] + (vb[1]+1+(i&1))*ch;
|
||||||
|
fz = orig[2] + vb[2]*cs;
|
||||||
|
dd->vertex(fx,fy,fz, col);
|
||||||
}
|
}
|
||||||
// Loop last segment
|
|
||||||
const int* v = &c.verts[0];
|
|
||||||
float fx = orig[0] + v[0]*cs;
|
|
||||||
float fy = orig[1] + (v[1]+1+(i&1))*ch;
|
|
||||||
float fz = orig[2] + v[2]*cs;
|
|
||||||
dd->vertex(fx,fy,fz, color);
|
|
||||||
}
|
}
|
||||||
dd->end();
|
dd->end();
|
||||||
|
|
||||||
|
|
@ -527,13 +903,10 @@ void duDebugDrawPolyMesh(duDebugDraw* dd, const struct rcPolyMesh& mesh)
|
||||||
for (int j = 0; j < nvp; ++j)
|
for (int j = 0; j < nvp; ++j)
|
||||||
{
|
{
|
||||||
if (p[j] == RC_MESH_NULL_IDX) break;
|
if (p[j] == RC_MESH_NULL_IDX) break;
|
||||||
if (p[nvp+j] == RC_MESH_NULL_IDX) continue;
|
if (p[nvp+j] & 0x8000) continue;
|
||||||
int vi[2];
|
const int nj = (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX) ? 0 : j+1;
|
||||||
vi[0] = p[j];
|
const int vi[2] = {p[j], p[nj]};
|
||||||
if (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX)
|
|
||||||
vi[1] = p[0];
|
|
||||||
else
|
|
||||||
vi[1] = p[j+1];
|
|
||||||
for (int k = 0; k < 2; ++k)
|
for (int k = 0; k < 2; ++k)
|
||||||
{
|
{
|
||||||
const unsigned short* v = &mesh.verts[vi[k]*3];
|
const unsigned short* v = &mesh.verts[vi[k]*3];
|
||||||
|
|
@ -555,20 +928,20 @@ void duDebugDrawPolyMesh(duDebugDraw* dd, const struct rcPolyMesh& mesh)
|
||||||
for (int j = 0; j < nvp; ++j)
|
for (int j = 0; j < nvp; ++j)
|
||||||
{
|
{
|
||||||
if (p[j] == RC_MESH_NULL_IDX) break;
|
if (p[j] == RC_MESH_NULL_IDX) break;
|
||||||
if (p[nvp+j] != RC_MESH_NULL_IDX) continue;
|
if ((p[nvp+j] & 0x8000) == 0) continue;
|
||||||
int vi[2];
|
const int nj = (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX) ? 0 : j+1;
|
||||||
vi[0] = p[j];
|
const int vi[2] = {p[j], p[nj]};
|
||||||
if (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX)
|
|
||||||
vi[1] = p[0];
|
unsigned int col = colb;
|
||||||
else
|
if ((p[nvp+j] & 0xf) != 0xf)
|
||||||
vi[1] = p[j+1];
|
col = duRGBA(255,255,255,128);
|
||||||
for (int k = 0; k < 2; ++k)
|
for (int k = 0; k < 2; ++k)
|
||||||
{
|
{
|
||||||
const unsigned short* v = &mesh.verts[vi[k]*3];
|
const unsigned short* v = &mesh.verts[vi[k]*3];
|
||||||
const float x = orig[0] + v[0]*cs;
|
const float x = orig[0] + v[0]*cs;
|
||||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||||
const float z = orig[2] + v[2]*cs;
|
const float z = orig[2] + v[2]*cs;
|
||||||
dd->vertex(x, y, z, colb);
|
dd->vertex(x, y, z, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ bool duDumpPolyMeshDetailToObj(rcPolyMeshDetail& dmesh, duFileIO* io)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int CSET_MAGIC = ('c' << 24) | ('s' << 16) | ('e' << 8) | 't';
|
static const int CSET_MAGIC = ('c' << 24) | ('s' << 16) | ('e' << 8) | 't';
|
||||||
static const int CSET_VERSION = 1;
|
static const int CSET_VERSION = 2;
|
||||||
|
|
||||||
bool duDumpContourSet(struct rcContourSet& cset, duFileIO* io)
|
bool duDumpContourSet(struct rcContourSet& cset, duFileIO* io)
|
||||||
{
|
{
|
||||||
|
|
@ -161,6 +161,10 @@ bool duDumpContourSet(struct rcContourSet& cset, duFileIO* io)
|
||||||
io->write(&cset.cs, sizeof(cset.cs));
|
io->write(&cset.cs, sizeof(cset.cs));
|
||||||
io->write(&cset.ch, sizeof(cset.ch));
|
io->write(&cset.ch, sizeof(cset.ch));
|
||||||
|
|
||||||
|
io->write(&cset.width, sizeof(cset.width));
|
||||||
|
io->write(&cset.height, sizeof(cset.height));
|
||||||
|
io->write(&cset.borderSize, sizeof(cset.borderSize));
|
||||||
|
|
||||||
for (int i = 0; i < cset.nconts; ++i)
|
for (int i = 0; i < cset.nconts; ++i)
|
||||||
{
|
{
|
||||||
const rcContour& cont = cset.conts[i];
|
const rcContour& cont = cset.conts[i];
|
||||||
|
|
@ -221,6 +225,10 @@ bool duReadContourSet(struct rcContourSet& cset, duFileIO* io)
|
||||||
io->read(&cset.cs, sizeof(cset.cs));
|
io->read(&cset.cs, sizeof(cset.cs));
|
||||||
io->read(&cset.ch, sizeof(cset.ch));
|
io->read(&cset.ch, sizeof(cset.ch));
|
||||||
|
|
||||||
|
io->read(&cset.width, sizeof(cset.width));
|
||||||
|
io->read(&cset.height, sizeof(cset.height));
|
||||||
|
io->read(&cset.borderSize, sizeof(cset.borderSize));
|
||||||
|
|
||||||
for (int i = 0; i < cset.nconts; ++i)
|
for (int i = 0; i < cset.nconts; ++i)
|
||||||
{
|
{
|
||||||
rcContour& cont = cset.conts[i];
|
rcContour& cont = cset.conts[i];
|
||||||
|
|
@ -251,7 +259,7 @@ bool duReadContourSet(struct rcContourSet& cset, duFileIO* io)
|
||||||
|
|
||||||
|
|
||||||
static const int CHF_MAGIC = ('r' << 24) | ('c' << 16) | ('h' << 8) | 'f';
|
static const int CHF_MAGIC = ('r' << 24) | ('c' << 16) | ('h' << 8) | 'f';
|
||||||
static const int CHF_VERSION = 2;
|
static const int CHF_VERSION = 3;
|
||||||
|
|
||||||
bool duDumpCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
|
bool duDumpCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
|
||||||
{
|
{
|
||||||
|
|
@ -275,6 +283,7 @@ bool duDumpCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
|
||||||
|
|
||||||
io->write(&chf.walkableHeight, sizeof(chf.walkableHeight));
|
io->write(&chf.walkableHeight, sizeof(chf.walkableHeight));
|
||||||
io->write(&chf.walkableClimb, sizeof(chf.walkableClimb));
|
io->write(&chf.walkableClimb, sizeof(chf.walkableClimb));
|
||||||
|
io->write(&chf.borderSize, sizeof(chf.borderSize));
|
||||||
|
|
||||||
io->write(&chf.maxDistance, sizeof(chf.maxDistance));
|
io->write(&chf.maxDistance, sizeof(chf.maxDistance));
|
||||||
io->write(&chf.maxRegions, sizeof(chf.maxRegions));
|
io->write(&chf.maxRegions, sizeof(chf.maxRegions));
|
||||||
|
|
@ -341,6 +350,7 @@ bool duReadCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
|
||||||
|
|
||||||
io->read(&chf.walkableHeight, sizeof(chf.walkableHeight));
|
io->read(&chf.walkableHeight, sizeof(chf.walkableHeight));
|
||||||
io->read(&chf.walkableClimb, sizeof(chf.walkableClimb));
|
io->read(&chf.walkableClimb, sizeof(chf.walkableClimb));
|
||||||
|
io->write(&chf.borderSize, sizeof(chf.borderSize));
|
||||||
|
|
||||||
io->read(&chf.maxDistance, sizeof(chf.maxDistance));
|
io->read(&chf.maxDistance, sizeof(chf.maxDistance));
|
||||||
io->read(&chf.maxRegions, sizeof(chf.maxRegions));
|
io->read(&chf.maxRegions, sizeof(chf.maxRegions));
|
||||||
|
|
@ -419,7 +429,8 @@ void duLogBuildTimes(rcContext& ctx, const int totalTimeUsec)
|
||||||
logLine(ctx, RC_TIMER_MEDIAN_AREA, "- Median Area", pc);
|
logLine(ctx, RC_TIMER_MEDIAN_AREA, "- Median Area", pc);
|
||||||
logLine(ctx, RC_TIMER_MARK_BOX_AREA, "- Mark Box Area", pc);
|
logLine(ctx, RC_TIMER_MARK_BOX_AREA, "- Mark Box Area", pc);
|
||||||
logLine(ctx, RC_TIMER_MARK_CONVEXPOLY_AREA, "- Mark Convex Area", pc);
|
logLine(ctx, RC_TIMER_MARK_CONVEXPOLY_AREA, "- Mark Convex Area", pc);
|
||||||
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD, "- Build Disntace Field", pc);
|
logLine(ctx, RC_TIMER_MARK_CYLINDER_AREA, "- Mark Cylinder Area", pc);
|
||||||
|
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD, "- Build Distance Field", pc);
|
||||||
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD_DIST, " - Distance", pc);
|
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD_DIST, " - Distance", pc);
|
||||||
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD_BLUR, " - Blur", pc);
|
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD_BLUR, " - Blur", pc);
|
||||||
logLine(ctx, RC_TIMER_BUILD_REGIONS, "- Build Regions", pc);
|
logLine(ctx, RC_TIMER_BUILD_REGIONS, "- Build Regions", pc);
|
||||||
|
|
@ -427,6 +438,7 @@ void duLogBuildTimes(rcContext& ctx, const int totalTimeUsec)
|
||||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_EXPAND, " - Expand", pc);
|
logLine(ctx, RC_TIMER_BUILD_REGIONS_EXPAND, " - Expand", pc);
|
||||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_FLOOD, " - Find Basins", pc);
|
logLine(ctx, RC_TIMER_BUILD_REGIONS_FLOOD, " - Find Basins", pc);
|
||||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_FILTER, " - Filter", pc);
|
logLine(ctx, RC_TIMER_BUILD_REGIONS_FILTER, " - Filter", pc);
|
||||||
|
logLine(ctx, RC_TIMER_BUILD_LAYERS, "- Build Layers", pc);
|
||||||
logLine(ctx, RC_TIMER_BUILD_CONTOURS, "- Build Contours", pc);
|
logLine(ctx, RC_TIMER_BUILD_CONTOURS, "- Build Contours", pc);
|
||||||
logLine(ctx, RC_TIMER_BUILD_CONTOURS_TRACE, " - Trace", pc);
|
logLine(ctx, RC_TIMER_BUILD_CONTOURS_TRACE, " - Trace", pc);
|
||||||
logLine(ctx, RC_TIMER_BUILD_CONTOURS_SIMPLIFY, " - Simplify", pc);
|
logLine(ctx, RC_TIMER_BUILD_CONTOURS_SIMPLIFY, " - Simplify", pc);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
|
# MaNGOS is a full featured server for World of Warcraft, supporting
|
||||||
|
# the following clients: 1.12.x, 2.4.3, 3.2.5a, 4.2.3 and 5.4.8
|
||||||
|
#
|
||||||
|
# Copyright (C) 2005-2014 MaNGOS project <http://getmangos.eu>
|
||||||
|
#
|
||||||
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|
@ -13,5 +18,24 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# ***** END GPL LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
# World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||||
|
# and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# Define the Detour library
|
||||||
|
file(GLOB sources Source/*.cpp)
|
||||||
|
file(GLOB headers Include/*.h)
|
||||||
|
|
||||||
|
set(Detour_LIB_SRCS ${sources} ${headers})
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/Include"
|
||||||
|
)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# Build the Detour library
|
||||||
|
#add_library(detour STATIC ${Detour_LIB_SRCS})
|
||||||
add_subdirectory(Source)
|
add_subdirectory(Source)
|
||||||
|
|
@ -19,18 +19,41 @@
|
||||||
#ifndef DETOURALLOCATOR_H
|
#ifndef DETOURALLOCATOR_H
|
||||||
#define DETOURALLOCATOR_H
|
#define DETOURALLOCATOR_H
|
||||||
|
|
||||||
|
/// Provides hint values to the memory allocator on how long the
|
||||||
|
/// memory is expected to be used.
|
||||||
enum dtAllocHint
|
enum dtAllocHint
|
||||||
{
|
{
|
||||||
DT_ALLOC_PERM, // Memory persist after a function call.
|
DT_ALLOC_PERM, ///< Memory persist after a function call.
|
||||||
DT_ALLOC_TEMP // Memory used temporarily within a function.
|
DT_ALLOC_TEMP ///< Memory used temporarily within a function.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A memory allocation function.
|
||||||
|
// @param[in] size The size, in bytes of memory, to allocate.
|
||||||
|
// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use.
|
||||||
|
// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||||
|
/// @see dtAllocSetCustom
|
||||||
typedef void* (dtAllocFunc)(int size, dtAllocHint hint);
|
typedef void* (dtAllocFunc)(int size, dtAllocHint hint);
|
||||||
|
|
||||||
|
/// A memory deallocation function.
|
||||||
|
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAllocFunc.
|
||||||
|
/// @see dtAllocSetCustom
|
||||||
typedef void (dtFreeFunc)(void* ptr);
|
typedef void (dtFreeFunc)(void* ptr);
|
||||||
|
|
||||||
|
/// Sets the base custom allocation functions to be used by Detour.
|
||||||
|
/// @param[in] allocFunc The memory allocation function to be used by #dtAlloc
|
||||||
|
/// @param[in] freeFunc The memory de-allocation function to be used by #dtFree
|
||||||
void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc);
|
void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc);
|
||||||
|
|
||||||
|
/// Allocates a memory block.
|
||||||
|
/// @param[in] size The size, in bytes of memory, to allocate.
|
||||||
|
/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
|
||||||
|
/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||||
|
/// @see dtFree
|
||||||
void* dtAlloc(int size, dtAllocHint hint);
|
void* dtAlloc(int size, dtAllocHint hint);
|
||||||
|
|
||||||
|
/// Deallocates a memory block.
|
||||||
|
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAlloc.
|
||||||
|
/// @see dtAlloc
|
||||||
void dtFree(void* ptr);
|
void dtFree(void* ptr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
|
// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
|
||||||
# define dtAssert(x) do { (void)sizeof(x); } while(__LINE__==-1,false)
|
# define dtAssert(x) do { (void)sizeof(x); } while((void)(__LINE__==-1),false)
|
||||||
#else
|
#else
|
||||||
# include <assert.h>
|
# include <assert.h>
|
||||||
# define dtAssert assert
|
# define dtAssert assert
|
||||||
|
|
|
||||||
|
|
@ -19,15 +19,71 @@
|
||||||
#ifndef DETOURCOMMON_H
|
#ifndef DETOURCOMMON_H
|
||||||
#define DETOURCOMMON_H
|
#define DETOURCOMMON_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
@defgroup detour Detour
|
||||||
|
|
||||||
|
Members in this module are used to create, manipulate, and query navigation
|
||||||
|
meshes.
|
||||||
|
|
||||||
|
@note This is a summary list of members. Use the index or search
|
||||||
|
feature to find minor members.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// @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.
|
||||||
|
/// @param[in,out] a Value A
|
||||||
|
/// @param[in,out] b Value B
|
||||||
template<class T> inline void dtSwap(T& a, T& b) { T t = a; a = b; b = t; }
|
template<class T> inline void dtSwap(T& a, T& b) { T t = a; a = b; b = t; }
|
||||||
|
|
||||||
|
/// Returns the minimum of two values.
|
||||||
|
/// @param[in] a Value A
|
||||||
|
/// @param[in] b Value B
|
||||||
|
/// @return The minimum of the two values.
|
||||||
template<class T> inline T dtMin(T a, T b) { return a < b ? a : b; }
|
template<class T> inline T dtMin(T a, T b) { return a < b ? a : b; }
|
||||||
|
|
||||||
|
/// Returns the maximum of two values.
|
||||||
|
/// @param[in] a Value A
|
||||||
|
/// @param[in] b Value B
|
||||||
|
/// @return The maximum of the two values.
|
||||||
template<class T> inline T dtMax(T a, T b) { return a > b ? a : b; }
|
template<class T> inline T dtMax(T a, T b) { return a > b ? a : b; }
|
||||||
|
|
||||||
|
/// Returns the absolute value.
|
||||||
|
/// @param[in] a The value.
|
||||||
|
/// @return The absolute value of the specified value.
|
||||||
template<class T> inline T dtAbs(T a) { return a < 0 ? -a : a; }
|
template<class T> inline T dtAbs(T a) { return a < 0 ? -a : a; }
|
||||||
|
|
||||||
|
/// Returns the square of the value.
|
||||||
|
/// @param[in] a The value.
|
||||||
|
/// @return The square of the value.
|
||||||
template<class T> inline T dtSqr(T a) { return a*a; }
|
template<class T> inline T dtSqr(T a) { return a*a; }
|
||||||
|
|
||||||
|
/// Clamps the value to the specified range.
|
||||||
|
/// @param[in] v The value to clamp.
|
||||||
|
/// @param[in] mn The minimum permitted return value.
|
||||||
|
/// @param[in] mx The maximum permitted return value.
|
||||||
|
/// @return The value, clamped to the specified range.
|
||||||
template<class T> inline T dtClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); }
|
template<class T> inline T dtClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); }
|
||||||
|
|
||||||
|
/// Returns the square root of the value.
|
||||||
|
/// @param[in] x The value.
|
||||||
|
/// @return The square root of the vlaue.
|
||||||
float dtSqrt(float x);
|
float dtSqrt(float x);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Vector helper functions.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Derives the cross product of two vectors. (@p v1 x @p v2)
|
||||||
|
/// @param[out] dest The cross product. [(x, y, z)]
|
||||||
|
/// @param[in] v1 A Vector [(x, y, z)]
|
||||||
|
/// @param[in] v2 A vector [(x, y, z)]
|
||||||
inline void dtVcross(float* dest, const float* v1, const float* v2)
|
inline void dtVcross(float* dest, const float* v1, const float* v2)
|
||||||
{
|
{
|
||||||
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||||
|
|
@ -35,11 +91,20 @@ inline void dtVcross(float* dest, const float* v1, const float* v2)
|
||||||
dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derives the dot product of two vectors. (@p v1 . @p v2)
|
||||||
|
/// @param[in] v1 A Vector [(x, y, z)]
|
||||||
|
/// @param[in] v2 A vector [(x, y, z)]
|
||||||
|
/// @return The dot product.
|
||||||
inline float dtVdot(const float* v1, const float* v2)
|
inline float dtVdot(const float* v1, const float* v2)
|
||||||
{
|
{
|
||||||
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s))
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] v1 The base vector. [(x, y, z)]
|
||||||
|
/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
|
||||||
|
/// @param[in] s The amount to scale @p v2 by before adding to @p v1.
|
||||||
inline void dtVmad(float* dest, const float* v1, const float* v2, const float s)
|
inline void dtVmad(float* dest, const float* v1, const float* v2, const float s)
|
||||||
{
|
{
|
||||||
dest[0] = v1[0]+v2[0]*s;
|
dest[0] = v1[0]+v2[0]*s;
|
||||||
|
|
@ -47,6 +112,11 @@ inline void dtVmad(float* dest, const float* v1, const float* v2, const float s)
|
||||||
dest[2] = v1[2]+v2[2]*s;
|
dest[2] = v1[2]+v2[2]*s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs a linear interpolation between two vectors. (@p v1 toward @p v2)
|
||||||
|
/// @param[out] dest The result vector. [(x, y, x)]
|
||||||
|
/// @param[in] v1 The starting vector.
|
||||||
|
/// @param[in] v2 The destination vector.
|
||||||
|
/// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0]
|
||||||
inline void dtVlerp(float* dest, const float* v1, const float* v2, const float t)
|
inline void dtVlerp(float* dest, const float* v1, const float* v2, const float t)
|
||||||
{
|
{
|
||||||
dest[0] = v1[0]+(v2[0]-v1[0])*t;
|
dest[0] = v1[0]+(v2[0]-v1[0])*t;
|
||||||
|
|
@ -54,6 +124,10 @@ inline void dtVlerp(float* dest, const float* v1, const float* v2, const float t
|
||||||
dest[2] = v1[2]+(v2[2]-v1[2])*t;
|
dest[2] = v1[2]+(v2[2]-v1[2])*t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs a vector addition. (@p v1 + @p v2)
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] v1 The base vector. [(x, y, z)]
|
||||||
|
/// @param[in] v2 The vector to add to @p v1. [(x, y, z)]
|
||||||
inline void dtVadd(float* dest, const float* v1, const float* v2)
|
inline void dtVadd(float* dest, const float* v1, const float* v2)
|
||||||
{
|
{
|
||||||
dest[0] = v1[0]+v2[0];
|
dest[0] = v1[0]+v2[0];
|
||||||
|
|
@ -61,6 +135,10 @@ inline void dtVadd(float* dest, const float* v1, const float* v2)
|
||||||
dest[2] = v1[2]+v2[2];
|
dest[2] = v1[2]+v2[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs a vector subtraction. (@p v1 - @p v2)
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] v1 The base vector. [(x, y, z)]
|
||||||
|
/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)]
|
||||||
inline void dtVsub(float* dest, const float* v1, const float* v2)
|
inline void dtVsub(float* dest, const float* v1, const float* v2)
|
||||||
{
|
{
|
||||||
dest[0] = v1[0]-v2[0];
|
dest[0] = v1[0]-v2[0];
|
||||||
|
|
@ -68,6 +146,10 @@ inline void dtVsub(float* dest, const float* v1, const float* v2)
|
||||||
dest[2] = v1[2]-v2[2];
|
dest[2] = v1[2]-v2[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Scales the vector by the specified value. (@p v * @p t)
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] v The vector to scale. [(x, y, z)]
|
||||||
|
/// @param[in] t The scaling factor.
|
||||||
inline void dtVscale(float* dest, const float* v, const float t)
|
inline void dtVscale(float* dest, const float* v, const float t)
|
||||||
{
|
{
|
||||||
dest[0] = v[0]*t;
|
dest[0] = v[0]*t;
|
||||||
|
|
@ -75,6 +157,9 @@ inline void dtVscale(float* dest, const float* v, const float t)
|
||||||
dest[2] = v[2]*t;
|
dest[2] = v[2]*t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Selects the minimum value of each element from the specified vectors.
|
||||||
|
/// @param[in,out] mn A vector. (Will be updated with the result.) [(x, y, z)]
|
||||||
|
/// @param[in] v A vector. [(x, y, z)]
|
||||||
inline void dtVmin(float* mn, const float* v)
|
inline void dtVmin(float* mn, const float* v)
|
||||||
{
|
{
|
||||||
mn[0] = dtMin(mn[0], v[0]);
|
mn[0] = dtMin(mn[0], v[0]);
|
||||||
|
|
@ -82,6 +167,9 @@ inline void dtVmin(float* mn, const float* v)
|
||||||
mn[2] = dtMin(mn[2], v[2]);
|
mn[2] = dtMin(mn[2], v[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Selects the maximum value of each element from the specified vectors.
|
||||||
|
/// @param[in,out] mx A vector. (Will be updated with the result.) [(x, y, z)]
|
||||||
|
/// @param[in] v A vector. [(x, y, z)]
|
||||||
inline void dtVmax(float* mx, const float* v)
|
inline void dtVmax(float* mx, const float* v)
|
||||||
{
|
{
|
||||||
mx[0] = dtMax(mx[0], v[0]);
|
mx[0] = dtMax(mx[0], v[0]);
|
||||||
|
|
@ -89,11 +177,19 @@ inline void dtVmax(float* mx, const float* v)
|
||||||
mx[2] = dtMax(mx[2], v[2]);
|
mx[2] = dtMax(mx[2], v[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the vector elements to the specified values.
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] x The x-value of the vector.
|
||||||
|
/// @param[in] y The y-value of the vector.
|
||||||
|
/// @param[in] z The z-value of the vector.
|
||||||
inline void dtVset(float* dest, const float x, const float y, const float z)
|
inline void dtVset(float* dest, const float x, const float y, const float z)
|
||||||
{
|
{
|
||||||
dest[0] = x; dest[1] = y; dest[2] = z;
|
dest[0] = x; dest[1] = y; dest[2] = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs a vector copy.
|
||||||
|
/// @param[out] dest The result. [(x, y, z)]
|
||||||
|
/// @param[in] a The vector to copy. [(x, y, z)]
|
||||||
inline void dtVcopy(float* dest, const float* a)
|
inline void dtVcopy(float* dest, const float* a)
|
||||||
{
|
{
|
||||||
dest[0] = a[0];
|
dest[0] = a[0];
|
||||||
|
|
@ -101,16 +197,26 @@ inline void dtVcopy(float* dest, const float* a)
|
||||||
dest[2] = a[2];
|
dest[2] = a[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derives the scalar length of the vector.
|
||||||
|
/// @param[in] v The vector. [(x, y, z)]
|
||||||
|
/// @return The scalar length of the vector.
|
||||||
inline float dtVlen(const float* v)
|
inline float dtVlen(const float* v)
|
||||||
{
|
{
|
||||||
return dtSqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
|
return dtSqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derives the square of the scalar length of the vector. (len * len)
|
||||||
|
/// @param[in] v The vector. [(x, y, z)]
|
||||||
|
/// @return The square of the scalar length of the vector.
|
||||||
inline float dtVlenSqr(const float* v)
|
inline float dtVlenSqr(const float* v)
|
||||||
{
|
{
|
||||||
return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the distance between two points.
|
||||||
|
/// @param[in] v1 A point. [(x, y, z)]
|
||||||
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
|
/// @return The distance between the two points.
|
||||||
inline float dtVdist(const float* v1, const float* v2)
|
inline float dtVdist(const float* v1, const float* v2)
|
||||||
{
|
{
|
||||||
const float dx = v2[0] - v1[0];
|
const float dx = v2[0] - v1[0];
|
||||||
|
|
@ -119,6 +225,10 @@ inline float dtVdist(const float* v1, const float* v2)
|
||||||
return dtSqrt(dx*dx + dy*dy + dz*dz);
|
return dtSqrt(dx*dx + dy*dy + dz*dz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the square of the distance between two points.
|
||||||
|
/// @param[in] v1 A point. [(x, y, z)]
|
||||||
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
|
/// @return The square of the distance between the two points.
|
||||||
inline float dtVdistSqr(const float* v1, const float* v2)
|
inline float dtVdistSqr(const float* v1, const float* v2)
|
||||||
{
|
{
|
||||||
const float dx = v2[0] - v1[0];
|
const float dx = v2[0] - v1[0];
|
||||||
|
|
@ -127,6 +237,12 @@ inline float dtVdistSqr(const float* v1, const float* v2)
|
||||||
return dx*dx + dy*dy + dz*dz;
|
return dx*dx + dy*dy + dz*dz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derives the distance between the specified points on the xz-plane.
|
||||||
|
/// @param[in] v1 A point. [(x, y, z)]
|
||||||
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
|
/// @return The distance between the point on the xz-plane.
|
||||||
|
///
|
||||||
|
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
||||||
inline float dtVdist2D(const float* v1, const float* v2)
|
inline float dtVdist2D(const float* v1, const float* v2)
|
||||||
{
|
{
|
||||||
const float dx = v2[0] - v1[0];
|
const float dx = v2[0] - v1[0];
|
||||||
|
|
@ -134,6 +250,10 @@ inline float dtVdist2D(const float* v1, const float* v2)
|
||||||
return dtSqrt(dx*dx + dz*dz);
|
return dtSqrt(dx*dx + dz*dz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derives the square of the distance between the specified points on the xz-plane.
|
||||||
|
/// @param[in] v1 A point. [(x, y, z)]
|
||||||
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
|
/// @return The square of the distance between the point on the xz-plane.
|
||||||
inline float dtVdist2DSqr(const float* v1, const float* v2)
|
inline float dtVdist2DSqr(const float* v1, const float* v2)
|
||||||
{
|
{
|
||||||
const float dx = v2[0] - v1[0];
|
const float dx = v2[0] - v1[0];
|
||||||
|
|
@ -141,6 +261,8 @@ inline float dtVdist2DSqr(const float* v1, const float* v2)
|
||||||
return dx*dx + dz*dz;
|
return dx*dx + dz*dz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Normalizes the vector.
|
||||||
|
/// @param[in,out] v The vector to normalize. [(x, y, z)]
|
||||||
inline void dtVnormalize(float* v)
|
inline void dtVnormalize(float* v)
|
||||||
{
|
{
|
||||||
float d = 1.0f / dtSqrt(dtSqr(v[0]) + dtSqr(v[1]) + dtSqr(v[2]));
|
float d = 1.0f / dtSqrt(dtSqr(v[0]) + dtSqr(v[1]) + dtSqr(v[2]));
|
||||||
|
|
@ -149,6 +271,13 @@ inline void dtVnormalize(float* v)
|
||||||
v[2] *= d;
|
v[2] *= d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs a 'sloppy' colocation check of the specified points.
|
||||||
|
/// @param[in] p0 A point. [(x, y, z)]
|
||||||
|
/// @param[in] p1 A point. [(x, y, z)]
|
||||||
|
/// @return True if the points are considered to be at the same location.
|
||||||
|
///
|
||||||
|
/// Basically, this function will return true if the specified points are
|
||||||
|
/// close enough to eachother to be considered colocated.
|
||||||
inline bool dtVequal(const float* p0, const float* p1)
|
inline bool dtVequal(const float* p0, const float* p1)
|
||||||
{
|
{
|
||||||
static const float thr = dtSqr(1.0f/16384.0f);
|
static const float thr = dtSqr(1.0f/16384.0f);
|
||||||
|
|
@ -156,6 +285,138 @@ inline bool dtVequal(const float* p0, const float* p1)
|
||||||
return d < thr;
|
return d < thr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derives the dot product of two vectors on the xz-plane. (@p u . @p v)
|
||||||
|
/// @param[in] u A vector [(x, y, z)]
|
||||||
|
/// @param[in] v A vector [(x, y, z)]
|
||||||
|
/// @return The dot product on the xz-plane.
|
||||||
|
///
|
||||||
|
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
inline float dtVdot2D(const float* u, const float* v)
|
||||||
|
{
|
||||||
|
return u[0]*v[0] + u[2]*v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the xz-plane 2D perp product of the two vectors. (uz*vx - ux*vz)
|
||||||
|
/// @param[in] u The LHV vector [(x, y, z)]
|
||||||
|
/// @param[in] v The RHV vector [(x, y, z)]
|
||||||
|
/// @return The dot product on the xz-plane.
|
||||||
|
///
|
||||||
|
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
inline float dtVperp2D(const float* u, const float* v)
|
||||||
|
{
|
||||||
|
return u[2]*v[0] - u[0]*v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Computational geometry helper functions.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Derives the signed xz-plane area of the triangle ABC, or the relationship of line AB to point C.
|
||||||
|
/// @param[in] a Vertex A. [(x, y, z)]
|
||||||
|
/// @param[in] b Vertex B. [(x, y, z)]
|
||||||
|
/// @param[in] c Vertex C. [(x, y, z)]
|
||||||
|
/// @return The signed xz-plane area of the triangle.
|
||||||
|
inline float dtTriArea2D(const float* a, const float* b, const float* c)
|
||||||
|
{
|
||||||
|
const float abx = b[0] - a[0];
|
||||||
|
const float abz = b[2] - a[2];
|
||||||
|
const float acx = c[0] - a[0];
|
||||||
|
const float acz = c[2] - a[2];
|
||||||
|
return acx*abz - abx*acz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if two axis-aligned bounding boxes overlap.
|
||||||
|
/// @param[in] amin Minimum bounds of box A. [(x, y, z)]
|
||||||
|
/// @param[in] amax Maximum bounds of box A. [(x, y, z)]
|
||||||
|
/// @param[in] bmin Minimum bounds of box B. [(x, y, z)]
|
||||||
|
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
||||||
|
/// @return True if the two AABB's overlap.
|
||||||
|
/// @see dtOverlapBounds
|
||||||
|
inline bool dtOverlapQuantBounds(const unsigned short amin[3], const unsigned short amax[3],
|
||||||
|
const unsigned short bmin[3], const unsigned short bmax[3])
|
||||||
|
{
|
||||||
|
bool overlap = true;
|
||||||
|
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||||
|
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
||||||
|
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
||||||
|
return overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if two axis-aligned bounding boxes overlap.
|
||||||
|
/// @param[in] amin Minimum bounds of box A. [(x, y, z)]
|
||||||
|
/// @param[in] amax Maximum bounds of box A. [(x, y, z)]
|
||||||
|
/// @param[in] bmin Minimum bounds of box B. [(x, y, z)]
|
||||||
|
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
||||||
|
/// @return True if the two AABB's overlap.
|
||||||
|
/// @see dtOverlapQuantBounds
|
||||||
|
inline bool dtOverlapBounds(const float* amin, const float* amax,
|
||||||
|
const float* bmin, const float* bmax)
|
||||||
|
{
|
||||||
|
bool overlap = true;
|
||||||
|
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||||
|
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
||||||
|
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
||||||
|
return overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the closest point on a triangle from the specified reference point.
|
||||||
|
/// @param[out] closest The closest point on the triangle.
|
||||||
|
/// @param[in] p The reference point from which to test. [(x, y, z)]
|
||||||
|
/// @param[in] a Vertex A of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[in] b Vertex B of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[in] c Vertex C of triangle ABC. [(x, y, z)]
|
||||||
|
void dtClosestPtPointTriangle(float* closest, const float* p,
|
||||||
|
const float* a, const float* b, const float* c);
|
||||||
|
|
||||||
|
/// Derives the y-axis height of the closest point on the triangle from the specified reference point.
|
||||||
|
/// @param[in] p The reference point from which to test. [(x, y, z)]
|
||||||
|
/// @param[in] a Vertex A of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[in] b Vertex B of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[in] c Vertex C of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[out] h The resulting height.
|
||||||
|
bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h);
|
||||||
|
|
||||||
|
bool dtIntersectSegmentPoly2D(const float* p0, const float* p1,
|
||||||
|
const float* verts, int nverts,
|
||||||
|
float& tmin, float& tmax,
|
||||||
|
int& segMin, int& segMax);
|
||||||
|
|
||||||
|
bool dtIntersectSegSeg2D(const float* ap, const float* aq,
|
||||||
|
const float* bp, const float* bq,
|
||||||
|
float& s, float& t);
|
||||||
|
|
||||||
|
/// Determines if the specified point is inside the convex polygon on the xz-plane.
|
||||||
|
/// @param[in] pt The point to check. [(x, y, z)]
|
||||||
|
/// @param[in] verts The polygon vertices. [(x, y, z) * @p nverts]
|
||||||
|
/// @param[in] nverts The number of vertices. [Limit: >= 3]
|
||||||
|
/// @return True if the point is inside the polygon.
|
||||||
|
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts);
|
||||||
|
|
||||||
|
bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
|
||||||
|
float* ed, float* et);
|
||||||
|
|
||||||
|
float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t);
|
||||||
|
|
||||||
|
/// Derives the centroid of a convex polygon.
|
||||||
|
/// @param[out] tc The centroid of the polgyon. [(x, y, z)]
|
||||||
|
/// @param[in] idx The polygon indices. [(vertIndex) * @p nidx]
|
||||||
|
/// @param[in] nidx The number of indices in the polygon. [Limit: >= 3]
|
||||||
|
/// @param[in] verts The polygon vertices. [(x, y, z) * vertCount]
|
||||||
|
void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts);
|
||||||
|
|
||||||
|
/// Determines if the two convex polygons overlap on the xz-plane.
|
||||||
|
/// @param[in] polya Polygon A vertices. [(x, y, z) * @p npolya]
|
||||||
|
/// @param[in] npolya The number of vertices in polygon A.
|
||||||
|
/// @param[in] polyb Polygon B vertices. [(x, y, z) * @p npolyb]
|
||||||
|
/// @param[in] npolyb The number of vertices in polygon B.
|
||||||
|
/// @return True if the two polygons overlap.
|
||||||
|
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
||||||
|
const float* polyb, const int npolyb);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Miscellanious functions.
|
||||||
|
/// @{
|
||||||
|
|
||||||
inline unsigned int dtNextPow2(unsigned int v)
|
inline unsigned int dtNextPow2(unsigned int v)
|
||||||
{
|
{
|
||||||
v--;
|
v--;
|
||||||
|
|
@ -184,65 +445,91 @@ inline int dtAlign4(int x) { return (x+3) & ~3; }
|
||||||
|
|
||||||
inline int dtOppositeTile(int side) { return (side+4) & 0x7; }
|
inline int dtOppositeTile(int side) { return (side+4) & 0x7; }
|
||||||
|
|
||||||
inline float dtVdot2D(const float* u, const float* v)
|
inline void dtSwapByte(unsigned char* a, unsigned char* b)
|
||||||
{
|
{
|
||||||
return u[0]*v[0] + u[2]*v[2];
|
unsigned char tmp = *a;
|
||||||
|
*a = *b;
|
||||||
|
*b = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float dtVperp2D(const float* u, const float* v)
|
inline void dtSwapEndian(unsigned short* v)
|
||||||
{
|
{
|
||||||
return u[2]*v[0] - u[0]*v[2];
|
unsigned char* x = (unsigned char*)v;
|
||||||
|
dtSwapByte(x+0, x+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float dtTriArea2D(const float* a, const float* b, const float* c)
|
inline void dtSwapEndian(short* v)
|
||||||
{
|
{
|
||||||
const float abx = b[0] - a[0];
|
unsigned char* x = (unsigned char*)v;
|
||||||
const float abz = b[2] - a[2];
|
dtSwapByte(x+0, x+1);
|
||||||
const float acx = c[0] - a[0];
|
|
||||||
const float acz = c[2] - a[2];
|
|
||||||
return acx*abz - abx*acz;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool dtOverlapQuantBounds(const unsigned short amin[3], const unsigned short amax[3],
|
inline void dtSwapEndian(unsigned int* v)
|
||||||
const unsigned short bmin[3], const unsigned short bmax[3])
|
|
||||||
{
|
{
|
||||||
bool overlap = true;
|
unsigned char* x = (unsigned char*)v;
|
||||||
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
||||||
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
|
||||||
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
|
||||||
return overlap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool dtOverlapBounds(const float* amin, const float* amax,
|
inline void dtSwapEndian(int* v)
|
||||||
const float* bmin, const float* bmax)
|
|
||||||
{
|
{
|
||||||
bool overlap = true;
|
unsigned char* x = (unsigned char*)v;
|
||||||
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
||||||
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
|
||||||
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
|
||||||
return overlap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dtClosestPtPointTriangle(float* closest, const float* p,
|
inline void dtSwapEndian(float* v)
|
||||||
const float* a, const float* b, const float* c);
|
{
|
||||||
|
unsigned char* x = (unsigned char*)v;
|
||||||
|
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
||||||
|
}
|
||||||
|
|
||||||
bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h);
|
void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
|
||||||
|
const float s, const float t, float* out);
|
||||||
|
|
||||||
bool dtIntersectSegmentPoly2D(const float* p0, const float* p1,
|
/// @}
|
||||||
const float* verts, int nverts,
|
|
||||||
float& tmin, float& tmax,
|
|
||||||
int& segMin, int& segMax);
|
|
||||||
|
|
||||||
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts);
|
|
||||||
|
|
||||||
bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
|
|
||||||
float* ed, float* et);
|
|
||||||
|
|
||||||
float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t);
|
|
||||||
|
|
||||||
void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts);
|
|
||||||
|
|
||||||
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
|
||||||
const float* polyb, const int npolyb);
|
|
||||||
|
|
||||||
#endif // DETOURCOMMON_H
|
#endif // DETOURCOMMON_H
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// This section contains detailed documentation for members that don't have
|
||||||
|
// a source file. It reduces clutter in the main section of the header.
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
@fn float dtTriArea2D(const float* a, const float* b, const float* c)
|
||||||
|
@par
|
||||||
|
|
||||||
|
The vertices are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
|
||||||
|
This is a low cost function than can be used for various purposes. Its main purpose
|
||||||
|
is for point/line relationship testing.
|
||||||
|
|
||||||
|
In all cases: A value of zero indicates that all vertices are collinear or represent the same point.
|
||||||
|
(On the xz-plane.)
|
||||||
|
|
||||||
|
When used for point/line relationship tests, AB usually represents a line against which
|
||||||
|
the C point is to be tested. In this case:
|
||||||
|
|
||||||
|
A positive value indicates that point C is to the left of line AB, looking from A toward B.<br/>
|
||||||
|
A negative value indicates that point C is to the right of lineAB, looking from A toward B.
|
||||||
|
|
||||||
|
When used for evaluating a triangle:
|
||||||
|
|
||||||
|
The absolute value of the return value is two times the area of the triangle when it is
|
||||||
|
projected onto the xz-plane.
|
||||||
|
|
||||||
|
A positive return value indicates:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>The vertices are wrapped in the normal Detour wrap direction.</li>
|
||||||
|
<li>The triangle's 3D face normal is in the general up direction.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
A negative return value indicates:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>The vertices are reverse wrapped. (Wrapped opposite the normal Detour wrap direction.)</li>
|
||||||
|
<li>The triangle's 3D face normal is in the general down direction.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
|
||||||
21
dep/recastnavigation/Detour/Include/DetourMath.h
Normal file
21
dep/recastnavigation/Detour/Include/DetourMath.h
Normal file
|
|
@ -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
|
||||||
|
|
@ -20,409 +20,741 @@
|
||||||
#define DETOURNAVMESH_H
|
#define DETOURNAVMESH_H
|
||||||
|
|
||||||
#include "DetourAlloc.h"
|
#include "DetourAlloc.h"
|
||||||
|
#include "DetourStatus.h"
|
||||||
|
|
||||||
#ifdef WIN32
|
// Undefine (or define in a build cofnig) the following line to use 64bit polyref.
|
||||||
typedef unsigned __int64 uint64;
|
// Generally not needed, useful for very large worlds.
|
||||||
#else
|
// 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>
|
#include <stdint.h>
|
||||||
#ifndef uint64_t
|
|
||||||
#ifdef __linux__
|
|
||||||
#include <linux/types.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
typedef uint64_t uint64;
|
|
||||||
#endif
|
#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 to change dtHashRef() to proper 64-bit hash too.
|
// It is also recommended that you change dtHashRef() to a proper 64-bit hash.
|
||||||
|
|
||||||
// Reference to navigation polygon.
|
/// A handle to a polygon within a navigation mesh tile.
|
||||||
typedef uint64 dtPolyRef;
|
/// @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;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Reference to navigation mesh tile.
|
/// A handle to a tile within a navigation mesh.
|
||||||
typedef uint64 dtTileRef;
|
/// @ingroup detour
|
||||||
|
#ifdef DT_POLYREF64
|
||||||
|
typedef uint64_t dtTileRef;
|
||||||
|
#else
|
||||||
|
typedef unsigned int dtTileRef;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Maximum number of vertices per navigation polygon.
|
/// The maximum number of vertices per navigation polygon.
|
||||||
|
/// @ingroup detour
|
||||||
static const int DT_VERTS_PER_POLYGON = 6;
|
static const int DT_VERTS_PER_POLYGON = 6;
|
||||||
|
|
||||||
static const int DT_NAVMESH_MAGIC = 'D'<<24 | 'N'<<16 | 'A'<<8 | 'V'; //'DNAV';
|
/// @{
|
||||||
static const int DT_NAVMESH_VERSION = 6;
|
/// @name Tile Serialization Constants
|
||||||
|
/// These constants are used to detect whether a navigation tile's data
|
||||||
|
/// and state format is compatible with the current build.
|
||||||
|
///
|
||||||
|
|
||||||
static const int DT_NAVMESH_STATE_MAGIC = 'D'<<24 | 'N'<<16 | 'M'<<8 | 'S'; //'DNMS';
|
/// A magic number used to detect compatibility of navigation tile data.
|
||||||
|
static const int DT_NAVMESH_MAGIC = 'D'<<24 | 'N'<<16 | 'A'<<8 | 'V';
|
||||||
|
|
||||||
|
/// A version number used to detect compatibility of navigation tile data.
|
||||||
|
static const int DT_NAVMESH_VERSION = 7;
|
||||||
|
|
||||||
|
/// A magic number used to detect the compatibility of navigation tile states.
|
||||||
|
static const int DT_NAVMESH_STATE_MAGIC = 'D'<<24 | 'N'<<16 | 'M'<<8 | 'S';
|
||||||
|
|
||||||
|
/// A version number used to detect compatibility of navigation tile states.
|
||||||
static const int DT_NAVMESH_STATE_VERSION = 1;
|
static const int DT_NAVMESH_STATE_VERSION = 1;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// A flag that indicates that an entity links to an external entity.
|
||||||
|
/// (E.g. A polygon edge is a portal that links to another polygon.)
|
||||||
static const unsigned short DT_EXT_LINK = 0x8000;
|
static const unsigned short DT_EXT_LINK = 0x8000;
|
||||||
|
|
||||||
|
/// A value that indicates the entity does not link to anything.
|
||||||
static const unsigned int DT_NULL_LINK = 0xffffffff;
|
static const unsigned int DT_NULL_LINK = 0xffffffff;
|
||||||
|
|
||||||
|
/// A flag that indicates that an off-mesh connection can be traversed in both directions. (Is bidirectional.)
|
||||||
static const unsigned int DT_OFFMESH_CON_BIDIR = 1;
|
static const unsigned int DT_OFFMESH_CON_BIDIR = 1;
|
||||||
|
|
||||||
|
/// The maximum number of user defined area ids.
|
||||||
|
/// @ingroup detour
|
||||||
static const int DT_MAX_AREAS = 64;
|
static const int DT_MAX_AREAS = 64;
|
||||||
|
|
||||||
static const int STATIC_SALT_BITS = 12;
|
/// Tile flags used for various functions and fields.
|
||||||
static const int STATIC_TILE_BITS = 21;
|
/// For an example, see dtNavMesh::addTile().
|
||||||
static const int STATIC_POLY_BITS = 31;
|
|
||||||
// we cannot have over 31 bits for either tile nor poly
|
|
||||||
// without changing polyCount to use 64bits too.
|
|
||||||
|
|
||||||
// Flags for addTile
|
|
||||||
enum dtTileFlags
|
enum dtTileFlags
|
||||||
{
|
{
|
||||||
DT_TILE_FREE_DATA = 0x01, // Navmesh owns the tile memory and should free it.
|
/// The navigation mesh owns the tile memory and is responsible for freeing it.
|
||||||
|
DT_TILE_FREE_DATA = 0x01,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Flags returned by findStraightPath().
|
/// Vertex flags returned by dtNavMeshQuery::findStraightPath.
|
||||||
enum dtStraightPathFlags
|
enum dtStraightPathFlags
|
||||||
{
|
{
|
||||||
DT_STRAIGHTPATH_START = 0x01, // The vertex is the start position.
|
DT_STRAIGHTPATH_START = 0x01, ///< The vertex is the start position in the path.
|
||||||
DT_STRAIGHTPATH_END = 0x02, // The vertex is the end position.
|
DT_STRAIGHTPATH_END = 0x02, ///< The vertex is the end position in the path.
|
||||||
DT_STRAIGHTPATH_OFFMESH_CONNECTION = 0x04, // The vertex is start of an off-mesh link.
|
DT_STRAIGHTPATH_OFFMESH_CONNECTION = 0x04, ///< The vertex is the start of an off-mesh connection.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Flags describing polygon properties.
|
/// Options for dtNavMeshQuery::findStraightPath.
|
||||||
|
enum dtStraightPathOptions
|
||||||
|
{
|
||||||
|
DT_STRAIGHTPATH_AREA_CROSSINGS = 0x01, ///< Add a vertex at every polygon edge crossing where area changes.
|
||||||
|
DT_STRAIGHTPATH_ALL_CROSSINGS = 0x02, ///< Add a vertex at every polygon edge crossing.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Options for dtNavMeshQuery::findPath
|
||||||
|
enum dtFindPathOptions
|
||||||
|
{
|
||||||
|
DT_FINDPATH_LOW_QUALITY_FAR = 0x01, ///< [provisional] trade quality for performance far from the origin. The idea is that by then a new query will be issued
|
||||||
|
DT_FINDPATH_ANY_ANGLE = 0x02, ///< use raycasts during pathfind to "shortcut" (raycast still consider costs)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Options for dtNavMeshQuery::raycast
|
||||||
|
enum dtRaycastOptions
|
||||||
|
{
|
||||||
|
DT_RAYCAST_USE_COSTS = 0x01, ///< Raycast should calculate movement cost along the ray and fill RaycastHit::cost
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Limit raycasting during any angle pahfinding
|
||||||
|
/// The limit is given as a multiple of the character radius
|
||||||
|
static const float DT_RAY_CAST_LIMIT_PROPORTIONS = 50.0f;
|
||||||
|
|
||||||
|
/// Flags representing the type of a navigation mesh polygon.
|
||||||
enum dtPolyTypes
|
enum dtPolyTypes
|
||||||
{
|
{
|
||||||
DT_POLYTYPE_GROUND = 0, // Regular ground polygons.
|
/// The polygon is a standard convex polygon that is part of the surface of the mesh.
|
||||||
DT_POLYTYPE_OFFMESH_CONNECTION = 1, // Off-mesh connections.
|
DT_POLYTYPE_GROUND = 0,
|
||||||
};
|
/// The polygon is an off-mesh connection consisting of two vertices.
|
||||||
|
DT_POLYTYPE_OFFMESH_CONNECTION = 1,
|
||||||
enum dtStatus
|
|
||||||
{
|
|
||||||
DT_FAILURE = 0, // Operation failed.
|
|
||||||
DT_FAILURE_DATA_MAGIC,
|
|
||||||
DT_FAILURE_DATA_VERSION,
|
|
||||||
DT_FAILURE_OUT_OF_MEMORY,
|
|
||||||
DT_SUCCESS, // Operation succeed.
|
|
||||||
DT_IN_PROGRESS, // Operation still in progress.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Structure describing the navigation polygon data.
|
/// Defines a polyogn within a dtMeshTile object.
|
||||||
|
/// @ingroup detour
|
||||||
struct dtPoly
|
struct dtPoly
|
||||||
{
|
{
|
||||||
unsigned int firstLink; // Index to first link in linked list.
|
/// Index to first link in linked list. (Or #DT_NULL_LINK if there is no link.)
|
||||||
unsigned short verts[DT_VERTS_PER_POLYGON]; // Indices to vertices of the poly.
|
unsigned int firstLink;
|
||||||
unsigned short neis[DT_VERTS_PER_POLYGON]; // Refs to neighbours of the poly.
|
|
||||||
unsigned short flags; // Flags (see dtPolyFlags).
|
/// The indices of the polygon's vertices.
|
||||||
unsigned char vertCount; // Number of vertices.
|
/// The actual vertices are located in dtMeshTile::verts.
|
||||||
unsigned char areaAndtype; // Bit packed: Area ID of the polygon, and Polygon type, see dtPolyTypes..
|
unsigned short verts[DT_VERTS_PER_POLYGON];
|
||||||
|
|
||||||
|
/// Packed data representing neighbor polygons references and flags for each edge.
|
||||||
|
unsigned short neis[DT_VERTS_PER_POLYGON];
|
||||||
|
|
||||||
|
/// The user defined polygon flags.
|
||||||
|
unsigned short flags;
|
||||||
|
|
||||||
|
/// The number of vertices in the polygon.
|
||||||
|
unsigned char vertCount;
|
||||||
|
|
||||||
|
/// The bit packed area id and polygon type.
|
||||||
|
/// @note Use the structure's set and get methods to acess this value.
|
||||||
|
unsigned char areaAndtype;
|
||||||
|
|
||||||
|
/// Sets the user defined area id. [Limit: < #DT_MAX_AREAS]
|
||||||
inline void setArea(unsigned char a) { areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f); }
|
inline void setArea(unsigned char a) { areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f); }
|
||||||
|
|
||||||
|
/// Sets the polygon type. (See: #dtPolyTypes.)
|
||||||
inline void setType(unsigned char t) { areaAndtype = (areaAndtype & 0x3f) | (t << 6); }
|
inline void setType(unsigned char t) { areaAndtype = (areaAndtype & 0x3f) | (t << 6); }
|
||||||
|
|
||||||
|
/// Gets the user defined area id.
|
||||||
inline unsigned char getArea() const { return areaAndtype & 0x3f; }
|
inline unsigned char getArea() const { return areaAndtype & 0x3f; }
|
||||||
|
|
||||||
|
/// Gets the polygon type. (See: #dtPolyTypes)
|
||||||
inline unsigned char getType() const { return areaAndtype >> 6; }
|
inline unsigned char getType() const { return areaAndtype >> 6; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Stucture describing polygon detail triangles.
|
/// Defines the location of detail sub-mesh data within a dtMeshTile.
|
||||||
struct dtPolyDetail
|
struct dtPolyDetail
|
||||||
{
|
{
|
||||||
unsigned int vertBase; // Offset to detail vertex array.
|
unsigned int vertBase; ///< The offset of the vertices in the dtMeshTile::detailVerts array.
|
||||||
unsigned int triBase; // Offset to detail triangle array.
|
unsigned int triBase; ///< The offset of the triangles in the dtMeshTile::detailTris array.
|
||||||
unsigned char vertCount; // Number of vertices in the detail mesh.
|
unsigned char vertCount; ///< The number of vertices in the sub-mesh.
|
||||||
unsigned char triCount; // Number of triangles.
|
unsigned char triCount; ///< The number of triangles in the sub-mesh.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Stucture describing a link to another polygon.
|
/// Defines a link between polygons.
|
||||||
|
/// @note This structure is rarely if ever used by the end user.
|
||||||
|
/// @see dtMeshTile
|
||||||
struct dtLink
|
struct dtLink
|
||||||
{
|
{
|
||||||
dtPolyRef ref; // Neighbour reference.
|
dtPolyRef ref; ///< Neighbour reference. (The neighbor that is linked to.)
|
||||||
unsigned int next; // Index to next link.
|
unsigned int next; ///< Index of the next link.
|
||||||
unsigned char edge; // Index to polygon edge which owns this link.
|
unsigned char edge; ///< Index of the polygon edge that owns this link.
|
||||||
unsigned char side; // If boundary link, defines on which side the link is.
|
unsigned char side; ///< If a boundary link, defines on which side the link is.
|
||||||
unsigned char bmin, bmax; // If boundary link, defines the sub edge area.
|
unsigned char bmin; ///< If a boundary link, defines the minimum sub-edge area.
|
||||||
|
unsigned char bmax; ///< If a boundary link, defines the maximum sub-edge area.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Bounding volume node.
|
||||||
|
/// @note This structure is rarely if ever used by the end user.
|
||||||
|
/// @see dtMeshTile
|
||||||
struct dtBVNode
|
struct dtBVNode
|
||||||
{
|
{
|
||||||
unsigned short bmin[3], bmax[3]; // BVnode bounds
|
unsigned short bmin[3]; ///< Minimum bounds of the node's AABB. [(x, y, z)]
|
||||||
int i; // Index to item or if negative, escape index.
|
unsigned short bmax[3]; ///< Maximum bounds of the node's AABB. [(x, y, z)]
|
||||||
|
int i; ///< The node's index. (Negative for escape sequence.)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Defines an navigation mesh off-mesh connection within a dtMeshTile object.
|
||||||
|
/// An off-mesh connection is a user defined traversable connection made up to two vertices.
|
||||||
struct dtOffMeshConnection
|
struct dtOffMeshConnection
|
||||||
{
|
{
|
||||||
float pos[6]; // Both end point locations.
|
/// The endpoints of the connection. [(ax, ay, az, bx, by, bz)]
|
||||||
float rad; // Link connection radius.
|
float pos[6];
|
||||||
unsigned short poly; // Poly Id
|
|
||||||
unsigned char flags; // Link flags
|
/// The radius of the endpoints. [Limit: >= 0]
|
||||||
unsigned char side; // End point side.
|
float rad;
|
||||||
unsigned int userId; // User ID to identify this connection.
|
|
||||||
|
/// The polygon reference of the connection within the tile.
|
||||||
|
unsigned short poly;
|
||||||
|
|
||||||
|
/// Link flags.
|
||||||
|
/// @note These are not the connection's user defined flags. Those are assigned via the
|
||||||
|
/// connection's dtPoly definition. These are link flags used for internal purposes.
|
||||||
|
unsigned char flags;
|
||||||
|
|
||||||
|
/// End point side.
|
||||||
|
unsigned char side;
|
||||||
|
|
||||||
|
/// The id of the offmesh connection. (User assigned when the navigation mesh is built.)
|
||||||
|
unsigned int userId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Provides high level information related to a dtMeshTile object.
|
||||||
|
/// @ingroup detour
|
||||||
struct dtMeshHeader
|
struct dtMeshHeader
|
||||||
{
|
{
|
||||||
int magic; // Magic number, used to identify the data.
|
int magic; ///< Tile magic number. (Used to identify the data format.)
|
||||||
int version; // Data version number.
|
int version; ///< Tile data format version number.
|
||||||
int x, y; // Location of the time on the grid.
|
int x; ///< The x-position of the tile within the dtNavMesh tile grid. (x, y, layer)
|
||||||
unsigned int userId; // User ID of the tile.
|
int y; ///< The y-position of the tile within the dtNavMesh tile grid. (x, y, layer)
|
||||||
int polyCount; // Number of polygons in the tile.
|
int layer; ///< The layer of the tile within the dtNavMesh tile grid. (x, y, layer)
|
||||||
int vertCount; // Number of vertices in the tile.
|
unsigned int userId; ///< The user defined id of the tile.
|
||||||
int maxLinkCount; // Number of allocated links.
|
int polyCount; ///< The number of polygons in the tile.
|
||||||
int detailMeshCount; // Number of detail meshes.
|
int vertCount; ///< The number of vertices in the tile.
|
||||||
int detailVertCount; // Number of detail vertices.
|
int maxLinkCount; ///< The number of allocated links.
|
||||||
int detailTriCount; // Number of detail triangles.
|
int detailMeshCount; ///< The number of sub-meshes in the detail mesh.
|
||||||
int bvNodeCount; // Number of BVtree nodes.
|
|
||||||
int offMeshConCount; // Number of Off-Mesh links.
|
/// The number of unique vertices in the detail mesh. (In addition to the polygon vertices.)
|
||||||
int offMeshBase; // Index to first polygon which is Off-Mesh link.
|
int detailVertCount;
|
||||||
float walkableHeight; // Height of the agent.
|
|
||||||
float walkableRadius; // Radius of the agent
|
int detailTriCount; ///< The number of triangles in the detail mesh.
|
||||||
float walkableClimb; // Max climb height of the agent.
|
int bvNodeCount; ///< The number of bounding volume nodes. (Zero if bounding volumes are disabled.)
|
||||||
float bmin[3], bmax[3]; // Bounding box of the tile.
|
int offMeshConCount; ///< The number of off-mesh connections.
|
||||||
float bvQuantFactor; // BVtree quantization factor (world to bvnode coords)
|
int offMeshBase; ///< The index of the first polygon which is an off-mesh connection.
|
||||||
|
float walkableHeight; ///< The height of the agents using the tile.
|
||||||
|
float walkableRadius; ///< The radius of the agents using the tile.
|
||||||
|
float walkableClimb; ///< The maximum climb height of the agents using the tile.
|
||||||
|
float bmin[3]; ///< The minimum bounds of the tile's AABB. [(x, y, z)]
|
||||||
|
float bmax[3]; ///< The maximum bounds of the tile's AABB. [(x, y, z)]
|
||||||
|
|
||||||
|
/// The bounding volume quantization factor.
|
||||||
|
float bvQuantFactor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Defines a navigation mesh tile.
|
||||||
|
/// @ingroup detour
|
||||||
struct dtMeshTile
|
struct dtMeshTile
|
||||||
{
|
{
|
||||||
unsigned int salt; // Counter describing modifications to the tile.
|
unsigned int salt; ///< Counter describing modifications to the tile.
|
||||||
|
|
||||||
unsigned int linksFreeList; // Index to next free link.
|
unsigned int linksFreeList; ///< Index to the next free link.
|
||||||
dtMeshHeader* header; // Pointer to tile header.
|
dtMeshHeader* header; ///< The tile header.
|
||||||
dtPoly* polys; // Pointer to the polygons (will be updated when tile is added).
|
dtPoly* polys; ///< The tile polygons. [Size: dtMeshHeader::polyCount]
|
||||||
float* verts; // Pointer to the vertices (will be updated when tile added).
|
float* verts; ///< The tile vertices. [Size: dtMeshHeader::vertCount]
|
||||||
dtLink* links; // Pointer to the links (will be updated when tile added).
|
dtLink* links; ///< The tile links. [Size: dtMeshHeader::maxLinkCount]
|
||||||
dtPolyDetail* detailMeshes; // Pointer to detail meshes (will be updated when tile added).
|
dtPolyDetail* detailMeshes; ///< The tile's detail sub-meshes. [Size: dtMeshHeader::detailMeshCount]
|
||||||
float* detailVerts; // Pointer to detail vertices (will be updated when tile added).
|
|
||||||
unsigned char* detailTris; // Pointer to detail triangles (will be updated when tile added).
|
|
||||||
dtBVNode* bvTree; // Pointer to BVtree nodes (will be updated when tile added).
|
|
||||||
dtOffMeshConnection* offMeshCons; // Pointer to Off-Mesh links. (will be updated when tile added).
|
|
||||||
|
|
||||||
unsigned char* data; // Pointer to tile data.
|
/// The detail mesh's unique vertices. [(x, y, z) * dtMeshHeader::detailVertCount]
|
||||||
int dataSize; // Size of the tile data.
|
float* detailVerts;
|
||||||
int flags; // Tile flags, see dtTileFlags.
|
|
||||||
dtMeshTile* next; // Next free tile or, next tile in spatial grid.
|
/// The detail mesh's triangles. [(vertA, vertB, vertC) * dtMeshHeader::detailTriCount]
|
||||||
|
unsigned char* detailTris;
|
||||||
|
|
||||||
|
/// The tile bounding volume nodes. [Size: dtMeshHeader::bvNodeCount]
|
||||||
|
/// (Will be null if bounding volumes are disabled.)
|
||||||
|
dtBVNode* bvTree;
|
||||||
|
|
||||||
|
dtOffMeshConnection* offMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
|
||||||
|
|
||||||
|
unsigned char* data; ///< The tile data. (Not directly accessed under normal situations.)
|
||||||
|
int dataSize; ///< Size of the tile data.
|
||||||
|
int flags; ///< Tile flags. (See: #dtTileFlags)
|
||||||
|
dtMeshTile* next; ///< The next free tile, or the next tile in the spatial grid.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Configuration parameters used to define multi-tile navigation meshes.
|
||||||
|
/// The values are used to allocate space during the initialization of a navigation mesh.
|
||||||
|
/// @see dtNavMesh::init()
|
||||||
|
/// @ingroup detour
|
||||||
struct dtNavMeshParams
|
struct dtNavMeshParams
|
||||||
{
|
{
|
||||||
float orig[3]; // Origin of the nav mesh tile space.
|
float orig[3]; ///< The world space origin of the navigation mesh's tile space. [(x, y, z)]
|
||||||
float tileWidth, tileHeight; // Width and height of each tile.
|
float tileWidth; ///< The width of each tile. (Along the x-axis.)
|
||||||
int maxTiles; // Maximum number of tiles the navmesh can contain.
|
float tileHeight; ///< The height of each tile. (Along the z-axis.)
|
||||||
int maxPolys; // Maximum number of polygons each tile can contain.
|
int maxTiles; ///< The maximum number of tiles the navigation mesh can contain.
|
||||||
|
int maxPolys; ///< The maximum number of polygons each tile can contain.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A navigation mesh based on tiles of convex polygons.
|
||||||
|
/// @ingroup detour
|
||||||
class dtNavMesh
|
class dtNavMesh
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
dtNavMesh();
|
dtNavMesh();
|
||||||
~dtNavMesh();
|
~dtNavMesh();
|
||||||
|
|
||||||
// Initializes the nav mesh for tiled use.
|
/// @{
|
||||||
// Params:
|
/// @name Initialization and Tile Management
|
||||||
// params - (in) navmesh initialization params, see dtNavMeshParams.
|
|
||||||
// Returns: True if succeed, else false.
|
/// Initializes the navigation mesh for tiled use.
|
||||||
|
/// @param[in] params Initialization parameters.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
dtStatus init(const dtNavMeshParams* params);
|
dtStatus init(const dtNavMeshParams* params);
|
||||||
|
|
||||||
// Initializes the nav mesh for single tile use.
|
/// Initializes the navigation mesh for single tile use.
|
||||||
// Params:
|
/// @param[in] data Data of the new tile. (See: #dtCreateNavMeshData)
|
||||||
// data - (in) Data of the new tile mesh.
|
/// @param[in] dataSize The data size of the new tile.
|
||||||
// dataSize - (in) Data size of the new tile mesh.
|
/// @param[in] flags The tile flags. (See: #dtTileFlags)
|
||||||
// flags - (in) Tile flags, see dtTileFlags.
|
/// @return The status flags for the operation.
|
||||||
// Returns: True if succeed, else false.
|
/// @see dtCreateNavMeshData
|
||||||
dtStatus init(unsigned char* data, const int dataSize, const int flags);
|
dtStatus init(unsigned char* data, const int dataSize, const int flags);
|
||||||
|
|
||||||
// Returns pointer to navmesh initialization params.
|
/// The navigation mesh initialization params.
|
||||||
const dtNavMeshParams* getParams() const;
|
const dtNavMeshParams* getParams() const;
|
||||||
|
|
||||||
// Adds new tile into the navmesh.
|
/// Adds a tile to the navigation mesh.
|
||||||
// The add will fail if the data is in wrong format,
|
/// @param[in] data Data for the new tile mesh. (See: #dtCreateNavMeshData)
|
||||||
// there is not enough tiles left, or if there is a tile already at the location.
|
/// @param[in] dataSize Data size of the new tile mesh.
|
||||||
// Params:
|
/// @param[in] flags Tile flags. (See: #dtTileFlags)
|
||||||
// data - (in) Data of the new tile mesh.
|
/// @param[in] lastRef The desired reference for the tile. (When reloading a tile.) [opt] [Default: 0]
|
||||||
// dataSize - (in) Data size of the new tile mesh.
|
/// @param[out] result The tile reference. (If the tile was succesfully added.) [opt]
|
||||||
// flags - (in) Tile flags, see dtTileFlags.
|
/// @return The status flags for the operation.
|
||||||
// lastRef - (in,optional) Last tile ref, the tile will be restored so that
|
|
||||||
// the reference (as well as poly references) will be the same. Default: 0.
|
|
||||||
// result - (out,optional) tile ref if the tile was succesfully added.
|
|
||||||
dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result);
|
dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result);
|
||||||
|
|
||||||
// Removes specified tile.
|
/// Removes the specified tile from the navigation mesh.
|
||||||
// Params:
|
/// @param[in] ref The reference of the tile to remove.
|
||||||
// ref - (in) Reference to the tile to remove.
|
/// @param[out] data Data associated with deleted tile.
|
||||||
// data - (out) Data associated with deleted tile.
|
/// @param[out] dataSize Size of the data associated with deleted tile.
|
||||||
// dataSize - (out) Size of the data associated with deleted tile.
|
/// @return The status flags for the operation.
|
||||||
dtStatus removeTile(dtTileRef ref, unsigned char** data, int* dataSize);
|
dtStatus removeTile(dtTileRef ref, unsigned char** data, int* dataSize);
|
||||||
|
|
||||||
// Calculates tile location based in input world position.
|
/// @}
|
||||||
// Params:
|
|
||||||
// pos - (in) world position of the query.
|
/// @{
|
||||||
// tx - (out) tile x location.
|
/// @name Query Functions
|
||||||
// ty - (out) tile y location.
|
|
||||||
|
/// Calculates the tile grid location for the specified world position.
|
||||||
|
/// @param[in] pos The world position for the query. [(x, y, z)]
|
||||||
|
/// @param[out] tx The tile's x-location. (x, y)
|
||||||
|
/// @param[out] ty The tile's y-location. (x, y)
|
||||||
void calcTileLoc(const float* pos, int* tx, int* ty) const;
|
void calcTileLoc(const float* pos, int* tx, int* ty) const;
|
||||||
|
|
||||||
// Returns pointer to tile at specified location.
|
/// Gets the tile at the specified grid location.
|
||||||
// Params:
|
/// @param[in] x The tile's x-location. (x, y, layer)
|
||||||
// x,y - (in) Location of the tile to get.
|
/// @param[in] y The tile's y-location. (x, y, layer)
|
||||||
// Returns: pointer to tile if tile exists or 0 tile does not exists.
|
/// @param[in] layer The tile's layer. (x, y, layer)
|
||||||
const dtMeshTile* getTileAt(int x, int y) const;
|
/// @return The tile, or null if the tile does not exist.
|
||||||
|
const dtMeshTile* getTileAt(const int x, const int y, const int layer) const;
|
||||||
|
|
||||||
// Returns reference to tile at specified location.
|
/// Gets all tiles at the specified grid location. (All layers.)
|
||||||
// Params:
|
/// @param[in] x The tile's x-location. (x, y)
|
||||||
// x,y - (in) Location of the tile to get.
|
/// @param[in] y The tile's y-location. (x, y)
|
||||||
// Returns: reference to tile if tile exists or 0 tile does not exists.
|
/// @param[out] tiles A pointer to an array of tiles that will hold the result.
|
||||||
dtTileRef getTileRefAt(int x, int y) const;
|
/// @param[in] maxTiles The maximum tiles the tiles parameter can hold.
|
||||||
|
/// @return The number of tiles returned in the tiles array.
|
||||||
|
int getTilesAt(const int x, const int y,
|
||||||
|
dtMeshTile const** tiles, const int maxTiles) const;
|
||||||
|
|
||||||
// Returns tile references of a tile based on tile pointer.
|
/// Gets the tile reference for the tile at specified grid location.
|
||||||
|
/// @param[in] x The tile's x-location. (x, y, layer)
|
||||||
|
/// @param[in] y The tile's y-location. (x, y, layer)
|
||||||
|
/// @param[in] layer The tile's layer. (x, y, layer)
|
||||||
|
/// @return The tile reference of the tile, or 0 if there is none.
|
||||||
|
dtTileRef getTileRefAt(int x, int y, int layer) const;
|
||||||
|
|
||||||
|
/// Gets the tile reference for the specified tile.
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @return The tile reference of the tile.
|
||||||
dtTileRef getTileRef(const dtMeshTile* tile) const;
|
dtTileRef getTileRef(const dtMeshTile* tile) const;
|
||||||
|
|
||||||
// Returns tile based on references.
|
/// Gets the tile for the specified tile reference.
|
||||||
|
/// @param[in] ref The tile reference of the tile to retrieve.
|
||||||
|
/// @return The tile for the specified reference, or null if the
|
||||||
|
/// reference is invalid.
|
||||||
const dtMeshTile* getTileByRef(dtTileRef ref) const;
|
const dtMeshTile* getTileByRef(dtTileRef ref) const;
|
||||||
|
|
||||||
// Returns max number of tiles.
|
/// The maximum number of tiles supported by the navigation mesh.
|
||||||
|
/// @return The maximum number of tiles supported by the navigation mesh.
|
||||||
int getMaxTiles() const;
|
int getMaxTiles() const;
|
||||||
|
|
||||||
// Returns pointer to tile in the tile array.
|
/// Gets the tile at the specified index.
|
||||||
// Params:
|
/// @param[in] i The tile index. [Limit: 0 >= index < #getMaxTiles()]
|
||||||
// i - (in) Index to the tile to retrieve, max index is getMaxTiles()-1.
|
/// @return The tile at the specified index.
|
||||||
// Returns: Pointer to specified tile.
|
|
||||||
const dtMeshTile* getTile(int i) const;
|
const dtMeshTile* getTile(int i) const;
|
||||||
|
|
||||||
// Returns pointer to tile and polygon pointed by the polygon reference.
|
/// Gets the tile and polygon for the specified polygon reference.
|
||||||
// Params:
|
/// @param[in] ref The reference for the a polygon.
|
||||||
// ref - (in) reference to a polygon.
|
/// @param[out] tile The tile containing the polygon.
|
||||||
// tile - (out) pointer to the tile containing the polygon.
|
/// @param[out] poly The polygon.
|
||||||
// poly - (out) pointer to the polygon.
|
/// @return The status flags for the operation.
|
||||||
dtStatus getTileAndPolyByRef(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
dtStatus getTileAndPolyByRef(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
||||||
|
|
||||||
// Returns pointer to tile and polygon pointed by the polygon reference.
|
/// Returns the tile and polygon for the specified polygon reference.
|
||||||
// Note: this function does not check if 'ref' s valid, and is thus faster. Use only with valid refs!
|
/// @param[in] ref A known valid reference for a polygon.
|
||||||
// Params:
|
/// @param[out] tile The tile containing the polygon.
|
||||||
// ref - (in) reference to a polygon.
|
/// @param[out] poly The polygon.
|
||||||
// tile - (out) pointer to the tile containing the polygon.
|
|
||||||
// poly - (out) pointer to the polygon.
|
|
||||||
void getTileAndPolyByRefUnsafe(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
void getTileAndPolyByRefUnsafe(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
||||||
|
|
||||||
// Returns true if polygon reference points to valid data.
|
/// Checks the validity of a polygon reference.
|
||||||
|
/// @param[in] ref The polygon reference to check.
|
||||||
|
/// @return True if polygon reference is valid for the navigation mesh.
|
||||||
bool isValidPolyRef(dtPolyRef ref) const;
|
bool isValidPolyRef(dtPolyRef ref) const;
|
||||||
|
|
||||||
// Returns base poly id for specified tile, polygon refs can be deducted from this.
|
/// Gets the polygon reference for the tile's base polygon.
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @return The polygon reference for the base polygon in the specified tile.
|
||||||
dtPolyRef getPolyRefBase(const dtMeshTile* tile) const;
|
dtPolyRef getPolyRefBase(const dtMeshTile* tile) const;
|
||||||
|
|
||||||
// Returns start and end location of an off-mesh link polygon.
|
/// Gets the endpoints for an off-mesh connection, ordered by "direction of travel".
|
||||||
// Params:
|
/// @param[in] prevRef The reference of the polygon before the connection.
|
||||||
// prevRef - (in) ref to the polygon before the link (used to select direction).
|
/// @param[in] polyRef The reference of the off-mesh connection polygon.
|
||||||
// polyRef - (in) ref to the off-mesh link polygon.
|
/// @param[out] startPos The start position of the off-mesh connection. [(x, y, z)]
|
||||||
// startPos[3] - (out) start point of the link.
|
/// @param[out] endPos The end position of the off-mesh connection. [(x, y, z)]
|
||||||
// endPos[3] - (out) end point of the link.
|
/// @return The status flags for the operation.
|
||||||
// Returns: true if link is found.
|
|
||||||
dtStatus getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, float* startPos, float* endPos) const;
|
dtStatus getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, float* startPos, float* endPos) const;
|
||||||
|
|
||||||
// Returns pointer to off-mesh connection based on polyref, or null if ref not valid.
|
/// Gets the specified off-mesh connection.
|
||||||
|
/// @param[in] ref The polygon reference of the off-mesh connection.
|
||||||
|
/// @return The specified off-mesh connection, or null if the polygon reference is not valid.
|
||||||
const dtOffMeshConnection* getOffMeshConnectionByRef(dtPolyRef ref) const;
|
const dtOffMeshConnection* getOffMeshConnectionByRef(dtPolyRef ref) const;
|
||||||
|
|
||||||
// Sets polygon flags.
|
/// @}
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// @name State Management
|
||||||
|
/// These functions do not effect #dtTileRef or #dtPolyRef's.
|
||||||
|
|
||||||
|
/// Sets the user defined flags for the specified polygon.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @param[in] flags The new flags for the polygon.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
dtStatus setPolyFlags(dtPolyRef ref, unsigned short flags);
|
dtStatus setPolyFlags(dtPolyRef ref, unsigned short flags);
|
||||||
|
|
||||||
// Return polygon flags.
|
/// Gets the user defined flags for the specified polygon.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @param[out] resultFlags The polygon flags.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
dtStatus getPolyFlags(dtPolyRef ref, unsigned short* resultFlags) const;
|
dtStatus getPolyFlags(dtPolyRef ref, unsigned short* resultFlags) const;
|
||||||
|
|
||||||
// Set polygon type.
|
/// Sets the user defined area for the specified polygon.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @param[in] area The new area id for the polygon. [Limit: < #DT_MAX_AREAS]
|
||||||
|
/// @return The status flags for the operation.
|
||||||
dtStatus setPolyArea(dtPolyRef ref, unsigned char area);
|
dtStatus setPolyArea(dtPolyRef ref, unsigned char area);
|
||||||
|
|
||||||
// Return polygon area type.
|
/// Gets the user defined area for the specified polygon.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @param[out] resultArea The area id for the polygon.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
dtStatus getPolyArea(dtPolyRef ref, unsigned char* resultArea) const;
|
dtStatus getPolyArea(dtPolyRef ref, unsigned char* resultArea) const;
|
||||||
|
|
||||||
|
/// Gets the size of the buffer required by #storeTileState to store the specified tile's state.
|
||||||
// Returns number of bytes required to store tile state.
|
/// @param[in] tile The tile.
|
||||||
|
/// @return The size of the buffer required to store the state.
|
||||||
int getTileStateSize(const dtMeshTile* tile) const;
|
int getTileStateSize(const dtMeshTile* tile) const;
|
||||||
|
|
||||||
// Stores tile state to buffer.
|
/// Stores the non-structural state of the tile in the specified buffer. (Flags, area ids, etc.)
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @param[out] data The buffer to store the tile's state in.
|
||||||
|
/// @param[in] maxDataSize The size of the data buffer. [Limit: >= #getTileStateSize]
|
||||||
|
/// @return The status flags for the operation.
|
||||||
dtStatus storeTileState(const dtMeshTile* tile, unsigned char* data, const int maxDataSize) const;
|
dtStatus storeTileState(const dtMeshTile* tile, unsigned char* data, const int maxDataSize) const;
|
||||||
|
|
||||||
// Restores tile state.
|
/// Restores the state of the tile.
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @param[in] data The new state. (Obtained from #storeTileState.)
|
||||||
|
/// @param[in] maxDataSize The size of the state within the data buffer.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
dtStatus restoreTileState(dtMeshTile* tile, const unsigned char* data, const int maxDataSize);
|
dtStatus restoreTileState(dtMeshTile* tile, const unsigned char* data, const int maxDataSize);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
// Encodes a tile id.
|
/// @{
|
||||||
|
/// @name Encoding and Decoding
|
||||||
|
/// These functions are generally meant for internal use only.
|
||||||
|
|
||||||
|
/// Derives a standard polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] salt The tile's salt value.
|
||||||
|
/// @param[in] it The index of 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 tile id.
|
/// Decodes a standard polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] ref The polygon reference to decode.
|
||||||
|
/// @param[out] salt The tile's salt value.
|
||||||
|
/// @param[out] it The index of the tile.
|
||||||
|
/// @param[out] ip The index of the polygon within the tile.
|
||||||
|
/// @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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decodes a tile salt.
|
/// Extracts a tile's salt value from the specified polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decodes a tile id.
|
/// Extracts the tile's index from the specified polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decodes a poly id.
|
/// Extracts the polygon's index (within its tile) from the specified polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Returns pointer to tile in the tile array.
|
/// Returns pointer to tile in the tile array.
|
||||||
dtMeshTile* getTile(int i);
|
dtMeshTile* getTile(int i);
|
||||||
|
|
||||||
// Returns neighbour tile based on side.
|
/// Returns neighbour tile based on side.
|
||||||
dtMeshTile* getNeighbourTileAt(int x, int y, int side) const;
|
int getTilesAt(const int x, const int y,
|
||||||
// Returns all polygons in neighbour tile based on portal defined by the segment.
|
dtMeshTile** tiles, const int maxTiles) const;
|
||||||
|
|
||||||
|
/// Returns neighbour tile based on side.
|
||||||
|
int getNeighbourTilesAt(const int x, const int y, const int side,
|
||||||
|
dtMeshTile** tiles, const int maxTiles) const;
|
||||||
|
|
||||||
|
/// Returns all polygons in neighbour tile based on portal defined by the segment.
|
||||||
int findConnectingPolys(const float* va, const float* vb,
|
int findConnectingPolys(const float* va, const float* vb,
|
||||||
const dtMeshTile* tile, int side,
|
const dtMeshTile* tile, int side,
|
||||||
dtPolyRef* con, float* conarea, int maxcon) const;
|
dtPolyRef* con, float* conarea, int maxcon) const;
|
||||||
|
|
||||||
// Builds internal polygons links for a tile.
|
/// Builds internal polygons links for a tile.
|
||||||
void connectIntLinks(dtMeshTile* tile);
|
void connectIntLinks(dtMeshTile* tile);
|
||||||
// Builds internal polygons links for a tile.
|
/// Builds internal polygons links for a tile.
|
||||||
void connectIntOffMeshLinks(dtMeshTile* tile);
|
void baseOffMeshLinks(dtMeshTile* tile);
|
||||||
|
|
||||||
// Builds external polygon links for a tile.
|
/// Builds external polygon links for a tile.
|
||||||
void connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
void connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||||
// Builds external polygon links for a tile.
|
/// Builds external polygon links for a tile.
|
||||||
void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||||
|
|
||||||
// Removes external links at specified side.
|
/// Removes external links at specified side.
|
||||||
void unconnectExtLinks(dtMeshTile* tile, int side);
|
void unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target);
|
||||||
|
|
||||||
|
|
||||||
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed for off-mesh connection finding.
|
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed for off-mesh connection finding.
|
||||||
|
|
||||||
// Queries polygons within a tile.
|
/// Queries polygons within a tile.
|
||||||
int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
||||||
dtPolyRef* polys, const int maxPolys) const;
|
dtPolyRef* polys, const int maxPolys) const;
|
||||||
// Find nearest polygon within a tile.
|
/// Find nearest polygon within a tile.
|
||||||
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.
|
||||||
dtStatus closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip,
|
void closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
|
||||||
const float* pos, float* closest) 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)
|
||||||
float m_tileWidth, m_tileHeight; // Dimensions of each tile.
|
float m_tileWidth, m_tileHeight; ///< Dimensions of each tile.
|
||||||
int m_maxTiles; // Max number of tiles.
|
int m_maxTiles; ///< Max number of tiles.
|
||||||
int m_tileLutSize; // Tile hash lookup size (must be pot).
|
int m_tileLutSize; ///< Tile hash lookup size (must be pot).
|
||||||
int m_tileLutMask; // Tile hash lookup mask.
|
int m_tileLutMask; ///< Tile hash lookup mask.
|
||||||
|
|
||||||
dtMeshTile** m_posLookup; // Tile hash lookup.
|
dtMeshTile** m_posLookup; ///< Tile hash lookup.
|
||||||
dtMeshTile* m_nextFree; // Freelist of tiles.
|
dtMeshTile* m_nextFree; ///< Freelist of tiles.
|
||||||
dtMeshTile* m_tiles; // List of tiles.
|
dtMeshTile* m_tiles; ///< List of tiles.
|
||||||
|
|
||||||
unsigned int m_saltBits; // Number of salt bits in the tile ID.
|
#ifndef DT_POLYREF64
|
||||||
unsigned int m_tileBits; // Number of tile bits in the tile ID.
|
unsigned int m_saltBits; ///< Number of salt bits in the tile ID.
|
||||||
unsigned int m_polyBits; // Number of poly 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.
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to allocate navmesh class using Detour allocator.
|
/// Allocates a navigation mesh object using the Detour allocator.
|
||||||
|
/// @return A navigation mesh that is ready for initialization, or null on failure.
|
||||||
|
/// @ingroup detour
|
||||||
dtNavMesh* dtAllocNavMesh();
|
dtNavMesh* dtAllocNavMesh();
|
||||||
|
|
||||||
|
/// Frees the specified navigation mesh object using the Detour allocator.
|
||||||
|
/// @param[in] navmesh A navigation mesh allocated using #dtAllocNavMesh
|
||||||
|
/// @ingroup detour
|
||||||
void dtFreeNavMesh(dtNavMesh* navmesh);
|
void dtFreeNavMesh(dtNavMesh* navmesh);
|
||||||
|
|
||||||
#endif // DETOURNAVMESH_H
|
#endif // DETOURNAVMESH_H
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// This section contains detailed documentation for members that don't have
|
||||||
|
// a source file. It reduces clutter in the main section of the header.
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
@typedef dtPolyRef
|
||||||
|
@par
|
||||||
|
|
||||||
|
Polygon references are subject to the same invalidate/preserve/restore
|
||||||
|
rules that apply to #dtTileRef's. If the #dtTileRef for the polygon's
|
||||||
|
tile changes, the polygon reference becomes invalid.
|
||||||
|
|
||||||
|
Changing a polygon's flags, area id, etc. does not impact its polygon
|
||||||
|
reference.
|
||||||
|
|
||||||
|
@typedef dtTileRef
|
||||||
|
@par
|
||||||
|
|
||||||
|
The following changes will invalidate a tile reference:
|
||||||
|
|
||||||
|
- The referenced tile has been removed from the navigation mesh.
|
||||||
|
- The navigation mesh has been initialized using a different set
|
||||||
|
of #dtNavMeshParams.
|
||||||
|
|
||||||
|
A tile reference is preserved/restored if the tile is added to a navigation
|
||||||
|
mesh initialized with the original #dtNavMeshParams and is added at the
|
||||||
|
original reference location. (E.g. The lastRef parameter is used with
|
||||||
|
dtNavMesh::addTile.)
|
||||||
|
|
||||||
|
Basically, if the storage structure of a tile changes, its associated
|
||||||
|
tile reference changes.
|
||||||
|
|
||||||
|
|
||||||
|
@var unsigned short dtPoly::neis[DT_VERTS_PER_POLYGON]
|
||||||
|
@par
|
||||||
|
|
||||||
|
Each entry represents data for the edge starting at the vertex of the same index.
|
||||||
|
E.g. The entry at index n represents the edge data for vertex[n] to vertex[n+1].
|
||||||
|
|
||||||
|
A value of zero indicates the edge has no polygon connection. (It makes up the
|
||||||
|
border of the navigation mesh.)
|
||||||
|
|
||||||
|
The information can be extracted as follows:
|
||||||
|
@code
|
||||||
|
neighborRef = neis[n] & 0xff; // Get the neighbor polygon reference.
|
||||||
|
|
||||||
|
if (neis[n] & #DT_EX_LINK)
|
||||||
|
{
|
||||||
|
// The edge is an external (portal) edge.
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@var float dtMeshHeader::bvQuantFactor
|
||||||
|
@par
|
||||||
|
|
||||||
|
This value is used for converting between world and bounding volume coordinates.
|
||||||
|
For example:
|
||||||
|
@code
|
||||||
|
const float cs = 1.0f / tile->header->bvQuantFactor;
|
||||||
|
const dtBVNode* n = &tile->bvTree[i];
|
||||||
|
if (n->i >= 0)
|
||||||
|
{
|
||||||
|
// This is a leaf node.
|
||||||
|
float worldMinX = tile->header->bmin[0] + n->bmin[0]*cs;
|
||||||
|
float worldMinY = tile->header->bmin[0] + n->bmin[1]*cs;
|
||||||
|
// Etc...
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@struct dtMeshTile
|
||||||
|
@par
|
||||||
|
|
||||||
|
Tiles generally only exist within the context of a dtNavMesh object.
|
||||||
|
|
||||||
|
Some tile content is optional. For example, a tile may not contain any
|
||||||
|
off-mesh connections. In this case the associated pointer will be null.
|
||||||
|
|
||||||
|
If a detail mesh exists it will share vertices with the base polygon mesh.
|
||||||
|
Only the vertices unique to the detail mesh will be stored in #detailVerts.
|
||||||
|
|
||||||
|
@warning Tiles returned by a dtNavMesh object are not guarenteed to be populated.
|
||||||
|
For example: The tile at a location might not have been loaded yet, or may have been removed.
|
||||||
|
In this case, pointers will be null. So if in doubt, check the polygon count in the
|
||||||
|
tile's header to determine if a tile has polygons defined.
|
||||||
|
|
||||||
|
@var float dtOffMeshConnection::pos[6]
|
||||||
|
@par
|
||||||
|
|
||||||
|
For a properly built navigation mesh, vertex A will always be within the bounds of the mesh.
|
||||||
|
Vertex B is not required to be within the bounds of the mesh.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -21,57 +21,128 @@
|
||||||
|
|
||||||
#include "DetourAlloc.h"
|
#include "DetourAlloc.h"
|
||||||
|
|
||||||
|
/// Represents the source data used to build an navigation mesh tile.
|
||||||
// The units of the parameters are specified in parenthesis as follows:
|
/// @ingroup detour
|
||||||
// (vx) voxels, (wu) world units
|
|
||||||
struct dtNavMeshCreateParams
|
struct dtNavMeshCreateParams
|
||||||
{
|
{
|
||||||
// Navmesh vertices.
|
|
||||||
const unsigned short* verts; // Array of vertices, each vertex has 3 components. (vx).
|
/// @name Polygon Mesh Attributes
|
||||||
int vertCount; // Vertex count
|
/// Used to create the base navigation graph.
|
||||||
// Navmesh polygons
|
/// See #rcPolyMesh for details related to these attributes.
|
||||||
const unsigned short* polys; // Array of polygons, uses same format as rcPolyMesh.
|
/// @{
|
||||||
const unsigned short* polyFlags; // Array of flags per polygon.
|
|
||||||
const unsigned char* polyAreas; // Array of area ids per polygon.
|
const unsigned short* verts; ///< The polygon mesh vertices. [(x, y, z) * #vertCount] [Unit: vx]
|
||||||
int polyCount; // Number of polygons
|
int vertCount; ///< The number vertices in the polygon mesh. [Limit: >= 3]
|
||||||
int nvp; // Number of verts per polygon.
|
const unsigned short* polys; ///< The polygon data. [Size: #polyCount * 2 * #nvp]
|
||||||
// Navmesh Detail
|
const unsigned short* polyFlags; ///< The user defined flags assigned to each polygon. [Size: #polyCount]
|
||||||
const unsigned int* detailMeshes; // Detail meshes, uses same format as rcPolyMeshDetail.
|
const unsigned char* polyAreas; ///< The user defined area ids assigned to each polygon. [Size: #polyCount]
|
||||||
const float* detailVerts; // Detail mesh vertices, uses same format as rcPolyMeshDetail (wu).
|
int polyCount; ///< Number of polygons in the mesh. [Limit: >= 1]
|
||||||
int detailVertsCount; // Total number of detail vertices
|
int nvp; ///< Number maximum number of vertices per polygon. [Limit: >= 3]
|
||||||
const unsigned char* detailTris; // Array of detail tris per detail mesh.
|
|
||||||
int detailTriCount; // Total number of detail triangles.
|
/// @}
|
||||||
// Off-Mesh Connections.
|
/// @name Height Detail Attributes (Optional)
|
||||||
const float* offMeshConVerts; // Off-mesh connection vertices (wu).
|
/// See #rcPolyMeshDetail for details related to these attributes.
|
||||||
const float* offMeshConRad; // Off-mesh connection radii (wu).
|
/// @{
|
||||||
const unsigned short* offMeshConFlags; // Off-mesh connection flags.
|
|
||||||
const unsigned char* offMeshConAreas; // Off-mesh connection area ids.
|
const unsigned int* detailMeshes; ///< The height detail sub-mesh data. [Size: 4 * #polyCount]
|
||||||
const unsigned char* offMeshConDir; // Off-mesh connection direction flags (1 = bidir, 0 = oneway).
|
const float* detailVerts; ///< The detail mesh vertices. [Size: 3 * #detailVertsCount] [Unit: wu]
|
||||||
const unsigned int* offMeshConUserID; // Off-mesh connection user id (optional).
|
int detailVertsCount; ///< The number of vertices in the detail mesh.
|
||||||
int offMeshConCount; // Number of off-mesh connections
|
const unsigned char* detailTris; ///< The detail mesh triangles. [Size: 4 * #detailTriCount]
|
||||||
// Tile location
|
int detailTriCount; ///< The number of triangles in the detail mesh.
|
||||||
unsigned int userId; // User ID bound to the tile.
|
|
||||||
int tileX, tileY; // Tile location (tile coords).
|
/// @}
|
||||||
float bmin[3], bmax[3]; // Tile bounds (wu).
|
/// @name Off-Mesh Connections Attributes (Optional)
|
||||||
// Settings
|
/// Used to define a custom point-to-point edge within the navigation graph, an
|
||||||
float walkableHeight; // Agent height (wu).
|
/// off-mesh connection is a user defined traversable connection made up to two vertices,
|
||||||
float walkableRadius; // Agent radius (wu).
|
/// at least one of which resides within a navigation mesh polygon.
|
||||||
float walkableClimb; // Agent max climb (wu).
|
/// @{
|
||||||
float cs; // Cell size (xz) (wu).
|
|
||||||
float ch; // Cell height (y) (wu).
|
/// Off-mesh connection vertices. [(ax, ay, az, bx, by, bz) * #offMeshConCount] [Unit: wu]
|
||||||
int tileSize; // Tile size (width & height) (vx).
|
const float* offMeshConVerts;
|
||||||
|
/// Off-mesh connection radii. [Size: #offMeshConCount] [Unit: wu]
|
||||||
|
const float* offMeshConRad;
|
||||||
|
/// User defined flags assigned to the off-mesh connections. [Size: #offMeshConCount]
|
||||||
|
const unsigned short* offMeshConFlags;
|
||||||
|
/// User defined area ids assigned to the off-mesh connections. [Size: #offMeshConCount]
|
||||||
|
const unsigned char* offMeshConAreas;
|
||||||
|
/// The permitted travel direction of the off-mesh connections. [Size: #offMeshConCount]
|
||||||
|
///
|
||||||
|
/// 0 = Travel only from endpoint A to endpoint B.<br/>
|
||||||
|
/// #DT_OFFMESH_CON_BIDIR = Bidirectional travel.
|
||||||
|
const unsigned char* offMeshConDir;
|
||||||
|
/// The user defined ids of the off-mesh connection. [Size: #offMeshConCount]
|
||||||
|
const unsigned int* offMeshConUserID;
|
||||||
|
/// The number of off-mesh connections. [Limit: >= 0]
|
||||||
|
int offMeshConCount;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Tile Attributes
|
||||||
|
/// @note The tile grid/layer data can be left at zero if the destination is a single tile mesh.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
unsigned int userId; ///< The user defined id of the tile.
|
||||||
|
int tileX; ///< The tile's x-grid location within the multi-tile destination mesh. (Along the x-axis.)
|
||||||
|
int tileY; ///< The tile's y-grid location within the multi-tile desitation mesh. (Along the z-axis.)
|
||||||
|
int tileLayer; ///< The tile's layer within the layered destination mesh. [Limit: >= 0] (Along the y-axis.)
|
||||||
|
float bmin[3]; ///< The minimum bounds of the tile. [(x, y, z)] [Unit: wu]
|
||||||
|
float bmax[3]; ///< The maximum bounds of the tile. [(x, y, z)] [Unit: wu]
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name General Configuration Attributes
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
float walkableHeight; ///< The agent height. [Unit: wu]
|
||||||
|
float walkableRadius; ///< The agent radius. [Unit: wu]
|
||||||
|
float walkableClimb; ///< The agent maximum traversable ledge. (Up/Down) [Unit: wu]
|
||||||
|
float cs; ///< The xz-plane cell size of the polygon mesh. [Limit: > 0] [Unit: wu]
|
||||||
|
float ch; ///< The y-axis cell height of the polygon mesh. [Limit: > 0] [Unit: wu]
|
||||||
|
|
||||||
|
/// True if a bounding volume tree should be built for the tile.
|
||||||
|
/// @note The BVTree is not normally needed for layered navigation meshes.
|
||||||
|
bool buildBvTree;
|
||||||
|
|
||||||
|
/// @}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build navmesh data from given input data.
|
/// Builds navigation mesh tile data from the provided tile creation data.
|
||||||
|
/// @ingroup detour
|
||||||
|
/// @param[in] params Tile creation data.
|
||||||
|
/// @param[out] outData The resulting tile data.
|
||||||
|
/// @param[out] outDataSize The size of the tile data array.
|
||||||
|
/// @return True if the tile data was successfully created.
|
||||||
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize);
|
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize);
|
||||||
|
|
||||||
// Swaps endianess of navmesh header.
|
/// Swaps the endianess of the tile data's header (#dtMeshHeader).
|
||||||
|
/// @param[in,out] data The tile data array.
|
||||||
|
/// @param[in] dataSize The size of the data array.
|
||||||
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int dataSize);
|
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int dataSize);
|
||||||
|
|
||||||
// Swaps endianess of the navmesh data. This function assumes that the header is in correct
|
/// Swaps endianess of the tile data.
|
||||||
// endianess already. Call dtNavMeshHeaderSwapEndian() first on the data if the data is
|
/// @param[in,out] data The tile data array.
|
||||||
// assumed to be in wrong endianess to start with. If converting from native endianess to foreign,
|
/// @param[in] dataSize The size of the data array.
|
||||||
// call dtNavMeshHeaderSwapEndian() after the data has been swapped.
|
|
||||||
bool dtNavMeshDataSwapEndian(unsigned char* data, const int dataSize);
|
bool dtNavMeshDataSwapEndian(unsigned char* data, const int dataSize);
|
||||||
|
|
||||||
#endif // DETOURNAVMESHBUILDER_H
|
#endif // DETOURNAVMESHBUILDER_H
|
||||||
|
|
||||||
|
// This section contains detailed documentation for members that don't have
|
||||||
|
// a source file. It reduces clutter in the main section of the header.
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
@struct dtNavMeshCreateParams
|
||||||
|
@par
|
||||||
|
|
||||||
|
This structure is used to marshal data between the Recast mesh generation pipeline and Detour navigation components.
|
||||||
|
|
||||||
|
See the rcPolyMesh and rcPolyMeshDetail documentation for detailed information related to mesh structure.
|
||||||
|
|
||||||
|
Units are usually in voxels (vx) or world units (wu). The units for voxels, grid size, and cell size
|
||||||
|
are all based on the values of #cs and #ch.
|
||||||
|
|
||||||
|
The standard navigation mesh build process is to create tile data using dtCreateNavMeshData, then add the tile
|
||||||
|
to a navigation mesh using either the dtNavMesh single tile <tt>init()</tt> function or the dtNavMesh::addTile()
|
||||||
|
function.
|
||||||
|
|
||||||
|
@see dtCreateNavMeshData
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
@ -20,39 +20,35 @@
|
||||||
#define DETOURNAVMESHQUERY_H
|
#define DETOURNAVMESHQUERY_H
|
||||||
|
|
||||||
#include "DetourNavMesh.h"
|
#include "DetourNavMesh.h"
|
||||||
|
#include "DetourStatus.h"
|
||||||
|
|
||||||
|
|
||||||
// Define DT_VIRTUAL_QUERYFILTER if you wish to derive a custom filter from dtQueryFilter.
|
// Define DT_VIRTUAL_QUERYFILTER if you wish to derive a custom filter from dtQueryFilter.
|
||||||
// On certain platforms indirect or virtual function call is expensive. The default
|
// On certain platforms indirect or virtual function call is expensive. The default
|
||||||
// setting is to use non-virtual functions, the actualy implementations of the functions
|
// setting is to use non-virtual functions, the actual implementations of the functions
|
||||||
// are declared as inline for maximum speed.
|
// are declared as inline for maximum speed.
|
||||||
|
|
||||||
//#define DT_VIRTUAL_QUERYFILTER 1
|
//#define DT_VIRTUAL_QUERYFILTER 1
|
||||||
|
|
||||||
// Class for polygon filtering and cost calculation during query operations.
|
/// Defines polygon filtering and traversal costs for navigation mesh query operations.
|
||||||
// - It is possible to derive a custom query filter from dtQueryFilter by overriding
|
/// @ingroup detour
|
||||||
// the virtual functions passFilter() and getCost().
|
|
||||||
// - Both functions should be as fast as possible. Use cached local copy of data
|
|
||||||
// instead of accessing your own objects where possible.
|
|
||||||
// - You do not need to adhere to the flags and cost logic provided by the default
|
|
||||||
// implementation.
|
|
||||||
// - In order for the A* to work properly, the cost should be proportional to
|
|
||||||
// the travel distance. Using cost modifier less than 1.0 is likely to lead
|
|
||||||
// to problems during pathfinding.
|
|
||||||
class dtQueryFilter
|
class dtQueryFilter
|
||||||
{
|
{
|
||||||
float m_areaCost[DT_MAX_AREAS]; // Array storing cost per area type, used by default implementation.
|
float m_areaCost[DT_MAX_AREAS]; ///< Cost per area type. (Used by default implementation.)
|
||||||
unsigned short m_includeFlags; // Include poly flags, used by default implementation.
|
unsigned short m_includeFlags; ///< Flags for polygons that can be visited. (Used by default implementation.)
|
||||||
unsigned short m_excludeFlags; // Exclude poly flags, used by default implementation.
|
unsigned short m_excludeFlags; ///< Flags for polygons that should not be visted. (Used by default implementation.)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
dtQueryFilter();
|
dtQueryFilter();
|
||||||
|
|
||||||
// Returns true if the polygon is can visited.
|
#ifdef DT_VIRTUAL_QUERYFILTER
|
||||||
// Params:
|
virtual ~dtQueryFilter() { }
|
||||||
// ref - (in) reference to the polygon test.
|
#endif
|
||||||
// tile - (in) pointer to the tile of the polygon test.
|
|
||||||
// poly - (in) pointer to the polygon test.
|
/// Returns true if the polygon can be visited. (I.e. Is traversable.)
|
||||||
|
/// @param[in] ref The reference id of the polygon test.
|
||||||
|
/// @param[in] tile The tile containing the polygon.
|
||||||
|
/// @param[in] poly The polygon to test.
|
||||||
#ifdef DT_VIRTUAL_QUERYFILTER
|
#ifdef DT_VIRTUAL_QUERYFILTER
|
||||||
virtual bool passFilter(const dtPolyRef ref,
|
virtual bool passFilter(const dtPolyRef ref,
|
||||||
const dtMeshTile* tile,
|
const dtMeshTile* tile,
|
||||||
|
|
@ -63,16 +59,19 @@ public:
|
||||||
const dtPoly* poly) const;
|
const dtPoly* poly) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Returns cost to travel from 'pa' to 'pb'.'
|
/// Returns cost to move from the beginning to the end of a line segment
|
||||||
// The segment is fully contained inside 'cur'.
|
/// that is fully contained within a polygon.
|
||||||
// 'pa' lies on the edge between 'prev' and 'cur',
|
/// @param[in] pa The start position on the edge of the previous and current polygon. [(x, y, z)]
|
||||||
// 'pb' lies on the edge between 'cur' and 'next'.
|
/// @param[in] pb The end position on the edge of the current and next polygon. [(x, y, z)]
|
||||||
// Params:
|
/// @param[in] prevRef The reference id of the previous polygon. [opt]
|
||||||
// pa - (in) segment start position.
|
/// @param[in] prevTile The tile containing the previous polygon. [opt]
|
||||||
// pb - (in) segment end position.
|
/// @param[in] prevPoly The previous polygon. [opt]
|
||||||
// prevRef, prevTile, prevPoly - (in) data describing the previous polygon, can be null.
|
/// @param[in] curRef The reference id of the current polygon.
|
||||||
// curRef, curTile, curPoly - (in) data describing the current polygon.
|
/// @param[in] curTile The tile containing the current polygon.
|
||||||
// nextRef, nextTile, nextPoly - (in) data describing the next polygon, can be null.
|
/// @param[in] curPoly The current polygon.
|
||||||
|
/// @param[in] nextRef The refernece id of the next polygon. [opt]
|
||||||
|
/// @param[in] nextTile The tile containing the next polygon. [opt]
|
||||||
|
/// @param[in] nextPoly The next polygon. [opt]
|
||||||
#ifdef DT_VIRTUAL_QUERYFILTER
|
#ifdef DT_VIRTUAL_QUERYFILTER
|
||||||
virtual float getCost(const float* pa, const float* pb,
|
virtual float getCost(const float* pa, const float* pb,
|
||||||
const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly,
|
const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly,
|
||||||
|
|
@ -85,304 +84,426 @@ public:
|
||||||
const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const;
|
const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Getters and setters for the default implementation data.
|
/// @name Getters and setters for the default implementation data.
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/// Returns the traversal cost of the area.
|
||||||
|
/// @param[in] i The id of the area.
|
||||||
|
/// @returns The traversal cost of the area.
|
||||||
inline float getAreaCost(const int i) const { return m_areaCost[i]; }
|
inline float getAreaCost(const int i) const { return m_areaCost[i]; }
|
||||||
|
|
||||||
|
/// Sets the traversal cost of the area.
|
||||||
|
/// @param[in] i The id of the area.
|
||||||
|
/// @param[in] cost The new cost of traversing the area.
|
||||||
inline void setAreaCost(const int i, const float cost) { m_areaCost[i] = cost; }
|
inline void setAreaCost(const int i, const float cost) { m_areaCost[i] = cost; }
|
||||||
|
|
||||||
|
/// Returns the include flags for the filter.
|
||||||
|
/// Any polygons that include one or more of these flags will be
|
||||||
|
/// included in the operation.
|
||||||
inline unsigned short getIncludeFlags() const { return m_includeFlags; }
|
inline unsigned short getIncludeFlags() const { return m_includeFlags; }
|
||||||
|
|
||||||
|
/// Sets the include flags for the filter.
|
||||||
|
/// @param[in] flags The new flags.
|
||||||
inline void setIncludeFlags(const unsigned short flags) { m_includeFlags = flags; }
|
inline void setIncludeFlags(const unsigned short flags) { m_includeFlags = flags; }
|
||||||
|
|
||||||
|
/// Returns the exclude flags for the filter.
|
||||||
|
/// Any polygons that include one ore more of these flags will be
|
||||||
|
/// excluded from the operation.
|
||||||
inline unsigned short getExcludeFlags() const { return m_excludeFlags; }
|
inline unsigned short getExcludeFlags() const { return m_excludeFlags; }
|
||||||
|
|
||||||
|
/// Sets the exclude flags for the filter.
|
||||||
|
/// @param[in] flags The new flags.
|
||||||
inline void setExcludeFlags(const unsigned short flags) { m_excludeFlags = flags; }
|
inline void setExcludeFlags(const unsigned short flags) { m_excludeFlags = flags; }
|
||||||
|
|
||||||
|
///@}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Provides information about raycast hit
|
||||||
|
/// filled by dtNavMeshQuery::raycast
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtRaycastHit
|
||||||
|
{
|
||||||
|
/// The hit parameter. (FLT_MAX if no wall hit.)
|
||||||
|
float t;
|
||||||
|
|
||||||
|
/// hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
||||||
|
float hitNormal[3];
|
||||||
|
|
||||||
|
/// Pointer to an array of reference ids of the visited polygons. [opt]
|
||||||
|
dtPolyRef* path;
|
||||||
|
|
||||||
|
/// The number of visited polygons. [opt]
|
||||||
|
int pathCount;
|
||||||
|
|
||||||
|
/// The maximum number of polygons the @p path array can hold.
|
||||||
|
int maxPath;
|
||||||
|
|
||||||
|
/// The cost of the path until hit.
|
||||||
|
float pathCost;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Provides the ability to perform pathfinding related queries against
|
||||||
|
/// a navigation mesh.
|
||||||
|
/// @ingroup detour
|
||||||
class dtNavMeshQuery
|
class dtNavMeshQuery
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
dtNavMeshQuery();
|
dtNavMeshQuery();
|
||||||
~dtNavMeshQuery();
|
~dtNavMeshQuery();
|
||||||
|
|
||||||
// Initializes the nav mesh query.
|
/// Initializes the query object.
|
||||||
// Params:
|
/// @param[in] nav Pointer to the dtNavMesh object to use for all queries.
|
||||||
// nav - (in) pointer to navigation mesh data.
|
/// @param[in] maxNodes Maximum number of search nodes. [Limits: 0 < value <= 65536]
|
||||||
// maxNodes - (in) Maximum number of search nodes to use (max 65536).
|
/// @returns The status flags for the query.
|
||||||
// Returns: True if succeed, else false.
|
|
||||||
dtStatus init(const dtNavMesh* nav, const int maxNodes);
|
dtStatus init(const dtNavMesh* nav, const int maxNodes);
|
||||||
|
|
||||||
// Finds the nearest navigation polygon around the center location.
|
/// @name Standard Pathfinding Functions
|
||||||
// Params:
|
// /@{
|
||||||
// center[3] - (in) The center of the search box.
|
|
||||||
// extents[3] - (in) The extents of the search box.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// nearestRef - (out) Reference to the nearest polygon.
|
|
||||||
// nearestPt[3] - (out, opt) The nearest point on found polygon, null if not needed.
|
|
||||||
// Returns: Reference identifier for the polygon, or 0 if no polygons found.
|
|
||||||
dtStatus findNearestPoly(const float* center, const float* extents,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* nearestRef, float* nearestPt) const;
|
|
||||||
|
|
||||||
// Returns polygons which overlap the query box.
|
/// Finds a path from the start polygon to the end polygon.
|
||||||
// Params:
|
/// @param[in] startRef The refrence id of the start polygon.
|
||||||
// center[3] - (in) the center of the search box.
|
/// @param[in] endRef The reference id of the end polygon.
|
||||||
// extents[3] - (in) the extents of the search box.
|
/// @param[in] startPos A position within the start polygon. [(x, y, z)]
|
||||||
// filter - (in) path polygon filter.
|
/// @param[in] endPos A position within the end polygon. [(x, y, z)]
|
||||||
// polys - (out) array holding the search result.
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
// polyCount - (out) Number of polygons in search result array.
|
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||||
// maxPolys - (in) The max number of polygons the polys array can hold.
|
/// [(polyRef) * @p pathCount]
|
||||||
dtStatus queryPolygons(const float* center, const float* extents,
|
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||||
const dtQueryFilter* filter,
|
/// @param[in] maxPath The maximum number of polygons the @p path array can hold. [Limit: >= 1]
|
||||||
dtPolyRef* polys, int* polyCount, const int maxPolys) const;
|
|
||||||
|
|
||||||
// Finds path from start polygon to end polygon.
|
|
||||||
// If target polygon canno be reached through the navigation graph,
|
|
||||||
// the last node on the array is nearest node to the end polygon.
|
|
||||||
// Start end end positions are needed to calculate more accurate
|
|
||||||
// traversal cost at start end end polygons.
|
|
||||||
// Params:
|
|
||||||
// startRef - (in) ref to path start polygon.
|
|
||||||
// endRef - (in) ref to path end polygon.
|
|
||||||
// startPos[3] - (in) Path start location.
|
|
||||||
// endPos[3] - (in) Path end location.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// path - (out) array holding the search result.
|
|
||||||
// pathCount - (out) Number of polygons in search result array.
|
|
||||||
// maxPath - (in) The max number of polygons the path array can hold. Must be at least 1.
|
|
||||||
dtStatus findPath(dtPolyRef startRef, dtPolyRef endRef,
|
dtStatus findPath(dtPolyRef startRef, dtPolyRef endRef,
|
||||||
const float* startPos, const float* endPos,
|
const float* startPos, const float* endPos,
|
||||||
const dtQueryFilter* filter,
|
const dtQueryFilter* filter,
|
||||||
dtPolyRef* path, int* pathCount, const int maxPath) const;
|
dtPolyRef* path, int* pathCount, const int maxPath) const;
|
||||||
|
|
||||||
// Intializes sliced path find query.
|
/// Finds the straight path from the start to the end position within the polygon corridor.
|
||||||
// Note 1: calling any other dtNavMeshQuery method before calling findPathEnd()
|
/// @param[in] startPos Path start position. [(x, y, z)]
|
||||||
// may results in corrupted data!
|
/// @param[in] endPos Path end position. [(x, y, z)]
|
||||||
// Note 2: The pointer to filter is store, and used in subsequent
|
/// @param[in] path An array of polygon references that represent the path corridor.
|
||||||
// calls to updateSlicedFindPath().
|
/// @param[in] pathSize The number of polygons in the @p path array.
|
||||||
// Params:
|
/// @param[out] straightPath Points describing the straight path. [(x, y, z) * @p straightPathCount].
|
||||||
// startRef - (in) ref to path start polygon.
|
/// @param[out] straightPathFlags Flags describing each point. (See: #dtStraightPathFlags) [opt]
|
||||||
// endRef - (in) ref to path end polygon.
|
/// @param[out] straightPathRefs The reference id of the polygon that is being entered at each point. [opt]
|
||||||
// startPos[3] - (in) Path start location.
|
/// @param[out] straightPathCount The number of points in the straight path.
|
||||||
// endPos[3] - (in) Path end location.
|
/// @param[in] maxStraightPath The maximum number of points the straight path arrays can hold. [Limit: > 0]
|
||||||
// filter - (in) path polygon filter.
|
/// @param[in] options Query options. (see: #dtStraightPathOptions)
|
||||||
dtStatus initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef,
|
/// @returns The status flags for the query.
|
||||||
const float* startPos, const float* endPos,
|
|
||||||
const dtQueryFilter* filter);
|
|
||||||
|
|
||||||
// Updates sliced path find query.
|
|
||||||
// Params:
|
|
||||||
// maxIter - (in) max number of iterations to update.
|
|
||||||
// Returns: Path query state.
|
|
||||||
dtStatus updateSlicedFindPath(const int maxIter);
|
|
||||||
|
|
||||||
// Finalizes sliced path find query and returns found path.
|
|
||||||
// path - (out) array holding the search result.
|
|
||||||
// pathCount - (out) Number of polygons in search result array.
|
|
||||||
// maxPath - (in) The max number of polygons the path array can hold.
|
|
||||||
dtStatus finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath);
|
|
||||||
|
|
||||||
// Finalizes partial sliced path find query and returns path to the furthest
|
|
||||||
// polygon on the existing path that was visited during the search.
|
|
||||||
// existing - (out) Array of polygons in the existing path.
|
|
||||||
// existingSize - (out) Number of polygons in existing path array.
|
|
||||||
// path - (out) array holding the search result.
|
|
||||||
// pathCount - (out) Number of polygons in search result array.
|
|
||||||
// maxPath - (in) The max number of polygons the path array can hold.
|
|
||||||
dtStatus finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize,
|
|
||||||
dtPolyRef* path, int* pathCount, const int maxPath);
|
|
||||||
|
|
||||||
// Finds a straight path from start to end locations within the corridor
|
|
||||||
// described by the path polygons.
|
|
||||||
// Start and end locations will be clamped on the corridor.
|
|
||||||
// The returned polygon references are point to polygon which was entered when
|
|
||||||
// a path point was added. For the end point, zero will be returned. This allows
|
|
||||||
// to match for example off-mesh link points to their representative polygons.
|
|
||||||
// Params:
|
|
||||||
// startPos[3] - (in) Path start location.
|
|
||||||
// endPo[3] - (in) Path end location.
|
|
||||||
// path - (in) Array of connected polygons describing the corridor.
|
|
||||||
// pathSize - (in) Number of polygons in path array.
|
|
||||||
// straightPath - (out) Points describing the straight path.
|
|
||||||
// straightPathFlags - (out, opt) Flags describing each point type, see dtStraightPathFlags.
|
|
||||||
// straightPathRefs - (out, opt) References to polygons at point locations.
|
|
||||||
// straightPathCount - (out) Number of points in the path.
|
|
||||||
// maxStraightPath - (in) The max number of points the straight path array can hold. Must be at least 1.
|
|
||||||
dtStatus findStraightPath(const float* startPos, const float* endPos,
|
dtStatus findStraightPath(const float* startPos, const float* endPos,
|
||||||
const dtPolyRef* path, const int pathSize,
|
const dtPolyRef* path, const int pathSize,
|
||||||
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
||||||
int* straightPathCount, const int maxStraightPath) const;
|
int* straightPathCount, const int maxStraightPath, const int options = 0) const;
|
||||||
|
|
||||||
// Moves from startPos to endPos constrained to the navmesh.
|
///@}
|
||||||
// If the endPos is reachable, the resultPos will be endPos,
|
/// @name Sliced Pathfinding Functions
|
||||||
// or else the resultPos will be the nearest point in navmesh.
|
/// Common use case:
|
||||||
// Note: The resulting point is not projected to the ground, use getPolyHeight() to get height.
|
/// -# Call initSlicedFindPath() to initialize the sliced path query.
|
||||||
// Note: The algorithm is optimized for small delta movement and small number of polygons.
|
/// -# Call updateSlicedFindPath() until it returns complete.
|
||||||
// Params:
|
/// -# Call finalizeSlicedFindPath() to get the path.
|
||||||
// startRef - (in) ref to the polygon where startPos lies.
|
///@{
|
||||||
// startPos[3] - (in) start position of the mover.
|
|
||||||
// endPos[3] - (in) desired end position of the mover.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// resultPos[3] - (out) new position of the mover.
|
|
||||||
// visited - (out) array of visited polygons.
|
|
||||||
// visitedCount - (out) Number of entries in the visited array.
|
|
||||||
// maxVisitedSize - (in) max number of polygons in the visited array.
|
|
||||||
dtStatus moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
float* resultPos, dtPolyRef* visited, int* visitedCount, const int maxVisitedSize) const;
|
|
||||||
|
|
||||||
// Casts 'walkability' ray along the navmesh surface from startPos towards the endPos.
|
/// Intializes a sliced path query.
|
||||||
// Params:
|
/// @param[in] startRef The refrence id of the start polygon.
|
||||||
// startRef - (in) ref to the polygon where the start lies.
|
/// @param[in] endRef The reference id of the end polygon.
|
||||||
// startPos[3] - (in) start position of the query.
|
/// @param[in] startPos A position within the start polygon. [(x, y, z)]
|
||||||
// endPos[3] - (in) end position of the query.
|
/// @param[in] endPos A position within the end polygon. [(x, y, z)]
|
||||||
// t - (out) hit parameter along the segment, FLT_MAX if no hit.
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
// hitNormal[3] - (out) normal of the nearest hit.
|
/// @param[in] options query options (see: #dtFindPathOptions)
|
||||||
// filter - (in) path polygon filter.
|
/// @returns The status flags for the query.
|
||||||
// path - (out,opt) visited path polygons.
|
dtStatus initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef,
|
||||||
// pathCount - (out,opt) Number of polygons visited.
|
const float* startPos, const float* endPos,
|
||||||
// maxPath - (in) max number of polygons in the path array.
|
const dtQueryFilter* filter, const unsigned int options = 0);
|
||||||
dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
float* t, float* hitNormal, dtPolyRef* path, int* pathCount, const int maxPath) const;
|
|
||||||
|
|
||||||
// Returns distance to nearest wall from the specified location.
|
/// Updates an in-progress sliced path query.
|
||||||
// Params:
|
/// @param[in] maxIter The maximum number of iterations to perform.
|
||||||
// startRef - (in) ref to the polygon where the center lies.
|
/// @param[out] doneIters The actual number of iterations completed. [opt]
|
||||||
// centerPos[3] - (in) center if the query circle.
|
/// @returns The status flags for the query.
|
||||||
// maxRadius - (in) max search radius.
|
dtStatus updateSlicedFindPath(const int maxIter, int* doneIters);
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// hitDist - (out) distance to nearest wall from the test location.
|
|
||||||
// hitPos[3] - (out) location of the nearest hit.
|
|
||||||
// hitNormal[3] - (out) normal of the nearest hit.
|
|
||||||
dtStatus findDistanceToWall(dtPolyRef startRef, const float* centerPos, const float maxRadius,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
float* hitDist, float* hitPos, float* hitNormal) const;
|
|
||||||
|
|
||||||
// Finds polygons found along the navigation graph which touch the specified circle.
|
/// Finalizes and returns the results of a sliced path query.
|
||||||
// Params:
|
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||||
// startRef - (in) ref to the polygon where the search starts.
|
/// [(polyRef) * @p pathCount]
|
||||||
// centerPos[3] - (in) center if the query circle.
|
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||||
// radius - (in) radius of the query circle.
|
/// @param[in] maxPath The max number of polygons the path array can hold. [Limit: >= 1]
|
||||||
// filter - (in) path polygon filter.
|
/// @returns The status flags for the query.
|
||||||
// resultRef - (out, opt) refs to the polygons touched by the circle.
|
dtStatus finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath);
|
||||||
// resultParent - (out, opt) parent of each result polygon.
|
|
||||||
// resultCost - (out, opt) search cost at each result polygon.
|
/// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest
|
||||||
// resultCount - (out, opt) Number of results.
|
/// polygon on the existing path that was visited during the search.
|
||||||
// maxResult - (int) maximum capacity of search results.
|
/// @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.)
|
||||||
|
/// [(polyRef) * @p pathCount]
|
||||||
|
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||||
|
/// @param[in] maxPath The max number of polygons the @p path array can hold. [Limit: >= 1]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize,
|
||||||
|
dtPolyRef* path, int* pathCount, const int maxPath);
|
||||||
|
|
||||||
|
///@}
|
||||||
|
/// @name Dijkstra Search Functions
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Finds the polygons along the navigation graph that touch the specified circle.
|
||||||
|
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||||
|
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
||||||
|
/// @param[in] radius The radius of the search circle.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] resultRef The reference ids of the polygons touched by the circle. [opt]
|
||||||
|
/// @param[out] resultParent The reference ids of the parent polygons for each result.
|
||||||
|
/// Zero if a result polygon has no parent. [opt]
|
||||||
|
/// @param[out] resultCost The search cost from @p centerPos to the polygon. [opt]
|
||||||
|
/// @param[out] resultCount The number of polygons found. [opt]
|
||||||
|
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
dtStatus findPolysAroundCircle(dtPolyRef startRef, const float* centerPos, const float radius,
|
dtStatus findPolysAroundCircle(dtPolyRef startRef, const float* centerPos, const float radius,
|
||||||
const dtQueryFilter* filter,
|
const dtQueryFilter* filter,
|
||||||
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
||||||
int* resultCount, const int maxResult) const;
|
int* resultCount, const int maxResult) const;
|
||||||
|
|
||||||
// Finds polygons found along the navigation graph which touch the convex polygon shape.
|
/// Finds the polygons along the naviation graph that touch the specified convex polygon.
|
||||||
// Params:
|
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||||
// startRef - (in) ref to the polygon where the search starts.
|
/// @param[in] verts The vertices describing the convex polygon. (CCW)
|
||||||
// verts[3*n] - (in) vertices describing convex polygon shape (CCW).
|
/// [(x, y, z) * @p nverts]
|
||||||
// nverts - (in) number of vertices in the polygon.
|
/// @param[in] nverts The number of vertices in the polygon.
|
||||||
// filter - (in) path polygon filter.
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
// resultRef - (out, opt) refs to the polygons touched by the circle.
|
/// @param[out] resultRef The reference ids of the polygons touched by the search polygon. [opt]
|
||||||
// resultParent - (out, opt) parent of each result polygon.
|
/// @param[out] resultParent The reference ids of the parent polygons for each result. Zero if a
|
||||||
// resultCost - (out, opt) search cost at each result polygon.
|
/// result polygon has no parent. [opt]
|
||||||
// resultCount - (out) number of results.
|
/// @param[out] resultCost The search cost from the centroid point to the polygon. [opt]
|
||||||
// maxResult - (int) maximum capacity of search results.
|
/// @param[out] resultCount The number of polygons found.
|
||||||
|
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
dtStatus findPolysAroundShape(dtPolyRef startRef, const float* verts, const int nverts,
|
dtStatus findPolysAroundShape(dtPolyRef startRef, const float* verts, const int nverts,
|
||||||
const dtQueryFilter* filter,
|
const dtQueryFilter* filter,
|
||||||
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
||||||
int* resultCount, const int maxResult) const;
|
int* resultCount, const int maxResult) const;
|
||||||
|
|
||||||
// Finds non-overlapping local neighbourhood around center location.
|
/// @}
|
||||||
// Note: The algorithm is optimized for small query radius and small number of polygons.
|
/// @name Local Query Functions
|
||||||
// Params:
|
///@{
|
||||||
// startRef - (in) ref to the polygon where the search starts.
|
|
||||||
// centerPos[3] - (in) center if the query circle.
|
/// Finds the polygon nearest to the specified center point.
|
||||||
// radius - (in) radius of the query circle.
|
/// @param[in] center The center of the search box. [(x, y, z)]
|
||||||
// filter - (in) path polygon filter.
|
/// @param[in] extents The search distance along each axis. [(x, y, z)]
|
||||||
// resultRef - (out) refs to the polygons touched by the circle.
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
// resultParent - (out, opt) parent of each result polygon.
|
/// @param[out] nearestRef The reference id of the nearest polygon.
|
||||||
// resultCount - (out) number of results.
|
/// @param[out] nearestPt The nearest point on the polygon. [opt] [(x, y, z)]
|
||||||
// maxResult - (int) maximum capacity of search results.
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findNearestPoly(const float* center, const float* extents,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* nearestRef, float* nearestPt) const;
|
||||||
|
|
||||||
|
/// Finds polygons that overlap the search box.
|
||||||
|
/// @param[in] center The center of the search box. [(x, y, z)]
|
||||||
|
/// @param[in] extents The search distance along each axis. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] polys The reference ids of the polygons that overlap the query box.
|
||||||
|
/// @param[out] polyCount The number of polygons in the search result.
|
||||||
|
/// @param[in] maxPolys The maximum number of polygons the search result can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus queryPolygons(const float* center, const float* extents,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* polys, int* polyCount, const int maxPolys) const;
|
||||||
|
|
||||||
|
/// Finds the non-overlapping navigation polygons in the local neighbourhood around the center position.
|
||||||
|
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||||
|
/// @param[in] centerPos The center of the query circle. [(x, y, z)]
|
||||||
|
/// @param[in] radius The radius of the query circle.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] resultRef The reference ids of the polygons touched by the circle.
|
||||||
|
/// @param[out] resultParent The reference ids of the parent polygons for each result.
|
||||||
|
/// Zero if a result polygon has no parent. [opt]
|
||||||
|
/// @param[out] resultCount The number of polygons found.
|
||||||
|
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
dtStatus findLocalNeighbourhood(dtPolyRef startRef, const float* centerPos, const float radius,
|
dtStatus findLocalNeighbourhood(dtPolyRef startRef, const float* centerPos, const float radius,
|
||||||
const dtQueryFilter* filter,
|
const dtQueryFilter* filter,
|
||||||
dtPolyRef* resultRef, dtPolyRef* resultParent,
|
dtPolyRef* resultRef, dtPolyRef* resultParent,
|
||||||
int* resultCount, const int maxResult) const;
|
int* resultCount, const int maxResult) const;
|
||||||
|
|
||||||
// Returns wall segments of specified polygon.
|
/// Moves from the start to the end position constrained to the navigation mesh.
|
||||||
// Params:
|
/// @param[in] startRef The reference id of the start polygon.
|
||||||
// ref - (in) ref to the polygon.
|
/// @param[in] startPos A position of the mover within the start polygon. [(x, y, x)]
|
||||||
// filter - (in) path polygon filter.
|
/// @param[in] endPos The desired end position of the mover. [(x, y, z)]
|
||||||
// segments[6*maxSegments] - (out) wall segments (2 endpoints per segment).
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
// segmentCount - (out) number of wall segments.
|
/// @param[out] resultPos The result position of the mover. [(x, y, z)]
|
||||||
// maxSegments - (in) max number of segments that can be stored in 'segments'.
|
/// @param[out] visited The reference ids of the polygons visited during the move.
|
||||||
|
/// @param[out] visitedCount The number of polygons visited during the move.
|
||||||
|
/// @param[in] maxVisitedSize The maximum number of polygons the @p visited array can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
float* resultPos, dtPolyRef* visited, int* visitedCount, const int maxVisitedSize) const;
|
||||||
|
|
||||||
|
/// Casts a 'walkability' ray along the surface of the navigation mesh from
|
||||||
|
/// the start position toward the end position.
|
||||||
|
/// @note A wrapper around raycast(..., RaycastHit*). Retained for backward compatibility.
|
||||||
|
/// @param[in] startRef The reference id of the start polygon.
|
||||||
|
/// @param[in] startPos A position within the start polygon representing
|
||||||
|
/// the start of the ray. [(x, y, z)]
|
||||||
|
/// @param[in] endPos The position to cast the ray toward. [(x, y, z)]
|
||||||
|
/// @param[out] t The hit parameter. (FLT_MAX if no wall hit.)
|
||||||
|
/// @param[out] hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] path The reference ids of the visited polygons. [opt]
|
||||||
|
/// @param[out] pathCount The number of visited polygons. [opt]
|
||||||
|
/// @param[in] maxPath The maximum number of polygons the @p path array can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
float* t, float* hitNormal, dtPolyRef* path, int* pathCount, const int maxPath) const;
|
||||||
|
|
||||||
|
/// Casts a 'walkability' ray along the surface of the navigation mesh from
|
||||||
|
/// the start position toward the end position.
|
||||||
|
/// @param[in] startRef The reference id of the start polygon.
|
||||||
|
/// @param[in] startPos A position within the start polygon representing
|
||||||
|
/// the start of the ray. [(x, y, z)]
|
||||||
|
/// @param[in] endPos The position to cast the ray toward. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[in] flags govern how the raycast behaves. See dtRaycastOptions
|
||||||
|
/// @param[out] hit Pointer to a raycast hit structure which will be filled by the results.
|
||||||
|
/// @param[in] prevRef parent of start ref. Used during for cost calculation [opt]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter, const unsigned int options,
|
||||||
|
dtRaycastHit* hit, dtPolyRef prevRef = 0) const;
|
||||||
|
|
||||||
|
|
||||||
|
/// Finds the distance from the specified position to the nearest polygon wall.
|
||||||
|
/// @param[in] startRef The reference id of the polygon containing @p centerPos.
|
||||||
|
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
||||||
|
/// @param[in] maxRadius The radius of the search circle.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] hitDist The distance to the nearest wall from @p centerPos.
|
||||||
|
/// @param[out] hitPos The nearest position on the wall that was hit. [(x, y, z)]
|
||||||
|
/// @param[out] hitNormal The normalized ray formed from the wall point to the
|
||||||
|
/// source point. [(x, y, z)]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findDistanceToWall(dtPolyRef startRef, const float* centerPos, const float maxRadius,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
float* hitDist, float* hitPos, float* hitNormal) const;
|
||||||
|
|
||||||
|
/// Returns the segments for the specified polygon, optionally including portals.
|
||||||
|
/// @param[in] ref The reference id of the polygon.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] segmentVerts The segments. [(ax, ay, az, bx, by, bz) * segmentCount]
|
||||||
|
/// @param[out] segmentRefs The reference ids of each segment's neighbor polygon.
|
||||||
|
/// Or zero if the segment is a wall. [opt] [(parentRef) * @p segmentCount]
|
||||||
|
/// @param[out] segmentCount The number of segments returned.
|
||||||
|
/// @param[in] maxSegments The maximum number of segments the result arrays can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
dtStatus getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter,
|
dtStatus getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter,
|
||||||
float* segments, int* segmentCount, const int maxSegments) const;
|
float* segmentVerts, dtPolyRef* segmentRefs, int* segmentCount,
|
||||||
|
const int maxSegments) const;
|
||||||
|
|
||||||
// Returns closest point on navigation polygon.
|
/// Returns random location on navmesh.
|
||||||
// Uses detail polygons to find the closest point to the navigation polygon surface.
|
/// Polygons are chosen weighted by area. The search runs in linear related to number of polygon.
|
||||||
// Params:
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
// ref - (in) ref to the polygon.
|
/// @param[in] frand Function returning a random number [0..1).
|
||||||
// pos[3] - (in) the point to check.
|
/// @param[out] randomRef The reference id of the random location.
|
||||||
// closest[3] - (out) closest point.
|
/// @param[out] randomPt The random location.
|
||||||
// Returns: true if closest point found.
|
/// @returns The status flags for the query.
|
||||||
dtStatus closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest) const;
|
dtStatus findRandomPoint(const dtQueryFilter* filter, float (*frand)(),
|
||||||
|
dtPolyRef* randomRef, float* randomPt) const;
|
||||||
|
|
||||||
// Returns closest point on navigation polygon boundary.
|
/// Returns random location on navmesh within the reach of specified location.
|
||||||
// Uses the navigation polygon boundary to snap the point to poly boundary
|
/// Polygons are chosen weighted by area. The search runs in linear related to number of polygon.
|
||||||
// if it is outside the polygon. Much faster than closestPointToPoly. Does not affect height.
|
/// The location is not exactly constrained by the circle, but it limits the visited polygons.
|
||||||
// Params:
|
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||||
// ref - (in) ref to the polygon.
|
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
||||||
// pos[3] - (in) the point to check.
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
// closest[3] - (out) closest point.
|
/// @param[in] frand Function returning a random number [0..1).
|
||||||
// Returns: true if closest point found.
|
/// @param[out] randomRef The reference id of the random location.
|
||||||
|
/// @param[out] randomPt The random location. [(x, y, z)]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findRandomPointAroundCircle(dtPolyRef startRef, const float* centerPos, const float maxRadius,
|
||||||
|
const dtQueryFilter* filter, float (*frand)(),
|
||||||
|
dtPolyRef* randomRef, float* randomPt) const;
|
||||||
|
|
||||||
|
/// Finds the closest point on the specified polygon.
|
||||||
|
/// @param[in] ref The reference id of the polygon.
|
||||||
|
/// @param[in] pos The position to check. [(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.
|
||||||
|
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
|
||||||
|
/// polygon's xz-bounds.
|
||||||
|
/// @param[in] ref The reference id to the polygon.
|
||||||
|
/// @param[in] pos The position to check. [(x, y, z)]
|
||||||
|
/// @param[out] closest The closest point. [(x, y, z)]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
dtStatus closestPointOnPolyBoundary(dtPolyRef ref, const float* pos, float* closest) const;
|
dtStatus closestPointOnPolyBoundary(dtPolyRef ref, const float* pos, float* closest) const;
|
||||||
|
|
||||||
// Returns start and end location of an off-mesh link polygon.
|
/// Gets the height of the polygon at the provided position using the height detail. (Most accurate.)
|
||||||
// Params:
|
/// @param[in] ref The reference id of the polygon.
|
||||||
// prevRef - (in) ref to the polygon before the link (used to select direction).
|
/// @param[in] pos A position within the xz-bounds of the polygon. [(x, y, z)]
|
||||||
// polyRef - (in) ref to the off-mesh link polygon.
|
/// @param[out] height The height at the surface of the polygon.
|
||||||
// startPos[3] - (out) start point of the link.
|
/// @returns The status flags for the query.
|
||||||
// endPos[3] - (out) end point of the link.
|
|
||||||
// Returns: true if link is found.
|
|
||||||
dtStatus getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, float* startPos, float* endPos) const;
|
|
||||||
|
|
||||||
// Returns height of the polygon at specified location.
|
|
||||||
// Params:
|
|
||||||
// ref - (in) ref to the polygon.
|
|
||||||
// pos[3] - (in) the point where to locate the height.
|
|
||||||
// height - (out) height at the location.
|
|
||||||
// Returns: true if over polygon.
|
|
||||||
dtStatus getPolyHeight(dtPolyRef ref, const float* pos, float* height) const;
|
dtStatus getPolyHeight(dtPolyRef ref, const float* pos, float* height) const;
|
||||||
|
|
||||||
// Returns true if poly reference ins in closed list.
|
/// @}
|
||||||
|
/// @name Miscellaneous Functions
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Returns true if the polygon reference is valid and passes the filter restrictions.
|
||||||
|
/// @param[in] ref The polygon reference to check.
|
||||||
|
/// @param[in] filter The filter to apply.
|
||||||
|
bool isValidPolyRef(dtPolyRef ref, const dtQueryFilter* filter) const;
|
||||||
|
|
||||||
|
/// Returns true if the polygon reference is in the closed list.
|
||||||
|
/// @param[in] ref The reference id of the polygon to check.
|
||||||
|
/// @returns True if the polygon is in closed list.
|
||||||
bool isInClosedList(dtPolyRef ref) const;
|
bool isInClosedList(dtPolyRef ref) const;
|
||||||
|
|
||||||
|
/// Gets the node pool.
|
||||||
|
/// @returns The node pool.
|
||||||
class dtNodePool* getNodePool() const { return m_nodePool; }
|
class dtNodePool* getNodePool() const { return m_nodePool; }
|
||||||
|
|
||||||
|
/// Gets the navigation mesh the query object is using.
|
||||||
|
/// @return The navigation mesh the query object is using.
|
||||||
|
const dtNavMesh* getAttachedNavMesh() const { return m_nav; }
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Returns neighbour tile based on side.
|
/// Returns neighbour tile based on side.
|
||||||
dtMeshTile* getNeighbourTileAt(int x, int y, int side) const;
|
dtMeshTile* getNeighbourTileAt(int x, int y, int side) const;
|
||||||
|
|
||||||
// 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.
|
|
||||||
dtStatus 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;
|
||||||
dtStatus getPortalPoints(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
dtStatus getPortalPoints(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
||||||
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
||||||
float* left, float* right) const;
|
float* left, float* right) const;
|
||||||
|
|
||||||
// Returns edge mid point between two polygons.
|
/// Returns edge mid point between two polygons.
|
||||||
dtStatus getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mid) const;
|
dtStatus getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mid) const;
|
||||||
dtStatus getEdgeMidPoint(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
dtStatus getEdgeMidPoint(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
||||||
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
||||||
float* mid) const;
|
float* mid) const;
|
||||||
|
|
||||||
const dtNavMesh* m_nav; // Pointer to navmesh data.
|
// Appends vertex to a straight path
|
||||||
|
dtStatus appendVertex(const float* pos, const unsigned char flags, const dtPolyRef ref,
|
||||||
|
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
||||||
|
int* straightPathCount, const int maxStraightPath) const;
|
||||||
|
|
||||||
|
// Appends intermediate portal points to a straight path.
|
||||||
|
dtStatus appendPortals(const int startIdx, const int endIdx, const float* endPos, const dtPolyRef* path,
|
||||||
|
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
||||||
|
int* straightPathCount, const int maxStraightPath, const int options) const;
|
||||||
|
|
||||||
|
const dtNavMesh* m_nav; ///< Pointer to navmesh data.
|
||||||
|
|
||||||
struct dtQueryData
|
struct dtQueryData
|
||||||
{
|
{
|
||||||
|
|
@ -392,16 +513,24 @@ private:
|
||||||
dtPolyRef startRef, endRef;
|
dtPolyRef startRef, endRef;
|
||||||
float startPos[3], endPos[3];
|
float startPos[3], endPos[3];
|
||||||
const dtQueryFilter* filter;
|
const dtQueryFilter* filter;
|
||||||
|
unsigned int options;
|
||||||
|
float raycastLimitSqr;
|
||||||
};
|
};
|
||||||
dtQueryData m_query; // Sliced query state.
|
dtQueryData m_query; ///< Sliced query state.
|
||||||
|
|
||||||
class dtNodePool* m_tinyNodePool; // Pointer to small node pool.
|
class dtNodePool* m_tinyNodePool; ///< Pointer to small node pool.
|
||||||
class dtNodePool* m_nodePool; // Pointer to node pool.
|
class dtNodePool* m_nodePool; ///< Pointer to node pool.
|
||||||
class dtNodeQueue* m_openList; // Pointer to open list queue.
|
class dtNodeQueue* m_openList; ///< Pointer to open list queue.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to allocate navmesh query class using Detour allocator.
|
/// Allocates a query object using the Detour allocator.
|
||||||
|
/// @return An allocated query object, or null on failure.
|
||||||
|
/// @ingroup detour
|
||||||
dtNavMeshQuery* dtAllocNavMeshQuery();
|
dtNavMeshQuery* dtAllocNavMeshQuery();
|
||||||
|
|
||||||
|
/// Frees the specified query object using the Detour allocator.
|
||||||
|
/// @param[in] query A query object allocated using #dtAllocNavMeshQuery
|
||||||
|
/// @ingroup detour
|
||||||
void dtFreeNavMeshQuery(dtNavMeshQuery* query);
|
void dtFreeNavMeshQuery(dtNavMeshQuery* query);
|
||||||
|
|
||||||
#endif // DETOURNAVMESHQUERY_H
|
#endif // DETOURNAVMESHQUERY_H
|
||||||
|
|
|
||||||
|
|
@ -25,20 +25,28 @@ enum dtNodeFlags
|
||||||
{
|
{
|
||||||
DT_NODE_OPEN = 0x01,
|
DT_NODE_OPEN = 0x01,
|
||||||
DT_NODE_CLOSED = 0x02,
|
DT_NODE_CLOSED = 0x02,
|
||||||
|
DT_NODE_PARENT_DETACHED = 0x04, // parent of the node is not adjacent. Found using raycast.
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned short DT_NULL_IDX = 0xffff;
|
typedef unsigned short dtNodeIndex;
|
||||||
|
static const dtNodeIndex DT_NULL_IDX = (dtNodeIndex)~0;
|
||||||
|
|
||||||
struct dtNode
|
struct dtNode
|
||||||
{
|
{
|
||||||
float pos[3]; // Position of the node.
|
float pos[3]; ///< Position of the node.
|
||||||
float cost; // Cost from previous node to current node.
|
float cost; ///< Cost from previous node to current node.
|
||||||
float total; // Cost up to the node.
|
float total; ///< Cost up to the node.
|
||||||
unsigned int pidx : 30; // Index to parent node.
|
unsigned int pidx : 24; ///< Index to parent node.
|
||||||
unsigned int flags : 2; // Node flags 0/open/closed.
|
unsigned int state : 2; ///< extra state information. A polyRef can have multiple nodes with different extra info. see DT_MAX_STATES_PER_NODE
|
||||||
dtPolyRef id; // Polygon ref the node corresponds to.
|
unsigned int flags : 3; ///< Node flags. A combination of dtNodeFlags.
|
||||||
|
dtPolyRef id; ///< Polygon ref the node corresponds to.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const int DT_MAX_STATES_PER_NODE = 4; // number of extra states per node. See dtNode::state
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class dtNodePool
|
class dtNodePool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -46,8 +54,12 @@ public:
|
||||||
~dtNodePool();
|
~dtNodePool();
|
||||||
inline void operator=(const dtNodePool&) {}
|
inline void operator=(const dtNodePool&) {}
|
||||||
void clear();
|
void clear();
|
||||||
dtNode* getNode(dtPolyRef id);
|
|
||||||
dtNode* findNode(dtPolyRef id);
|
// Get a dtNode by ref and extra state information. If there is none then - allocate
|
||||||
|
// There can be more than one node for the same polyRef but with different extra state information
|
||||||
|
dtNode* getNode(dtPolyRef id, unsigned char state=0);
|
||||||
|
dtNode* findNode(dtPolyRef id, unsigned char state);
|
||||||
|
unsigned int findNodes(dtPolyRef id, dtNode** nodes, const int maxNodes);
|
||||||
|
|
||||||
inline unsigned int getNodeIdx(const dtNode* node) const
|
inline unsigned int getNodeIdx(const dtNode* node) const
|
||||||
{
|
{
|
||||||
|
|
@ -71,21 +83,22 @@ public:
|
||||||
{
|
{
|
||||||
return sizeof(*this) +
|
return sizeof(*this) +
|
||||||
sizeof(dtNode)*m_maxNodes +
|
sizeof(dtNode)*m_maxNodes +
|
||||||
sizeof(unsigned short)*m_maxNodes +
|
sizeof(dtNodeIndex)*m_maxNodes +
|
||||||
sizeof(unsigned short)*m_hashSize;
|
sizeof(dtNodeIndex)*m_hashSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int getMaxNodes() const { return m_maxNodes; }
|
inline int getMaxNodes() const { return m_maxNodes; }
|
||||||
|
|
||||||
inline int getHashSize() const { return m_hashSize; }
|
inline int getHashSize() const { return m_hashSize; }
|
||||||
inline unsigned short getFirst(int bucket) const { return m_first[bucket]; }
|
inline dtNodeIndex getFirst(int bucket) const { return m_first[bucket]; }
|
||||||
inline unsigned short getNext(int i) const { return m_next[i]; }
|
inline dtNodeIndex getNext(int i) const { return m_next[i]; }
|
||||||
|
inline int getNodeCount() const { return m_nodeCount; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
dtNode* m_nodes;
|
dtNode* m_nodes;
|
||||||
unsigned short* m_first;
|
dtNodeIndex* m_first;
|
||||||
unsigned short* m_next;
|
dtNodeIndex* m_next;
|
||||||
const int m_maxNodes;
|
const int m_maxNodes;
|
||||||
const int m_hashSize;
|
const int m_hashSize;
|
||||||
int m_nodeCount;
|
int m_nodeCount;
|
||||||
|
|
|
||||||
64
dep/recastnavigation/Detour/Include/DetourStatus.h
Normal file
64
dep/recastnavigation/Detour/Include/DetourStatus.h
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURSTATUS_H
|
||||||
|
#define DETOURSTATUS_H
|
||||||
|
|
||||||
|
typedef unsigned int dtStatus;
|
||||||
|
|
||||||
|
// High level status.
|
||||||
|
static const unsigned int DT_FAILURE = 1u << 31; // Operation failed.
|
||||||
|
static const unsigned int DT_SUCCESS = 1u << 30; // Operation succeed.
|
||||||
|
static const unsigned int DT_IN_PROGRESS = 1u << 29; // Operation still in progress.
|
||||||
|
|
||||||
|
// Detail information for status.
|
||||||
|
static const unsigned int DT_STATUS_DETAIL_MASK = 0x0ffffff;
|
||||||
|
static const unsigned int DT_WRONG_MAGIC = 1 << 0; // Input data is not recognized.
|
||||||
|
static const unsigned int DT_WRONG_VERSION = 1 << 1; // Input data is in wrong version.
|
||||||
|
static const unsigned int DT_OUT_OF_MEMORY = 1 << 2; // Operation ran out of memory.
|
||||||
|
static const unsigned int DT_INVALID_PARAM = 1 << 3; // An input parameter was invalid.
|
||||||
|
static const unsigned int DT_BUFFER_TOO_SMALL = 1 << 4; // Result buffer for the query was too small to store all results.
|
||||||
|
static const unsigned int DT_OUT_OF_NODES = 1 << 5; // Query ran out of nodes during search.
|
||||||
|
static const unsigned int DT_PARTIAL_RESULT = 1 << 6; // Query did not reach the end location, returning best guess.
|
||||||
|
|
||||||
|
|
||||||
|
// Returns true of status is success.
|
||||||
|
inline bool dtStatusSucceed(dtStatus status)
|
||||||
|
{
|
||||||
|
return (status & DT_SUCCESS) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true of status is failure.
|
||||||
|
inline bool dtStatusFailed(dtStatus status)
|
||||||
|
{
|
||||||
|
return (status & DT_FAILURE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true of status is in progress.
|
||||||
|
inline bool dtStatusInProgress(dtStatus status)
|
||||||
|
{
|
||||||
|
return (status & DT_IN_PROGRESS) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if specific detail is set.
|
||||||
|
inline bool dtStatusDetail(dtStatus status, unsigned int detail)
|
||||||
|
{
|
||||||
|
return (status & detail) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DETOURSTATUS_H
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
|
# MaNGOS is a full featured server for World of Warcraft, supporting
|
||||||
|
# the following clients: 1.12.x, 2.4.3, 3.2.5a, 4.2.3 and 5.4.8
|
||||||
|
# Copyright (C) 2005-2014 MaNGOS project <http://getmangos.eu>
|
||||||
#
|
#
|
||||||
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
|
@ -13,6 +16,14 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
# ***** END GPL LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
# World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||||
|
# and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||||
|
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
|
||||||
|
#
|
||||||
|
|
||||||
|
add_definitions(-DDT_POLYREF64)
|
||||||
|
|
||||||
set(detour_SRCS
|
set(detour_SRCS
|
||||||
DetourAlloc.cpp
|
DetourAlloc.cpp
|
||||||
|
|
@ -21,7 +32,6 @@ set(detour_SRCS
|
||||||
DetourNavMesh.cpp
|
DetourNavMesh.cpp
|
||||||
DetourNavMeshQuery.cpp
|
DetourNavMeshQuery.cpp
|
||||||
DetourNode.cpp
|
DetourNode.cpp
|
||||||
DetourObstacleAvoidance.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
@ -238,6 +238,9 @@ bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// All points are projected onto the xz-plane, so the y-values are ignored.
|
||||||
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts)
|
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts)
|
||||||
{
|
{
|
||||||
// TODO: Replace pnpoly with triArea2D tests?
|
// TODO: Replace pnpoly with triArea2D tests?
|
||||||
|
|
@ -291,6 +294,9 @@ inline bool overlapRange(const float amin, const float amax,
|
||||||
return ((amin+eps) > bmax || (amax-eps) < bmin) ? false : true;
|
return ((amin+eps) > bmax || (amax-eps) < bmin) ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// All vertices are projected onto the xz-plane, so the y-values are ignored.
|
||||||
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
||||||
const float* polyb, const int npolyb)
|
const float* polyb, const int npolyb)
|
||||||
{
|
{
|
||||||
|
|
@ -327,3 +333,61 @@ bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a random point in a convex polygon.
|
||||||
|
// Adapted from Graphics Gems article.
|
||||||
|
void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
|
||||||
|
const float s, const float t, float* out)
|
||||||
|
{
|
||||||
|
// Calc triangle araes
|
||||||
|
float areasum = 0.0f;
|
||||||
|
for (int i = 2; i < npts; i++) {
|
||||||
|
areas[i] = dtTriArea2D(&pts[0], &pts[(i-1)*3], &pts[i*3]);
|
||||||
|
areasum += dtMax(0.001f, areas[i]);
|
||||||
|
}
|
||||||
|
// Find sub triangle weighted by area.
|
||||||
|
const float thr = s*areasum;
|
||||||
|
float acc = 0.0f;
|
||||||
|
float u = 0.0f;
|
||||||
|
int tri = 0;
|
||||||
|
for (int i = 2; i < npts; i++) {
|
||||||
|
const float dacc = areas[i];
|
||||||
|
if (thr >= acc && thr < (acc+dacc))
|
||||||
|
{
|
||||||
|
u = (thr - acc) / dacc;
|
||||||
|
tri = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
acc += dacc;
|
||||||
|
}
|
||||||
|
|
||||||
|
float v = dtSqrt(t);
|
||||||
|
|
||||||
|
const float a = 1 - v;
|
||||||
|
const float b = (1 - u) * v;
|
||||||
|
const float c = u * v;
|
||||||
|
const float* pa = &pts[0];
|
||||||
|
const float* pb = &pts[(tri-1)*3];
|
||||||
|
const float* pc = &pts[tri*3];
|
||||||
|
|
||||||
|
out[0] = a*pa[0] + b*pb[0] + c*pc[0];
|
||||||
|
out[1] = a*pa[1] + b*pb[1] + c*pc[1];
|
||||||
|
out[2] = a*pa[2] + b*pb[2] + c*pc[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float vperpXZ(const float* a, const float* b) { return a[0]*b[2] - a[2]*b[0]; }
|
||||||
|
|
||||||
|
bool dtIntersectSegSeg2D(const float* ap, const float* aq,
|
||||||
|
const float* bp, const float* bq,
|
||||||
|
float& s, float& t)
|
||||||
|
{
|
||||||
|
float u[3], v[3], w[3];
|
||||||
|
dtVsub(u,aq,ap);
|
||||||
|
dtVsub(v,bq,bp);
|
||||||
|
dtVsub(w,ap,bp);
|
||||||
|
float d = vperpXZ(u,v);
|
||||||
|
if (fabsf(d) < 1e-6f) return false;
|
||||||
|
s = vperpXZ(v,w) / d;
|
||||||
|
t = vperpXZ(u,w) / d;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -16,12 +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 "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"
|
||||||
|
|
@ -201,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.bmin[1] = (unsigned short)dtMathFloorf((float)it.bmin[1]*ch/cs);
|
||||||
it.bmax[1] = (unsigned short)ceilf((float)it.bmax[1]*ch/cs);
|
it.bmax[1] = (unsigned short)dtMathCeilf((float)it.bmax[1]*ch/cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int curNode = 0;
|
int curNode = 0;
|
||||||
|
|
@ -237,11 +238,19 @@ static unsigned char classifyOffMeshPoint(const float* pt, const float* bmin, co
|
||||||
case ZM: return 6;
|
case ZM: return 6;
|
||||||
case XP|ZM: return 7;
|
case XP|ZM: return 7;
|
||||||
};
|
};
|
||||||
|
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Better error handling.
|
// TODO: Better error handling.
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// The output data array is allocated using the detour allocator (dtAlloc()). The method
|
||||||
|
/// used to free the memory will be determined by how the tile is added to the navigation
|
||||||
|
/// mesh.
|
||||||
|
///
|
||||||
|
/// @see dtNavMesh, dtNavMesh::addTile()
|
||||||
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize)
|
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize)
|
||||||
{
|
{
|
||||||
if (params->nvp > DT_VERTS_PER_POLYGON)
|
if (params->nvp > DT_VERTS_PER_POLYGON)
|
||||||
|
|
@ -252,8 +261,6 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||||
return false;
|
return false;
|
||||||
if (!params->polyCount || !params->polys)
|
if (!params->polyCount || !params->polys)
|
||||||
return false;
|
return false;
|
||||||
if (!params->detailMeshes || !params->detailVerts || !params->detailTris)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const int nvp = params->nvp;
|
const int nvp = params->nvp;
|
||||||
|
|
||||||
|
|
@ -269,10 +276,50 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||||
if (!offMeshConClass)
|
if (!offMeshConClass)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Find tight heigh bounds, used for culling out off-mesh start locations.
|
||||||
|
float hmin = FLT_MAX;
|
||||||
|
float hmax = -FLT_MAX;
|
||||||
|
|
||||||
|
if (params->detailVerts && params->detailVertsCount)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < params->detailVertsCount; ++i)
|
||||||
|
{
|
||||||
|
const float h = params->detailVerts[i*3+1];
|
||||||
|
hmin = dtMin(hmin,h);
|
||||||
|
hmax = dtMax(hmax,h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < params->vertCount; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* iv = ¶ms->verts[i*3];
|
||||||
|
const float h = params->bmin[1] + iv[1] * params->ch;
|
||||||
|
hmin = dtMin(hmin,h);
|
||||||
|
hmax = dtMax(hmax,h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hmin -= params->walkableClimb;
|
||||||
|
hmax += params->walkableClimb;
|
||||||
|
float bmin[3], bmax[3];
|
||||||
|
dtVcopy(bmin, params->bmin);
|
||||||
|
dtVcopy(bmax, params->bmax);
|
||||||
|
bmin[1] = hmin;
|
||||||
|
bmax[1] = hmax;
|
||||||
|
|
||||||
for (int i = 0; i < params->offMeshConCount; ++i)
|
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||||
{
|
{
|
||||||
offMeshConClass[i*2+0] = classifyOffMeshPoint(¶ms->offMeshConVerts[(i*2+0)*3], params->bmin, params->bmax);
|
const float* p0 = ¶ms->offMeshConVerts[(i*2+0)*3];
|
||||||
offMeshConClass[i*2+1] = classifyOffMeshPoint(¶ms->offMeshConVerts[(i*2+1)*3], params->bmin, params->bmax);
|
const float* p1 = ¶ms->offMeshConVerts[(i*2+1)*3];
|
||||||
|
offMeshConClass[i*2+0] = classifyOffMeshPoint(p0, bmin, bmax);
|
||||||
|
offMeshConClass[i*2+1] = classifyOffMeshPoint(p1, bmin, bmax);
|
||||||
|
|
||||||
|
// Zero out off-mesh start positions which are not even potentially touching the mesh.
|
||||||
|
if (offMeshConClass[i*2+0] == 0xff)
|
||||||
|
{
|
||||||
|
if (p0[1] < bmin[1] || p0[1] > bmax[1])
|
||||||
|
offMeshConClass[i*2+0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Cound how many links should be allocated for off-mesh connections.
|
// Cound how many links should be allocated for off-mesh connections.
|
||||||
if (offMeshConClass[i*2+0] == 0xff)
|
if (offMeshConClass[i*2+0] == 0xff)
|
||||||
|
|
@ -298,23 +345,13 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||||
for (int j = 0; j < nvp; ++j)
|
for (int j = 0; j < nvp; ++j)
|
||||||
{
|
{
|
||||||
if (p[j] == MESH_NULL_IDX) break;
|
if (p[j] == MESH_NULL_IDX) break;
|
||||||
int nj = j+1;
|
|
||||||
if (nj >= nvp || p[nj] == MESH_NULL_IDX) nj = 0;
|
|
||||||
const unsigned short* va = ¶ms->verts[p[j]*3];
|
|
||||||
const unsigned short* vb = ¶ms->verts[p[nj]*3];
|
|
||||||
|
|
||||||
edgeCount++;
|
edgeCount++;
|
||||||
|
|
||||||
if (params->tileSize > 0)
|
if (p[nvp+j] & 0x8000)
|
||||||
{
|
{
|
||||||
if (va[0] == params->tileSize && vb[0] == params->tileSize)
|
unsigned short dir = p[nvp+j] & 0xf;
|
||||||
portalCount++; // x+
|
if (dir != 0xf)
|
||||||
else if (va[2] == params->tileSize && vb[2] == params->tileSize)
|
portalCount++;
|
||||||
portalCount++; // z+
|
|
||||||
else if (va[0] == 0 && vb[0] == 0)
|
|
||||||
portalCount++; // x-
|
|
||||||
else if (va[2] == 0 && vb[2] == 0)
|
|
||||||
portalCount++; // z-
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -323,6 +360,11 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||||
|
|
||||||
// Find unique detail vertices.
|
// Find unique detail vertices.
|
||||||
int uniqueDetailVertCount = 0;
|
int uniqueDetailVertCount = 0;
|
||||||
|
int detailTriCount = 0;
|
||||||
|
if (params->detailMeshes)
|
||||||
|
{
|
||||||
|
// Has detail mesh, count unique detail vertex count and use input detail tri count.
|
||||||
|
detailTriCount = params->detailTriCount;
|
||||||
for (int i = 0; i < params->polyCount; ++i)
|
for (int i = 0; i < params->polyCount; ++i)
|
||||||
{
|
{
|
||||||
const unsigned short* p = ¶ms->polys[i*nvp*2];
|
const unsigned short* p = ¶ms->polys[i*nvp*2];
|
||||||
|
|
@ -336,6 +378,24 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||||
ndv -= nv;
|
ndv -= nv;
|
||||||
uniqueDetailVertCount += ndv;
|
uniqueDetailVertCount += ndv;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No input detail mesh, build detail mesh from nav polys.
|
||||||
|
uniqueDetailVertCount = 0; // No extra detail verts.
|
||||||
|
detailTriCount = 0;
|
||||||
|
for (int i = 0; i < params->polyCount; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* p = ¶ms->polys[i*nvp*2];
|
||||||
|
int nv = 0;
|
||||||
|
for (int j = 0; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == MESH_NULL_IDX) break;
|
||||||
|
nv++;
|
||||||
|
}
|
||||||
|
detailTriCount += nv-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate data size
|
// Calculate data size
|
||||||
const int headerSize = dtAlign4(sizeof(dtMeshHeader));
|
const int headerSize = dtAlign4(sizeof(dtMeshHeader));
|
||||||
|
|
@ -344,8 +404,8 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||||
const int linksSize = dtAlign4(sizeof(dtLink)*maxLinkCount);
|
const int linksSize = dtAlign4(sizeof(dtLink)*maxLinkCount);
|
||||||
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail)*params->polyCount);
|
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail)*params->polyCount);
|
||||||
const int detailVertsSize = dtAlign4(sizeof(float)*3*uniqueDetailVertCount);
|
const int detailVertsSize = dtAlign4(sizeof(float)*3*uniqueDetailVertCount);
|
||||||
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*params->detailTriCount);
|
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*detailTriCount);
|
||||||
const int bvTreeSize = dtAlign4(sizeof(dtBVNode)*params->polyCount*2);
|
const int bvTreeSize = params->buildBvTree ? dtAlign4(sizeof(dtBVNode)*params->polyCount*2) : 0;
|
||||||
const int offMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection)*storedOffMeshConCount);
|
const int offMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection)*storedOffMeshConCount);
|
||||||
|
|
||||||
const int dataSize = headerSize + vertsSize + polysSize + linksSize +
|
const int dataSize = headerSize + vertsSize + polysSize + linksSize +
|
||||||
|
|
@ -377,6 +437,7 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||||
header->version = DT_NAVMESH_VERSION;
|
header->version = DT_NAVMESH_VERSION;
|
||||||
header->x = params->tileX;
|
header->x = params->tileX;
|
||||||
header->y = params->tileY;
|
header->y = params->tileY;
|
||||||
|
header->layer = params->tileLayer;
|
||||||
header->userId = params->userId;
|
header->userId = params->userId;
|
||||||
header->polyCount = totPolyCount;
|
header->polyCount = totPolyCount;
|
||||||
header->vertCount = totVertCount;
|
header->vertCount = totVertCount;
|
||||||
|
|
@ -385,14 +446,14 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||||
dtVcopy(header->bmax, params->bmax);
|
dtVcopy(header->bmax, params->bmax);
|
||||||
header->detailMeshCount = params->polyCount;
|
header->detailMeshCount = params->polyCount;
|
||||||
header->detailVertCount = uniqueDetailVertCount;
|
header->detailVertCount = uniqueDetailVertCount;
|
||||||
header->detailTriCount = params->detailTriCount;
|
header->detailTriCount = detailTriCount;
|
||||||
header->bvQuantFactor = 1.0f / params->cs;
|
header->bvQuantFactor = 1.0f / params->cs;
|
||||||
header->offMeshBase = params->polyCount;
|
header->offMeshBase = params->polyCount;
|
||||||
header->walkableHeight = params->walkableHeight;
|
header->walkableHeight = params->walkableHeight;
|
||||||
header->walkableRadius = params->walkableRadius;
|
header->walkableRadius = params->walkableRadius;
|
||||||
header->walkableClimb = params->walkableClimb;
|
header->walkableClimb = params->walkableClimb;
|
||||||
header->offMeshConCount = storedOffMeshConCount;
|
header->offMeshConCount = storedOffMeshConCount;
|
||||||
header->bvNodeCount = params->polyCount*2;
|
header->bvNodeCount = params->buildBvTree ? params->polyCount*2 : 0;
|
||||||
|
|
||||||
const int offMeshVertsBase = params->vertCount;
|
const int offMeshVertsBase = params->vertCount;
|
||||||
const int offMeshPolyBase = params->polyCount;
|
const int offMeshPolyBase = params->polyCount;
|
||||||
|
|
@ -436,7 +497,27 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||||
{
|
{
|
||||||
if (src[j] == MESH_NULL_IDX) break;
|
if (src[j] == MESH_NULL_IDX) break;
|
||||||
p->verts[j] = src[j];
|
p->verts[j] = src[j];
|
||||||
p->neis[j] = (src[nvp+j]+1) & 0xffff;
|
if (src[nvp+j] & 0x8000)
|
||||||
|
{
|
||||||
|
// Border or portal edge.
|
||||||
|
unsigned short dir = src[nvp+j] & 0xf;
|
||||||
|
if (dir == 0xf) // Border
|
||||||
|
p->neis[j] = 0;
|
||||||
|
else if (dir == 0) // Portal x-
|
||||||
|
p->neis[j] = DT_EXT_LINK | 4;
|
||||||
|
else if (dir == 1) // Portal z+
|
||||||
|
p->neis[j] = DT_EXT_LINK | 2;
|
||||||
|
else if (dir == 2) // Portal x+
|
||||||
|
p->neis[j] = DT_EXT_LINK | 0;
|
||||||
|
else if (dir == 3) // Portal z-
|
||||||
|
p->neis[j] = DT_EXT_LINK | 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Normal connection
|
||||||
|
p->neis[j] = src[nvp+j]+1;
|
||||||
|
}
|
||||||
|
|
||||||
p->vertCount++;
|
p->vertCount++;
|
||||||
}
|
}
|
||||||
src += nvp*2;
|
src += nvp*2;
|
||||||
|
|
@ -459,35 +540,11 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store portal edges.
|
|
||||||
if (params->tileSize > 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < params->polyCount; ++i)
|
|
||||||
{
|
|
||||||
dtPoly* poly = &navPolys[i];
|
|
||||||
for (int j = 0; j < poly->vertCount; ++j)
|
|
||||||
{
|
|
||||||
int nj = j+1;
|
|
||||||
if (nj >= poly->vertCount) nj = 0;
|
|
||||||
|
|
||||||
const unsigned short* va = ¶ms->verts[poly->verts[j]*3];
|
|
||||||
const unsigned short* vb = ¶ms->verts[poly->verts[nj]*3];
|
|
||||||
|
|
||||||
if (va[0] == params->tileSize && vb[0] == params->tileSize) // x+
|
|
||||||
poly->neis[j] = DT_EXT_LINK | 0;
|
|
||||||
else if (va[2] == params->tileSize && vb[2] == params->tileSize) // z+
|
|
||||||
poly->neis[j] = DT_EXT_LINK | 2;
|
|
||||||
else if (va[0] == 0 && vb[0] == 0) // x-
|
|
||||||
poly->neis[j] = DT_EXT_LINK | 4;
|
|
||||||
else if (va[2] == 0 && vb[2] == 0) // z-
|
|
||||||
poly->neis[j] = DT_EXT_LINK | 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store detail meshes and vertices.
|
// Store detail meshes and vertices.
|
||||||
// The nav polygon vertices are stored as the first vertices on each mesh.
|
// The nav polygon vertices are stored as the first vertices on each mesh.
|
||||||
// We compress the mesh data by skipping them and using the navmesh coordinates.
|
// We compress the mesh data by skipping them and using the navmesh coordinates.
|
||||||
|
if (params->detailMeshes)
|
||||||
|
{
|
||||||
unsigned short vbase = 0;
|
unsigned short vbase = 0;
|
||||||
for (int i = 0; i < params->polyCount; ++i)
|
for (int i = 0; i < params->polyCount; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -508,11 +565,42 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||||
}
|
}
|
||||||
// Store triangles.
|
// Store triangles.
|
||||||
memcpy(navDTris, params->detailTris, sizeof(unsigned char)*4*params->detailTriCount);
|
memcpy(navDTris, params->detailTris, sizeof(unsigned char)*4*params->detailTriCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create dummy detail mesh by triangulating polys.
|
||||||
|
int tbase = 0;
|
||||||
|
for (int i = 0; i < params->polyCount; ++i)
|
||||||
|
{
|
||||||
|
dtPolyDetail& dtl = navDMeshes[i];
|
||||||
|
const int nv = navPolys[i].vertCount;
|
||||||
|
dtl.vertBase = 0;
|
||||||
|
dtl.vertCount = 0;
|
||||||
|
dtl.triBase = (unsigned int)tbase;
|
||||||
|
dtl.triCount = (unsigned char)(nv-2);
|
||||||
|
// Triangulate polygon (local indices).
|
||||||
|
for (int j = 2; j < nv; ++j)
|
||||||
|
{
|
||||||
|
unsigned char* t = &navDTris[tbase*4];
|
||||||
|
t[0] = 0;
|
||||||
|
t[1] = (unsigned char)(j-1);
|
||||||
|
t[2] = (unsigned char)j;
|
||||||
|
// Bit for each edge that belongs to poly boundary.
|
||||||
|
t[3] = (1<<2);
|
||||||
|
if (j == 2) t[3] |= (1<<0);
|
||||||
|
if (j == nv-1) t[3] |= (1<<4);
|
||||||
|
tbase++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Store and create BVtree.
|
// Store and create BVtree.
|
||||||
// TODO: take detail mesh into account! use byte per bbox extent?
|
// TODO: take detail mesh into account! use byte per bbox extent?
|
||||||
|
if (params->buildBvTree)
|
||||||
|
{
|
||||||
createBVTree(params->verts, params->vertCount, params->polys, params->polyCount,
|
createBVTree(params->verts, params->vertCount, params->polys, params->polyCount,
|
||||||
nvp, params->cs, params->ch, params->polyCount*2, navBvtree);
|
nvp, params->cs, params->ch, params->polyCount*2, navBvtree);
|
||||||
|
}
|
||||||
|
|
||||||
// Store Off-Mesh connections.
|
// Store Off-Mesh connections.
|
||||||
n = 0;
|
n = 0;
|
||||||
|
|
@ -544,51 +632,14 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void swapByte(unsigned char* a, unsigned char* b)
|
|
||||||
{
|
|
||||||
unsigned char tmp = *a;
|
|
||||||
*a = *b;
|
|
||||||
*b = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void swapEndian(unsigned short* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
swapByte(x+0, x+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void swapEndian(short* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
swapByte(x+0, x+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void swapEndian(unsigned int* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
swapByte(x+0, x+3); swapByte(x+1, x+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void swapEndian(int* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
swapByte(x+0, x+3); swapByte(x+1, x+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void swapEndian(float* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
swapByte(x+0, x+3); swapByte(x+1, x+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int /*dataSize*/)
|
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||||
{
|
{
|
||||||
dtMeshHeader* header = (dtMeshHeader*)data;
|
dtMeshHeader* header = (dtMeshHeader*)data;
|
||||||
|
|
||||||
int swappedMagic = DT_NAVMESH_MAGIC;
|
int swappedMagic = DT_NAVMESH_MAGIC;
|
||||||
int swappedVersion = DT_NAVMESH_VERSION;
|
int swappedVersion = DT_NAVMESH_VERSION;
|
||||||
swapEndian(&swappedMagic);
|
dtSwapEndian(&swappedMagic);
|
||||||
swapEndian(&swappedVersion);
|
dtSwapEndian(&swappedVersion);
|
||||||
|
|
||||||
if ((header->magic != DT_NAVMESH_MAGIC || header->version != DT_NAVMESH_VERSION) &&
|
if ((header->magic != DT_NAVMESH_MAGIC || header->version != DT_NAVMESH_VERSION) &&
|
||||||
(header->magic != swappedMagic || header->version != swappedVersion))
|
(header->magic != swappedMagic || header->version != swappedVersion))
|
||||||
|
|
@ -596,36 +647,43 @@ bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
swapEndian(&header->magic);
|
dtSwapEndian(&header->magic);
|
||||||
swapEndian(&header->version);
|
dtSwapEndian(&header->version);
|
||||||
swapEndian(&header->x);
|
dtSwapEndian(&header->x);
|
||||||
swapEndian(&header->y);
|
dtSwapEndian(&header->y);
|
||||||
swapEndian(&header->userId);
|
dtSwapEndian(&header->layer);
|
||||||
swapEndian(&header->polyCount);
|
dtSwapEndian(&header->userId);
|
||||||
swapEndian(&header->vertCount);
|
dtSwapEndian(&header->polyCount);
|
||||||
swapEndian(&header->maxLinkCount);
|
dtSwapEndian(&header->vertCount);
|
||||||
swapEndian(&header->detailMeshCount);
|
dtSwapEndian(&header->maxLinkCount);
|
||||||
swapEndian(&header->detailVertCount);
|
dtSwapEndian(&header->detailMeshCount);
|
||||||
swapEndian(&header->detailTriCount);
|
dtSwapEndian(&header->detailVertCount);
|
||||||
swapEndian(&header->bvNodeCount);
|
dtSwapEndian(&header->detailTriCount);
|
||||||
swapEndian(&header->offMeshConCount);
|
dtSwapEndian(&header->bvNodeCount);
|
||||||
swapEndian(&header->offMeshBase);
|
dtSwapEndian(&header->offMeshConCount);
|
||||||
swapEndian(&header->walkableHeight);
|
dtSwapEndian(&header->offMeshBase);
|
||||||
swapEndian(&header->walkableRadius);
|
dtSwapEndian(&header->walkableHeight);
|
||||||
swapEndian(&header->walkableClimb);
|
dtSwapEndian(&header->walkableRadius);
|
||||||
swapEndian(&header->bmin[0]);
|
dtSwapEndian(&header->walkableClimb);
|
||||||
swapEndian(&header->bmin[1]);
|
dtSwapEndian(&header->bmin[0]);
|
||||||
swapEndian(&header->bmin[2]);
|
dtSwapEndian(&header->bmin[1]);
|
||||||
swapEndian(&header->bmax[0]);
|
dtSwapEndian(&header->bmin[2]);
|
||||||
swapEndian(&header->bmax[1]);
|
dtSwapEndian(&header->bmax[0]);
|
||||||
swapEndian(&header->bmax[2]);
|
dtSwapEndian(&header->bmax[1]);
|
||||||
swapEndian(&header->bvQuantFactor);
|
dtSwapEndian(&header->bmax[2]);
|
||||||
|
dtSwapEndian(&header->bvQuantFactor);
|
||||||
|
|
||||||
// Freelist index and pointers are updated when tile is added, no need to swap.
|
// Freelist index and pointers are updated when tile is added, no need to swap.
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// @warning This function assumes that the header is in the correct endianess already.
|
||||||
|
/// Call #dtNavMeshHeaderSwapEndian() first on the data if the data is expected to be in wrong endianess
|
||||||
|
/// to start with. Call #dtNavMeshHeaderSwapEndian() after the data has been swapped if converting from
|
||||||
|
/// native to foreign endianess.
|
||||||
bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||||
{
|
{
|
||||||
// Make sure the data is in right format.
|
// Make sure the data is in right format.
|
||||||
|
|
@ -659,7 +717,7 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||||
// Vertices
|
// Vertices
|
||||||
for (int i = 0; i < header->vertCount*3; ++i)
|
for (int i = 0; i < header->vertCount*3; ++i)
|
||||||
{
|
{
|
||||||
swapEndian(&verts[i]);
|
dtSwapEndian(&verts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Polys
|
// Polys
|
||||||
|
|
@ -669,10 +727,10 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||||
// poly->firstLink is update when tile is added, no need to swap.
|
// poly->firstLink is update when tile is added, no need to swap.
|
||||||
for (int j = 0; j < DT_VERTS_PER_POLYGON; ++j)
|
for (int j = 0; j < DT_VERTS_PER_POLYGON; ++j)
|
||||||
{
|
{
|
||||||
swapEndian(&p->verts[j]);
|
dtSwapEndian(&p->verts[j]);
|
||||||
swapEndian(&p->neis[j]);
|
dtSwapEndian(&p->neis[j]);
|
||||||
}
|
}
|
||||||
swapEndian(&p->flags);
|
dtSwapEndian(&p->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Links are rebuild when tile is added, no need to swap.
|
// Links are rebuild when tile is added, no need to swap.
|
||||||
|
|
@ -681,14 +739,14 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||||
for (int i = 0; i < header->detailMeshCount; ++i)
|
for (int i = 0; i < header->detailMeshCount; ++i)
|
||||||
{
|
{
|
||||||
dtPolyDetail* pd = &detailMeshes[i];
|
dtPolyDetail* pd = &detailMeshes[i];
|
||||||
swapEndian(&pd->vertBase);
|
dtSwapEndian(&pd->vertBase);
|
||||||
swapEndian(&pd->triBase);
|
dtSwapEndian(&pd->triBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail verts
|
// Detail verts
|
||||||
for (int i = 0; i < header->detailVertCount*3; ++i)
|
for (int i = 0; i < header->detailVertCount*3; ++i)
|
||||||
{
|
{
|
||||||
swapEndian(&detailVerts[i]);
|
dtSwapEndian(&detailVerts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BV-tree
|
// BV-tree
|
||||||
|
|
@ -697,10 +755,10 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||||
dtBVNode* node = &bvTree[i];
|
dtBVNode* node = &bvTree[i];
|
||||||
for (int j = 0; j < 3; ++j)
|
for (int j = 0; j < 3; ++j)
|
||||||
{
|
{
|
||||||
swapEndian(&node->bmin[j]);
|
dtSwapEndian(&node->bmin[j]);
|
||||||
swapEndian(&node->bmax[j]);
|
dtSwapEndian(&node->bmax[j]);
|
||||||
}
|
}
|
||||||
swapEndian(&node->i);
|
dtSwapEndian(&node->i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Off-mesh Connections.
|
// Off-mesh Connections.
|
||||||
|
|
@ -708,9 +766,9 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||||
{
|
{
|
||||||
dtOffMeshConnection* con = &offMeshCons[i];
|
dtOffMeshConnection* con = &offMeshCons[i];
|
||||||
for (int j = 0; j < 6; ++j)
|
for (int j = 0; j < 6; ++j)
|
||||||
swapEndian(&con->pos[j]);
|
dtSwapEndian(&con->pos[j]);
|
||||||
swapEndian(&con->rad);
|
dtSwapEndian(&con->rad);
|
||||||
swapEndian(&con->poly);
|
dtSwapEndian(&con->poly);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -22,16 +22,30 @@
|
||||||
#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)
|
inline unsigned int dtHashRef(dtPolyRef a)
|
||||||
{
|
{
|
||||||
a = (~a) + (a << 18);
|
a = (~a) + (a << 18); // a = (a << 18) - a - 1;
|
||||||
a = a ^ (a >> 31);
|
a = a ^ (a >> 31);
|
||||||
a = a * 21;
|
a = a * 21; // a = (a + (a << 2)) + (a << 4);
|
||||||
a = a ^ (a >> 11);
|
a = a ^ (a >> 11);
|
||||||
a = a + (a << 6);
|
a = a + (a << 6);
|
||||||
a = a ^ (a >> 22);
|
a = a ^ (a >> 22);
|
||||||
return (unsigned int)a;
|
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) :
|
dtNodePool::dtNodePool(int maxNodes, int hashSize) :
|
||||||
|
|
@ -46,15 +60,15 @@ dtNodePool::dtNodePool(int maxNodes, int hashSize) :
|
||||||
dtAssert(m_maxNodes > 0);
|
dtAssert(m_maxNodes > 0);
|
||||||
|
|
||||||
m_nodes = (dtNode*)dtAlloc(sizeof(dtNode)*m_maxNodes, DT_ALLOC_PERM);
|
m_nodes = (dtNode*)dtAlloc(sizeof(dtNode)*m_maxNodes, DT_ALLOC_PERM);
|
||||||
m_next = (unsigned short*)dtAlloc(sizeof(unsigned short)*m_maxNodes, DT_ALLOC_PERM);
|
m_next = (dtNodeIndex*)dtAlloc(sizeof(dtNodeIndex)*m_maxNodes, DT_ALLOC_PERM);
|
||||||
m_first = (unsigned short*)dtAlloc(sizeof(unsigned short)*hashSize, DT_ALLOC_PERM);
|
m_first = (dtNodeIndex*)dtAlloc(sizeof(dtNodeIndex)*hashSize, DT_ALLOC_PERM);
|
||||||
|
|
||||||
dtAssert(m_nodes);
|
dtAssert(m_nodes);
|
||||||
dtAssert(m_next);
|
dtAssert(m_next);
|
||||||
dtAssert(m_first);
|
dtAssert(m_first);
|
||||||
|
|
||||||
memset(m_first, 0xff, sizeof(unsigned short)*m_hashSize);
|
memset(m_first, 0xff, sizeof(dtNodeIndex)*m_hashSize);
|
||||||
memset(m_next, 0xff, sizeof(unsigned short)*m_maxNodes);
|
memset(m_next, 0xff, sizeof(dtNodeIndex)*m_maxNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
dtNodePool::~dtNodePool()
|
dtNodePool::~dtNodePool()
|
||||||
|
|
@ -66,31 +80,50 @@ dtNodePool::~dtNodePool()
|
||||||
|
|
||||||
void dtNodePool::clear()
|
void dtNodePool::clear()
|
||||||
{
|
{
|
||||||
memset(m_first, 0xff, sizeof(unsigned short)*m_hashSize);
|
memset(m_first, 0xff, sizeof(dtNodeIndex)*m_hashSize);
|
||||||
m_nodeCount = 0;
|
m_nodeCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dtNode* dtNodePool::findNode(dtPolyRef id)
|
unsigned int dtNodePool::findNodes(dtPolyRef id, dtNode** nodes, const int maxNodes)
|
||||||
{
|
{
|
||||||
|
int n = 0;
|
||||||
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
|
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
|
||||||
unsigned short i = m_first[bucket];
|
dtNodeIndex i = m_first[bucket];
|
||||||
while (i != DT_NULL_IDX)
|
while (i != DT_NULL_IDX)
|
||||||
{
|
{
|
||||||
if (m_nodes[i].id == id)
|
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];
|
return &m_nodes[i];
|
||||||
i = m_next[i];
|
i = m_next[i];
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dtNode* dtNodePool::getNode(dtPolyRef id)
|
dtNode* dtNodePool::getNode(dtPolyRef id, unsigned char state)
|
||||||
{
|
{
|
||||||
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
|
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
|
||||||
unsigned short i = m_first[bucket];
|
dtNodeIndex i = m_first[bucket];
|
||||||
dtNode* node = 0;
|
dtNode* node = 0;
|
||||||
while (i != DT_NULL_IDX)
|
while (i != DT_NULL_IDX)
|
||||||
{
|
{
|
||||||
if (m_nodes[i].id == id)
|
if (m_nodes[i].id == id && m_nodes[i].state == state)
|
||||||
return &m_nodes[i];
|
return &m_nodes[i];
|
||||||
i = m_next[i];
|
i = m_next[i];
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +131,7 @@ dtNode* dtNodePool::getNode(dtPolyRef id)
|
||||||
if (m_nodeCount >= m_maxNodes)
|
if (m_nodeCount >= m_maxNodes)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
i = (unsigned short)m_nodeCount;
|
i = (dtNodeIndex)m_nodeCount;
|
||||||
m_nodeCount++;
|
m_nodeCount++;
|
||||||
|
|
||||||
// Init node
|
// Init node
|
||||||
|
|
@ -107,6 +140,7 @@ dtNode* dtNodePool::getNode(dtPolyRef id)
|
||||||
node->cost = 0;
|
node->cost = 0;
|
||||||
node->total = 0;
|
node->total = 0;
|
||||||
node->id = id;
|
node->id = id;
|
||||||
|
node->state = state;
|
||||||
node->flags = 0;
|
node->flags = 0;
|
||||||
|
|
||||||
m_next[i] = m_first[bucket];
|
m_next[i] = m_first[bucket];
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,19 @@ EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Win32 = Debug|Win32
|
Debug|Win32 = Debug|Win32
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
Release|Win32 = Release|Win32
|
Release|Win32 = Release|Win32
|
||||||
|
Release|x64 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|Win32.ActiveCfg = Debug|Win32
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|Win32.Build.0 = Debug|Win32
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|x64.Build.0 = Debug|x64
|
||||||
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|Win32.ActiveCfg = Release|Win32
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|Win32.Build.0 = Release|Win32
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,19 @@ EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Win32 = Debug|Win32
|
Debug|Win32 = Debug|Win32
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
Release|Win32 = Release|Win32
|
Release|Win32 = Release|Win32
|
||||||
|
Release|x64 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|Win32.ActiveCfg = Debug|Win32
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|Win32.Build.0 = Debug|Win32
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|x64.Build.0 = Debug|x64
|
||||||
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|Win32.ActiveCfg = Release|Win32
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|Win32.Build.0 = Release|Win32
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,26 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 2012
|
# Visual Studio 2013
|
||||||
|
VisualStudioVersion = 12.0.21005.1
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Detour", "VC120\Detour.vcxproj", "{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Detour", "VC120\Detour.vcxproj", "{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Win32 = Debug|Win32
|
Debug|Win32 = Debug|Win32
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
Release|Win32 = Release|Win32
|
Release|Win32 = Release|Win32
|
||||||
|
Release|x64 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|Win32.ActiveCfg = Debug|Win32
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|Win32.Build.0 = Debug|Win32
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Debug|x64.Build.0 = Debug|x64
|
||||||
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|Win32.ActiveCfg = Release|Win32
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|Win32.Build.0 = Release|Win32
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{72BDF975-4D4A-42C7-B2C4-F9ED90A2ABB6}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;DT_POLYREF64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
|
@ -101,10 +101,11 @@
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;DT_POLYREF64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<TargetMachine>MachineX64</TargetMachine>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
|
@ -114,7 +115,7 @@
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;DT_POLYREF64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
|
|
@ -130,23 +131,26 @@
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;DT_POLYREF64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<TargetMachine>MachineX64</TargetMachine>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\Include\DetourAlloc.h" />
|
<ClInclude Include="..\..\Include\DetourAlloc.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourAssert.h" />
|
<ClInclude Include="..\..\Include\DetourAssert.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourCommon.h" />
|
<ClInclude Include="..\..\Include\DetourCommon.h" />
|
||||||
|
<ClInclude Include="..\..\Include\DetourMath.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourNavMesh.h" />
|
<ClInclude Include="..\..\Include\DetourNavMesh.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourNavMeshBuilder.h" />
|
<ClInclude Include="..\..\Include\DetourNavMeshBuilder.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourNavMeshQuery.h" />
|
<ClInclude Include="..\..\Include\DetourNavMeshQuery.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourNode.h" />
|
<ClInclude Include="..\..\Include\DetourNode.h" />
|
||||||
|
<ClInclude Include="..\..\Include\DetourStatus.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\Source\DetourAlloc.cpp" />
|
<ClCompile Include="..\..\Source\DetourAlloc.cpp" />
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,12 @@
|
||||||
<ClInclude Include="..\..\Include\DetourNavMeshQuery.h">
|
<ClInclude Include="..\..\Include\DetourNavMeshQuery.h">
|
||||||
<Filter>include</Filter>
|
<Filter>include</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\Include\DetourMath.h">
|
||||||
|
<Filter>include</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\Include\DetourStatus.h">
|
||||||
|
<Filter>include</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\Source\DetourAlloc.cpp">
|
<ClCompile Include="..\..\Source\DetourAlloc.cpp">
|
||||||
|
|
|
||||||
|
|
@ -27,27 +27,27 @@
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
<PlatformToolset>v120</PlatformToolset>
|
<PlatformToolset>v110</PlatformToolset>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
<PlatformToolset>v120</PlatformToolset>
|
<PlatformToolset>v110</PlatformToolset>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
<PlatformToolset>v120</PlatformToolset>
|
<PlatformToolset>v110</PlatformToolset>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
<PlatformToolset>v120</PlatformToolset>
|
<PlatformToolset>v110</PlatformToolset>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
<ImportGroup Label="ExtensionSettings">
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
|
@ -94,7 +94,7 @@
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;DT_POLYREF64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
|
@ -105,10 +105,11 @@
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;DT_POLYREF64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<TargetMachine>MachineX64</TargetMachine>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
|
@ -118,7 +119,7 @@
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;DT_POLYREF64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
|
|
@ -134,23 +135,26 @@
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;DT_POLYREF64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<TargetMachine>MachineX64</TargetMachine>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\Include\DetourAlloc.h" />
|
<ClInclude Include="..\..\Include\DetourAlloc.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourAssert.h" />
|
<ClInclude Include="..\..\Include\DetourAssert.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourCommon.h" />
|
<ClInclude Include="..\..\Include\DetourCommon.h" />
|
||||||
|
<ClInclude Include="..\..\Include\DetourMath.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourNavMesh.h" />
|
<ClInclude Include="..\..\Include\DetourNavMesh.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourNavMeshBuilder.h" />
|
<ClInclude Include="..\..\Include\DetourNavMeshBuilder.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourNavMeshQuery.h" />
|
<ClInclude Include="..\..\Include\DetourNavMeshQuery.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourNode.h" />
|
<ClInclude Include="..\..\Include\DetourNode.h" />
|
||||||
|
<ClInclude Include="..\..\Include\DetourStatus.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\Source\DetourAlloc.cpp" />
|
<ClCompile Include="..\..\Source\DetourAlloc.cpp" />
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,12 @@
|
||||||
<ClInclude Include="..\..\Include\DetourNavMeshQuery.h">
|
<ClInclude Include="..\..\Include\DetourNavMeshQuery.h">
|
||||||
<Filter>include</Filter>
|
<Filter>include</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\Include\DetourMath.h">
|
||||||
|
<Filter>include</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\Include\DetourStatus.h">
|
||||||
|
<Filter>include</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\Source\DetourAlloc.cpp">
|
<ClCompile Include="..\..\Source\DetourAlloc.cpp">
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;DT_POLYREF64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
|
@ -105,10 +105,11 @@
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;DT_POLYREF64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<TargetMachine>MachineX64</TargetMachine>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
|
@ -118,7 +119,7 @@
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;DT_POLYREF64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
|
|
@ -134,23 +135,26 @@
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;DT_POLYREF64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<TargetMachine>MachineX64</TargetMachine>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\Include\DetourAlloc.h" />
|
<ClInclude Include="..\..\Include\DetourAlloc.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourAssert.h" />
|
<ClInclude Include="..\..\Include\DetourAssert.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourCommon.h" />
|
<ClInclude Include="..\..\Include\DetourCommon.h" />
|
||||||
|
<ClInclude Include="..\..\Include\DetourMath.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourNavMesh.h" />
|
<ClInclude Include="..\..\Include\DetourNavMesh.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourNavMeshBuilder.h" />
|
<ClInclude Include="..\..\Include\DetourNavMeshBuilder.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourNavMeshQuery.h" />
|
<ClInclude Include="..\..\Include\DetourNavMeshQuery.h" />
|
||||||
<ClInclude Include="..\..\Include\DetourNode.h" />
|
<ClInclude Include="..\..\Include\DetourNode.h" />
|
||||||
|
<ClInclude Include="..\..\Include\DetourStatus.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\Source\DetourAlloc.cpp" />
|
<ClCompile Include="..\..\Source\DetourAlloc.cpp" />
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,12 @@
|
||||||
<ClInclude Include="..\..\Include\DetourNavMeshQuery.h">
|
<ClInclude Include="..\..\Include\DetourNavMeshQuery.h">
|
||||||
<Filter>include</Filter>
|
<Filter>include</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\Include\DetourMath.h">
|
||||||
|
<Filter>include</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\Include\DetourStatus.h">
|
||||||
|
<Filter>include</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\Source\DetourAlloc.cpp">
|
<ClCompile Include="..\..\Source\DetourAlloc.cpp">
|
||||||
|
|
|
||||||
450
dep/recastnavigation/DetourCrowd/Include/DetourCrowd.h
Normal file
450
dep/recastnavigation/DetourCrowd/Include/DetourCrowd.h
Normal file
|
|
@ -0,0 +1,450 @@
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURCROWD_H
|
||||||
|
#define DETOURCROWD_H
|
||||||
|
|
||||||
|
#include "DetourNavMeshQuery.h"
|
||||||
|
#include "DetourObstacleAvoidance.h"
|
||||||
|
#include "DetourLocalBoundary.h"
|
||||||
|
#include "DetourPathCorridor.h"
|
||||||
|
#include "DetourProximityGrid.h"
|
||||||
|
#include "DetourPathQueue.h"
|
||||||
|
|
||||||
|
/// The maximum number of neighbors that a crowd agent can take into account
|
||||||
|
/// for steering decisions.
|
||||||
|
/// @ingroup crowd
|
||||||
|
static const int DT_CROWDAGENT_MAX_NEIGHBOURS = 6;
|
||||||
|
|
||||||
|
/// The maximum number of corners a crowd agent will look ahead in the path.
|
||||||
|
/// This value is used for sizing the crowd agent corner buffers.
|
||||||
|
/// Due to the behavior of the crowd manager, the actual number of useful
|
||||||
|
/// corners will be one less than this number.
|
||||||
|
/// @ingroup crowd
|
||||||
|
static const int DT_CROWDAGENT_MAX_CORNERS = 4;
|
||||||
|
|
||||||
|
/// The maximum number of crowd avoidance configurations supported by the
|
||||||
|
/// crowd manager.
|
||||||
|
/// @ingroup crowd
|
||||||
|
/// @see dtObstacleAvoidanceParams, dtCrowd::setObstacleAvoidanceParams(), dtCrowd::getObstacleAvoidanceParams(),
|
||||||
|
/// dtCrowdAgentParams::obstacleAvoidanceType
|
||||||
|
static const int DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS = 8;
|
||||||
|
|
||||||
|
/// The maximum number of query filter types supported by the crowd manager.
|
||||||
|
/// @ingroup crowd
|
||||||
|
/// @see dtQueryFilter, dtCrowd::getFilter() dtCrowd::getEditableFilter(),
|
||||||
|
/// dtCrowdAgentParams::queryFilterType
|
||||||
|
static const int DT_CROWD_MAX_QUERY_FILTER_TYPE = 16;
|
||||||
|
|
||||||
|
/// Provides neighbor data for agents managed by the crowd.
|
||||||
|
/// @ingroup crowd
|
||||||
|
/// @see dtCrowdAgent::neis, dtCrowd
|
||||||
|
struct dtCrowdNeighbour
|
||||||
|
{
|
||||||
|
int idx; ///< The index of the neighbor in the crowd.
|
||||||
|
float dist; ///< The distance between the current agent and the neighbor.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The type of navigation mesh polygon the agent is currently traversing.
|
||||||
|
/// @ingroup crowd
|
||||||
|
enum CrowdAgentState
|
||||||
|
{
|
||||||
|
DT_CROWDAGENT_STATE_INVALID, ///< The agent is not in a valid state.
|
||||||
|
DT_CROWDAGENT_STATE_WALKING, ///< The agent is traversing a normal navigation mesh polygon.
|
||||||
|
DT_CROWDAGENT_STATE_OFFMESH, ///< The agent is traversing an off-mesh connection.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Configuration parameters for a crowd agent.
|
||||||
|
/// @ingroup crowd
|
||||||
|
struct dtCrowdAgentParams
|
||||||
|
{
|
||||||
|
float radius; ///< Agent radius. [Limit: >= 0]
|
||||||
|
float height; ///< Agent height. [Limit: > 0]
|
||||||
|
float maxAcceleration; ///< Maximum allowed acceleration. [Limit: >= 0]
|
||||||
|
float maxSpeed; ///< Maximum allowed speed. [Limit: >= 0]
|
||||||
|
|
||||||
|
/// Defines how close a collision element must be before it is considered for steering behaviors. [Limits: > 0]
|
||||||
|
float collisionQueryRange;
|
||||||
|
|
||||||
|
float pathOptimizationRange; ///< The path visibility optimization range. [Limit: > 0]
|
||||||
|
|
||||||
|
/// How aggresive the agent manager should be at avoiding collisions with this agent. [Limit: >= 0]
|
||||||
|
float separationWeight;
|
||||||
|
|
||||||
|
/// Flags that impact steering behavior. (See: #UpdateFlags)
|
||||||
|
unsigned char updateFlags;
|
||||||
|
|
||||||
|
/// The index of the avoidance configuration to use for the agent.
|
||||||
|
/// [Limits: 0 <= value <= #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]
|
||||||
|
unsigned char obstacleAvoidanceType;
|
||||||
|
|
||||||
|
/// The index of the query filter used by this agent.
|
||||||
|
unsigned char queryFilterType;
|
||||||
|
|
||||||
|
/// User defined data attached to the agent.
|
||||||
|
void* userData;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MoveRequestState
|
||||||
|
{
|
||||||
|
DT_CROWDAGENT_TARGET_NONE = 0,
|
||||||
|
DT_CROWDAGENT_TARGET_FAILED,
|
||||||
|
DT_CROWDAGENT_TARGET_VALID,
|
||||||
|
DT_CROWDAGENT_TARGET_REQUESTING,
|
||||||
|
DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE,
|
||||||
|
DT_CROWDAGENT_TARGET_WAITING_FOR_PATH,
|
||||||
|
DT_CROWDAGENT_TARGET_VELOCITY,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Represents an agent managed by a #dtCrowd object.
|
||||||
|
/// @ingroup crowd
|
||||||
|
struct dtCrowdAgent
|
||||||
|
{
|
||||||
|
/// True if the agent is active, false if the agent is in an unused slot in the agent pool.
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
/// The type of mesh polygon the agent is traversing. (See: #CrowdAgentState)
|
||||||
|
unsigned char state;
|
||||||
|
|
||||||
|
/// True if the agent has valid path (targetState == DT_CROWDAGENT_TARGET_VALID) and the path does not lead to the requested position, else false.
|
||||||
|
bool partial;
|
||||||
|
|
||||||
|
/// The path corridor the agent is using.
|
||||||
|
dtPathCorridor corridor;
|
||||||
|
|
||||||
|
/// The local boundary data for the agent.
|
||||||
|
dtLocalBoundary boundary;
|
||||||
|
|
||||||
|
/// Time since the agent's path corridor was optimized.
|
||||||
|
float topologyOptTime;
|
||||||
|
|
||||||
|
/// The known neighbors of the agent.
|
||||||
|
dtCrowdNeighbour neis[DT_CROWDAGENT_MAX_NEIGHBOURS];
|
||||||
|
|
||||||
|
/// The number of neighbors.
|
||||||
|
int nneis;
|
||||||
|
|
||||||
|
/// The desired speed.
|
||||||
|
float desiredSpeed;
|
||||||
|
|
||||||
|
float npos[3]; ///< The current agent position. [(x, y, z)]
|
||||||
|
float disp[3];
|
||||||
|
float dvel[3]; ///< The desired velocity of the agent. [(x, y, z)]
|
||||||
|
float nvel[3];
|
||||||
|
float vel[3]; ///< The actual velocity of the agent. [(x, y, z)]
|
||||||
|
|
||||||
|
/// The agent's configuration parameters.
|
||||||
|
dtCrowdAgentParams params;
|
||||||
|
|
||||||
|
/// The local path corridor corners for the agent. (Staight path.) [(x, y, z) * #ncorners]
|
||||||
|
float cornerVerts[DT_CROWDAGENT_MAX_CORNERS*3];
|
||||||
|
|
||||||
|
/// The local path corridor corner flags. (See: #dtStraightPathFlags) [(flags) * #ncorners]
|
||||||
|
unsigned char cornerFlags[DT_CROWDAGENT_MAX_CORNERS];
|
||||||
|
|
||||||
|
/// The reference id of the polygon being entered at the corner. [(polyRef) * #ncorners]
|
||||||
|
dtPolyRef cornerPolys[DT_CROWDAGENT_MAX_CORNERS];
|
||||||
|
|
||||||
|
/// The number of corners.
|
||||||
|
int ncorners;
|
||||||
|
|
||||||
|
unsigned char targetState; ///< State of the movement request.
|
||||||
|
dtPolyRef targetRef; ///< Target polyref of the movement request.
|
||||||
|
float targetPos[3]; ///< Target position of the movement request (or velocity in case of DT_CROWDAGENT_TARGET_VELOCITY).
|
||||||
|
dtPathQueueRef targetPathqRef; ///< Path finder ref.
|
||||||
|
bool targetReplan; ///< Flag indicating that the current path is being replanned.
|
||||||
|
float targetReplanTime; /// <Time since the agent's target was replanned.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtCrowdAgentAnimation
|
||||||
|
{
|
||||||
|
bool active;
|
||||||
|
float initPos[3], startPos[3], endPos[3];
|
||||||
|
dtPolyRef polyRef;
|
||||||
|
float t, tmax;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Crowd agent update flags.
|
||||||
|
/// @ingroup crowd
|
||||||
|
/// @see dtCrowdAgentParams::updateFlags
|
||||||
|
enum UpdateFlags
|
||||||
|
{
|
||||||
|
DT_CROWD_ANTICIPATE_TURNS = 1,
|
||||||
|
DT_CROWD_OBSTACLE_AVOIDANCE = 2,
|
||||||
|
DT_CROWD_SEPARATION = 4,
|
||||||
|
DT_CROWD_OPTIMIZE_VIS = 8, ///< Use #dtPathCorridor::optimizePathVisibility() to optimize the agent path.
|
||||||
|
DT_CROWD_OPTIMIZE_TOPO = 16, ///< Use dtPathCorridor::optimizePathTopology() to optimize the agent path.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtCrowdAgentDebugInfo
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
float optStart[3], optEnd[3];
|
||||||
|
dtObstacleAvoidanceDebugData* vod;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Provides local steering behaviors for a group of agents.
|
||||||
|
/// @ingroup crowd
|
||||||
|
class dtCrowd
|
||||||
|
{
|
||||||
|
int m_maxAgents;
|
||||||
|
dtCrowdAgent* m_agents;
|
||||||
|
dtCrowdAgent** m_activeAgents;
|
||||||
|
dtCrowdAgentAnimation* m_agentAnims;
|
||||||
|
|
||||||
|
dtPathQueue m_pathq;
|
||||||
|
|
||||||
|
dtObstacleAvoidanceParams m_obstacleQueryParams[DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS];
|
||||||
|
dtObstacleAvoidanceQuery* m_obstacleQuery;
|
||||||
|
|
||||||
|
dtProximityGrid* m_grid;
|
||||||
|
|
||||||
|
dtPolyRef* m_pathResult;
|
||||||
|
int m_maxPathResult;
|
||||||
|
|
||||||
|
float m_ext[3];
|
||||||
|
|
||||||
|
dtQueryFilter m_filters[DT_CROWD_MAX_QUERY_FILTER_TYPE];
|
||||||
|
|
||||||
|
float m_maxAgentRadius;
|
||||||
|
|
||||||
|
int m_velocitySampleCount;
|
||||||
|
|
||||||
|
dtNavMeshQuery* m_navquery;
|
||||||
|
|
||||||
|
void updateTopologyOptimization(dtCrowdAgent** agents, const int nagents, const float dt);
|
||||||
|
void updateMoveRequest(const float dt);
|
||||||
|
void checkPathValidity(dtCrowdAgent** agents, const int nagents, const float dt);
|
||||||
|
|
||||||
|
inline int getAgentIndex(const dtCrowdAgent* agent) const { return (int)(agent - m_agents); }
|
||||||
|
|
||||||
|
bool requestMoveTargetReplan(const int idx, dtPolyRef ref, const float* pos);
|
||||||
|
|
||||||
|
void purge();
|
||||||
|
|
||||||
|
public:
|
||||||
|
dtCrowd();
|
||||||
|
~dtCrowd();
|
||||||
|
|
||||||
|
/// Initializes the crowd.
|
||||||
|
/// @param[in] maxAgents The maximum number of agents the crowd can manage. [Limit: >= 1]
|
||||||
|
/// @param[in] maxAgentRadius The maximum radius of any agent that will be added to the crowd. [Limit: > 0]
|
||||||
|
/// @param[in] nav The navigation mesh to use for planning.
|
||||||
|
/// @return True if the initialization succeeded.
|
||||||
|
bool init(const int maxAgents, const float maxAgentRadius, dtNavMesh* nav);
|
||||||
|
|
||||||
|
/// Sets the shared avoidance configuration for the specified index.
|
||||||
|
/// @param[in] idx The index. [Limits: 0 <= value < #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]
|
||||||
|
/// @param[in] params The new configuration.
|
||||||
|
void setObstacleAvoidanceParams(const int idx, const dtObstacleAvoidanceParams* params);
|
||||||
|
|
||||||
|
/// Gets the shared avoidance configuration for the specified index.
|
||||||
|
/// @param[in] idx The index of the configuration to retreive.
|
||||||
|
/// [Limits: 0 <= value < #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]
|
||||||
|
/// @return The requested configuration.
|
||||||
|
const dtObstacleAvoidanceParams* getObstacleAvoidanceParams(const int idx) const;
|
||||||
|
|
||||||
|
/// Gets the specified agent from the pool.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
/// @return The requested agent.
|
||||||
|
const dtCrowdAgent* getAgent(const int idx);
|
||||||
|
|
||||||
|
/// Gets the specified agent from the pool.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
/// @return The requested agent.
|
||||||
|
dtCrowdAgent* getEditableAgent(const int idx);
|
||||||
|
|
||||||
|
/// The maximum number of agents that can be managed by the object.
|
||||||
|
/// @return The maximum number of agents.
|
||||||
|
int getAgentCount() const;
|
||||||
|
|
||||||
|
/// Adds a new agent to the crowd.
|
||||||
|
/// @param[in] pos The requested position of the agent. [(x, y, z)]
|
||||||
|
/// @param[in] params The configutation of the agent.
|
||||||
|
/// @return The index of the agent in the agent pool. Or -1 if the agent could not be added.
|
||||||
|
int addAgent(const float* pos, const dtCrowdAgentParams* params);
|
||||||
|
|
||||||
|
/// Updates the specified agent's configuration.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
/// @param[in] params The new agent configuration.
|
||||||
|
void updateAgentParameters(const int idx, const dtCrowdAgentParams* params);
|
||||||
|
|
||||||
|
/// Removes the agent from the crowd.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
void removeAgent(const int idx);
|
||||||
|
|
||||||
|
/// Submits a new move request for the specified agent.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
/// @param[in] ref The position's polygon reference.
|
||||||
|
/// @param[in] pos The position within the polygon. [(x, y, z)]
|
||||||
|
/// @return True if the request was successfully submitted.
|
||||||
|
bool requestMoveTarget(const int idx, dtPolyRef ref, const float* pos);
|
||||||
|
|
||||||
|
/// Submits a new move request for the specified agent.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
/// @param[in] vel The movement velocity. [(x, y, z)]
|
||||||
|
/// @return True if the request was successfully submitted.
|
||||||
|
bool requestMoveVelocity(const int idx, const float* vel);
|
||||||
|
|
||||||
|
/// Resets any request for the specified agent.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
/// @return True if the request was successfully reseted.
|
||||||
|
bool resetMoveTarget(const int idx);
|
||||||
|
|
||||||
|
/// Gets the active agents int the agent pool.
|
||||||
|
/// @param[out] agents An array of agent pointers. [(#dtCrowdAgent *) * maxAgents]
|
||||||
|
/// @param[in] maxAgents The size of the crowd agent array.
|
||||||
|
/// @return The number of agents returned in @p agents.
|
||||||
|
int getActiveAgents(dtCrowdAgent** agents, const int maxAgents);
|
||||||
|
|
||||||
|
/// Updates the steering and positions of all agents.
|
||||||
|
/// @param[in] dt The time, in seconds, to update the simulation. [Limit: > 0]
|
||||||
|
/// @param[out] debug A debug object to load with debug information. [Opt]
|
||||||
|
void update(const float dt, dtCrowdAgentDebugInfo* debug);
|
||||||
|
|
||||||
|
/// Gets the filter used by the crowd.
|
||||||
|
/// @return The filter used by the crowd.
|
||||||
|
inline const dtQueryFilter* getFilter(const int i) const { return (i >= 0 && i < DT_CROWD_MAX_QUERY_FILTER_TYPE) ? &m_filters[i] : 0; }
|
||||||
|
|
||||||
|
/// Gets the filter used by the crowd.
|
||||||
|
/// @return The filter used by the crowd.
|
||||||
|
inline dtQueryFilter* getEditableFilter(const int i) { return (i >= 0 && i < DT_CROWD_MAX_QUERY_FILTER_TYPE) ? &m_filters[i] : 0; }
|
||||||
|
|
||||||
|
/// Gets the search extents [(x, y, z)] used by the crowd for query operations.
|
||||||
|
/// @return The search extents used by the crowd. [(x, y, z)]
|
||||||
|
const float* getQueryExtents() const { return m_ext; }
|
||||||
|
|
||||||
|
/// Gets the velocity sample count.
|
||||||
|
/// @return The velocity sample count.
|
||||||
|
inline int getVelocitySampleCount() const { return m_velocitySampleCount; }
|
||||||
|
|
||||||
|
/// Gets the crowd's proximity grid.
|
||||||
|
/// @return The crowd's proximity grid.
|
||||||
|
const dtProximityGrid* getGrid() const { return m_grid; }
|
||||||
|
|
||||||
|
/// Gets the crowd's path request queue.
|
||||||
|
/// @return The crowd's path request queue.
|
||||||
|
const dtPathQueue* getPathQueue() const { return &m_pathq; }
|
||||||
|
|
||||||
|
/// Gets the query object used by the crowd.
|
||||||
|
const dtNavMeshQuery* getNavMeshQuery() const { return m_navquery; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Allocates a crowd object using the Detour allocator.
|
||||||
|
/// @return A crowd object that is ready for initialization, or null on failure.
|
||||||
|
/// @ingroup crowd
|
||||||
|
dtCrowd* dtAllocCrowd();
|
||||||
|
|
||||||
|
/// Frees the specified crowd object using the Detour allocator.
|
||||||
|
/// @param[in] ptr A crowd object allocated using #dtAllocCrowd
|
||||||
|
/// @ingroup crowd
|
||||||
|
void dtFreeCrowd(dtCrowd* ptr);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DETOURCROWD_H
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// This section contains detailed documentation for members that don't have
|
||||||
|
// a source file. It reduces clutter in the main section of the header.
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
@defgroup crowd Crowd
|
||||||
|
|
||||||
|
Members in this module implement local steering and dynamic avoidance features.
|
||||||
|
|
||||||
|
The crowd is the big beast of the navigation features. It not only handles a
|
||||||
|
lot of the path management for you, but also local steering and dynamic
|
||||||
|
avoidance between members of the crowd. I.e. It can keep your agents from
|
||||||
|
running into each other.
|
||||||
|
|
||||||
|
Main class: #dtCrowd
|
||||||
|
|
||||||
|
The #dtNavMeshQuery and #dtPathCorridor classes provide perfectly good, easy
|
||||||
|
to use path planning features. But in the end they only give you points that
|
||||||
|
your navigation client should be moving toward. When it comes to deciding things
|
||||||
|
like agent velocity and steering to avoid other agents, that is up to you to
|
||||||
|
implement. Unless, of course, you decide to use #dtCrowd.
|
||||||
|
|
||||||
|
Basically, you add an agent to the crowd, providing various configuration
|
||||||
|
settings such as maximum speed and acceleration. You also provide a local
|
||||||
|
target to more toward. The crowd manager then provides, with every update, the
|
||||||
|
new agent position and velocity for the frame. The movement will be
|
||||||
|
constrained to the navigation mesh, and steering will be applied to ensure
|
||||||
|
agents managed by the crowd do not collide with each other.
|
||||||
|
|
||||||
|
This is very powerful feature set. But it comes with limitations.
|
||||||
|
|
||||||
|
The biggest limitation is that you must give control of the agent's position
|
||||||
|
completely over to the crowd manager. You can update things like maximum speed
|
||||||
|
and acceleration. But in order for the crowd manager to do its thing, it can't
|
||||||
|
allow you to constantly be giving it overrides to position and velocity. So
|
||||||
|
you give up direct control of the agent's movement. It belongs to the crowd.
|
||||||
|
|
||||||
|
The second biggest limitation revolves around the fact that the crowd manager
|
||||||
|
deals with local planning. So the agent's target should never be more than
|
||||||
|
256 polygons aways from its current position. If it is, you risk
|
||||||
|
your agent failing to reach its target. So you may still need to do long
|
||||||
|
distance planning and provide the crowd manager with intermediate targets.
|
||||||
|
|
||||||
|
Other significant limitations:
|
||||||
|
|
||||||
|
- All agents using the crowd manager will use the same #dtQueryFilter.
|
||||||
|
- Crowd management is relatively expensive. The maximum agents under crowd
|
||||||
|
management at any one time is between 20 and 30. A good place to start
|
||||||
|
is a maximum of 25 agents for 0.5ms per frame.
|
||||||
|
|
||||||
|
@note This is a summary list of members. Use the index or search
|
||||||
|
feature to find minor members.
|
||||||
|
|
||||||
|
@struct dtCrowdAgentParams
|
||||||
|
@see dtCrowdAgent, dtCrowd::addAgent(), dtCrowd::updateAgentParameters()
|
||||||
|
|
||||||
|
@var dtCrowdAgentParams::obstacleAvoidanceType
|
||||||
|
@par
|
||||||
|
|
||||||
|
#dtCrowd permits agents to use different avoidance configurations. This value
|
||||||
|
is the index of the #dtObstacleAvoidanceParams within the crowd.
|
||||||
|
|
||||||
|
@see dtObstacleAvoidanceParams, dtCrowd::setObstacleAvoidanceParams(),
|
||||||
|
dtCrowd::getObstacleAvoidanceParams()
|
||||||
|
|
||||||
|
@var dtCrowdAgentParams::collisionQueryRange
|
||||||
|
@par
|
||||||
|
|
||||||
|
Collision elements include other agents and navigation mesh boundaries.
|
||||||
|
|
||||||
|
This value is often based on the agent radius and/or maximum speed. E.g. radius * 8
|
||||||
|
|
||||||
|
@var dtCrowdAgentParams::pathOptimizationRange
|
||||||
|
@par
|
||||||
|
|
||||||
|
Only applicalbe if #updateFlags includes the #DT_CROWD_OPTIMIZE_VIS flag.
|
||||||
|
|
||||||
|
This value is often based on the agent radius. E.g. radius * 30
|
||||||
|
|
||||||
|
@see dtPathCorridor::optimizePathVisibility()
|
||||||
|
|
||||||
|
@var dtCrowdAgentParams::separationWeight
|
||||||
|
@par
|
||||||
|
|
||||||
|
A higher value will result in agents trying to stay farther away from each other at
|
||||||
|
the cost of more difficult steering in tight spaces.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURLOCALBOUNDARY_H
|
||||||
|
#define DETOURLOCALBOUNDARY_H
|
||||||
|
|
||||||
|
#include "DetourNavMeshQuery.h"
|
||||||
|
|
||||||
|
|
||||||
|
class dtLocalBoundary
|
||||||
|
{
|
||||||
|
static const int MAX_LOCAL_SEGS = 8;
|
||||||
|
static const int MAX_LOCAL_POLYS = 16;
|
||||||
|
|
||||||
|
struct Segment
|
||||||
|
{
|
||||||
|
float s[6]; ///< Segment start/end
|
||||||
|
float d; ///< Distance for pruning.
|
||||||
|
};
|
||||||
|
|
||||||
|
float m_center[3];
|
||||||
|
Segment m_segs[MAX_LOCAL_SEGS];
|
||||||
|
int m_nsegs;
|
||||||
|
|
||||||
|
dtPolyRef m_polys[MAX_LOCAL_POLYS];
|
||||||
|
int m_npolys;
|
||||||
|
|
||||||
|
void addSegment(const float dist, const float* seg);
|
||||||
|
|
||||||
|
public:
|
||||||
|
dtLocalBoundary();
|
||||||
|
~dtLocalBoundary();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void update(dtPolyRef ref, const float* pos, const float collisionQueryRange,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
bool isValid(dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
inline const float* getCenter() const { return m_center; }
|
||||||
|
inline int getSegmentCount() const { return m_nsegs; }
|
||||||
|
inline const float* getSegment(int i) const { return m_segs[i].s; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DETOURLOCALBOUNDARY_H
|
||||||
|
|
@ -21,21 +21,19 @@
|
||||||
|
|
||||||
struct dtObstacleCircle
|
struct dtObstacleCircle
|
||||||
{
|
{
|
||||||
float p[3]; // Position of the obstacle
|
float p[3]; ///< Position of the obstacle
|
||||||
float vel[3]; // Velocity of the obstacle
|
float vel[3]; ///< Velocity of the obstacle
|
||||||
float dvel[3]; // Velocity of the obstacle
|
float dvel[3]; ///< Velocity of the obstacle
|
||||||
float rad; // Radius of the obstacle
|
float rad; ///< Radius of the obstacle
|
||||||
float dp[3], np[3]; // Use for side selection during sampling.
|
float dp[3], np[3]; ///< Use for side selection during sampling.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dtObstacleSegment
|
struct dtObstacleSegment
|
||||||
{
|
{
|
||||||
float p[3], q[3]; // End points of the obstacle segment
|
float p[3], q[3]; ///< End points of the obstacle segment
|
||||||
bool touch;
|
bool touch;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int RVO_SAMPLE_RAD = 15;
|
|
||||||
static const int MAX_RVO_SAMPLES = (RVO_SAMPLE_RAD*2+1)*(RVO_SAMPLE_RAD*2+1) + 100;
|
|
||||||
|
|
||||||
class dtObstacleAvoidanceDebugData
|
class dtObstacleAvoidanceDebugData
|
||||||
{
|
{
|
||||||
|
|
@ -75,6 +73,23 @@ dtObstacleAvoidanceDebugData* dtAllocObstacleAvoidanceDebugData();
|
||||||
void dtFreeObstacleAvoidanceDebugData(dtObstacleAvoidanceDebugData* ptr);
|
void dtFreeObstacleAvoidanceDebugData(dtObstacleAvoidanceDebugData* ptr);
|
||||||
|
|
||||||
|
|
||||||
|
static const int DT_MAX_PATTERN_DIVS = 32; ///< Max numver of adaptive divs.
|
||||||
|
static const int DT_MAX_PATTERN_RINGS = 4; ///< Max number of adaptive rings.
|
||||||
|
|
||||||
|
struct dtObstacleAvoidanceParams
|
||||||
|
{
|
||||||
|
float velBias;
|
||||||
|
float weightDesVel;
|
||||||
|
float weightCurVel;
|
||||||
|
float weightSide;
|
||||||
|
float weightToi;
|
||||||
|
float horizTime;
|
||||||
|
unsigned char gridSize; ///< grid
|
||||||
|
unsigned char adaptiveDivs; ///< adaptive
|
||||||
|
unsigned char adaptiveRings; ///< adaptive
|
||||||
|
unsigned char adaptiveDepth; ///< adaptive
|
||||||
|
};
|
||||||
|
|
||||||
class dtObstacleAvoidanceQuery
|
class dtObstacleAvoidanceQuery
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -90,21 +105,14 @@ public:
|
||||||
|
|
||||||
void addSegment(const float* p, const float* q);
|
void addSegment(const float* p, const float* q);
|
||||||
|
|
||||||
inline void setVelocitySelectionBias(float v) { m_velBias = v; }
|
int sampleVelocityGrid(const float* pos, const float rad, const float vmax,
|
||||||
inline void setDesiredVelocityWeight(float w) { m_weightDesVel = w; }
|
|
||||||
inline void setCurrentVelocityWeight(float w) { m_weightCurVel = w; }
|
|
||||||
inline void setPreferredSideWeight(float w) { m_weightSide = w; }
|
|
||||||
inline void setCollisionTimeWeight(float w) { m_weightToi = w; }
|
|
||||||
inline void setTimeHorizon(float t) { m_horizTime = t; }
|
|
||||||
|
|
||||||
void sampleVelocityGrid(const float* pos, const float rad, const float vmax,
|
|
||||||
const float* vel, const float* dvel, float* nvel,
|
const float* vel, const float* dvel, float* nvel,
|
||||||
const int gsize,
|
const dtObstacleAvoidanceParams* params,
|
||||||
dtObstacleAvoidanceDebugData* debug = 0);
|
dtObstacleAvoidanceDebugData* debug = 0);
|
||||||
|
|
||||||
void sampleVelocityAdaptive(const float* pos, const float rad, const float vmax,
|
int sampleVelocityAdaptive(const float* pos, const float rad, const float vmax,
|
||||||
const float* vel, const float* dvel, float* nvel,
|
const float* vel, const float* dvel, float* nvel,
|
||||||
const int ndivs, const int nrings, const int depth,
|
const dtObstacleAvoidanceParams* params,
|
||||||
dtObstacleAvoidanceDebugData* debug = 0);
|
dtObstacleAvoidanceDebugData* debug = 0);
|
||||||
|
|
||||||
inline int getObstacleCircleCount() const { return m_ncircles; }
|
inline int getObstacleCircleCount() const { return m_ncircles; }
|
||||||
|
|
@ -119,18 +127,16 @@ private:
|
||||||
|
|
||||||
float processSample(const float* vcand, const float cs,
|
float processSample(const float* vcand, const float cs,
|
||||||
const float* pos, const float rad,
|
const float* pos, const float rad,
|
||||||
const float vmax, const float* vel, const float* dvel,
|
const float* vel, const float* dvel,
|
||||||
dtObstacleAvoidanceDebugData* debug);
|
dtObstacleAvoidanceDebugData* debug);
|
||||||
|
|
||||||
dtObstacleCircle* insertCircle(const float dist);
|
dtObstacleCircle* insertCircle(const float dist);
|
||||||
dtObstacleSegment* insertSegment(const float dist);
|
dtObstacleSegment* insertSegment(const float dist);
|
||||||
|
|
||||||
float m_velBias;
|
dtObstacleAvoidanceParams m_params;
|
||||||
float m_weightDesVel;
|
float m_invHorizTime;
|
||||||
float m_weightCurVel;
|
float m_vmax;
|
||||||
float m_weightSide;
|
float m_invVmax;
|
||||||
float m_weightToi;
|
|
||||||
float m_horizTime;
|
|
||||||
|
|
||||||
int m_maxCircles;
|
int m_maxCircles;
|
||||||
dtObstacleCircle* m_circles;
|
dtObstacleCircle* m_circles;
|
||||||
146
dep/recastnavigation/DetourCrowd/Include/DetourPathCorridor.h
Normal file
146
dep/recastnavigation/DetourCrowd/Include/DetourPathCorridor.h
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOUTPATHCORRIDOR_H
|
||||||
|
#define DETOUTPATHCORRIDOR_H
|
||||||
|
|
||||||
|
#include "DetourNavMeshQuery.h"
|
||||||
|
|
||||||
|
/// Represents a dynamic polygon corridor used to plan agent movement.
|
||||||
|
/// @ingroup crowd, detour
|
||||||
|
class dtPathCorridor
|
||||||
|
{
|
||||||
|
float m_pos[3];
|
||||||
|
float m_target[3];
|
||||||
|
|
||||||
|
dtPolyRef* m_path;
|
||||||
|
int m_npath;
|
||||||
|
int m_maxPath;
|
||||||
|
|
||||||
|
public:
|
||||||
|
dtPathCorridor();
|
||||||
|
~dtPathCorridor();
|
||||||
|
|
||||||
|
/// Allocates the corridor's path buffer.
|
||||||
|
/// @param[in] maxPath The maximum path size the corridor can handle.
|
||||||
|
/// @return True if the initialization succeeded.
|
||||||
|
bool init(const int maxPath);
|
||||||
|
|
||||||
|
/// Resets the path corridor to the specified position.
|
||||||
|
/// @param[in] ref The polygon reference containing the position.
|
||||||
|
/// @param[in] pos The new position in the corridor. [(x, y, z)]
|
||||||
|
void reset(dtPolyRef ref, const float* pos);
|
||||||
|
|
||||||
|
/// Finds the corners in the corridor from the position toward the target. (The straightened path.)
|
||||||
|
/// @param[out] cornerVerts The corner vertices. [(x, y, z) * cornerCount] [Size: <= maxCorners]
|
||||||
|
/// @param[out] cornerFlags The flag for each corner. [(flag) * cornerCount] [Size: <= maxCorners]
|
||||||
|
/// @param[out] cornerPolys The polygon reference for each corner. [(polyRef) * cornerCount]
|
||||||
|
/// [Size: <= @p maxCorners]
|
||||||
|
/// @param[in] maxCorners The maximum number of corners the buffers can hold.
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
/// @return The number of corners returned in the corner buffers. [0 <= value <= @p maxCorners]
|
||||||
|
int findCorners(float* cornerVerts, unsigned char* cornerFlags,
|
||||||
|
dtPolyRef* cornerPolys, const int maxCorners,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Attempts to optimize the path if the specified point is visible from the current position.
|
||||||
|
/// @param[in] next The point to search toward. [(x, y, z])
|
||||||
|
/// @param[in] pathOptimizationRange The maximum range to search. [Limit: > 0]
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
void optimizePathVisibility(const float* next, const float pathOptimizationRange,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Attempts to optimize the path using a local area search. (Partial replanning.)
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
bool optimizePathTopology(dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
bool moveOverOffmeshConnection(dtPolyRef offMeshConRef, dtPolyRef* refs,
|
||||||
|
float* startPos, float* endPos,
|
||||||
|
dtNavMeshQuery* navquery);
|
||||||
|
|
||||||
|
bool fixPathStart(dtPolyRef safeRef, const float* safePos);
|
||||||
|
|
||||||
|
bool trimInvalidPath(dtPolyRef safeRef, const float* safePos,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Checks the current corridor path to see if its polygon references remain valid.
|
||||||
|
/// @param[in] maxLookAhead The number of polygons from the beginning of the corridor to search.
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
bool isValid(const int maxLookAhead, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Moves the position from the current location to the desired location, adjusting the corridor
|
||||||
|
/// as needed to reflect the change.
|
||||||
|
/// @param[in] npos The desired new position. [(x, y, z)]
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
/// @return Returns true if move succeeded.
|
||||||
|
bool movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Moves the target from the curent location to the desired location, adjusting the corridor
|
||||||
|
/// as needed to reflect the change.
|
||||||
|
/// @param[in] npos The desired new target position. [(x, y, z)]
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
/// @return Returns true if move succeeded.
|
||||||
|
bool moveTargetPosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Loads a new path and target into the corridor.
|
||||||
|
/// @param[in] target The target location within the last polygon of the path. [(x, y, z)]
|
||||||
|
/// @param[in] path The path corridor. [(polyRef) * @p npolys]
|
||||||
|
/// @param[in] npath The number of polygons in the path.
|
||||||
|
void setCorridor(const float* target, const dtPolyRef* polys, const int npath);
|
||||||
|
|
||||||
|
/// Gets the current position within the corridor. (In the first polygon.)
|
||||||
|
/// @return The current position within the corridor.
|
||||||
|
inline const float* getPos() const { return m_pos; }
|
||||||
|
|
||||||
|
/// Gets the current target within the corridor. (In the last polygon.)
|
||||||
|
/// @return The current target within the corridor.
|
||||||
|
inline const float* getTarget() const { return m_target; }
|
||||||
|
|
||||||
|
/// The polygon reference id of the first polygon in the corridor, the polygon containing the position.
|
||||||
|
/// @return The polygon reference id of the first polygon in the corridor. (Or zero if there is no path.)
|
||||||
|
inline dtPolyRef getFirstPoly() const { return m_npath ? m_path[0] : 0; }
|
||||||
|
|
||||||
|
/// The polygon reference id of the last polygon in the corridor, the polygon containing the target.
|
||||||
|
/// @return The polygon reference id of the last polygon in the corridor. (Or zero if there is no path.)
|
||||||
|
inline dtPolyRef getLastPoly() const { return m_npath ? m_path[m_npath-1] : 0; }
|
||||||
|
|
||||||
|
/// The corridor's path.
|
||||||
|
/// @return The corridor's path. [(polyRef) * #getPathCount()]
|
||||||
|
inline const dtPolyRef* getPath() const { return m_path; }
|
||||||
|
|
||||||
|
/// The number of polygons in the current corridor path.
|
||||||
|
/// @return The number of polygons in the current corridor path.
|
||||||
|
inline int getPathCount() const { return m_npath; }
|
||||||
|
};
|
||||||
|
|
||||||
|
int dtMergeCorridorStartMoved(dtPolyRef* path, const int npath, const int maxPath,
|
||||||
|
const dtPolyRef* visited, const int nvisited);
|
||||||
|
|
||||||
|
int dtMergeCorridorEndMoved(dtPolyRef* path, const int npath, const int maxPath,
|
||||||
|
const dtPolyRef* visited, const int nvisited);
|
||||||
|
|
||||||
|
int dtMergeCorridorStartShortcut(dtPolyRef* path, const int npath, const int maxPath,
|
||||||
|
const dtPolyRef* visited, const int nvisited);
|
||||||
|
|
||||||
|
#endif // DETOUTPATHCORRIDOR_H
|
||||||
75
dep/recastnavigation/DetourCrowd/Include/DetourPathQueue.h
Normal file
75
dep/recastnavigation/DetourCrowd/Include/DetourPathQueue.h
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURPATHQUEUE_H
|
||||||
|
#define DETOURPATHQUEUE_H
|
||||||
|
|
||||||
|
#include "DetourNavMesh.h"
|
||||||
|
#include "DetourNavMeshQuery.h"
|
||||||
|
|
||||||
|
static const unsigned int DT_PATHQ_INVALID = 0;
|
||||||
|
|
||||||
|
typedef unsigned int dtPathQueueRef;
|
||||||
|
|
||||||
|
class dtPathQueue
|
||||||
|
{
|
||||||
|
struct PathQuery
|
||||||
|
{
|
||||||
|
dtPathQueueRef ref;
|
||||||
|
/// Path find start and end location.
|
||||||
|
float startPos[3], endPos[3];
|
||||||
|
dtPolyRef startRef, endRef;
|
||||||
|
/// Result.
|
||||||
|
dtPolyRef* path;
|
||||||
|
int npath;
|
||||||
|
/// State.
|
||||||
|
dtStatus status;
|
||||||
|
int keepAlive;
|
||||||
|
const dtQueryFilter* filter; ///< TODO: This is potentially dangerous!
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int MAX_QUEUE = 8;
|
||||||
|
PathQuery m_queue[MAX_QUEUE];
|
||||||
|
dtPathQueueRef m_nextHandle;
|
||||||
|
int m_maxPathSize;
|
||||||
|
int m_queueHead;
|
||||||
|
dtNavMeshQuery* m_navquery;
|
||||||
|
|
||||||
|
void purge();
|
||||||
|
|
||||||
|
public:
|
||||||
|
dtPathQueue();
|
||||||
|
~dtPathQueue();
|
||||||
|
|
||||||
|
bool init(const int maxPathSize, const int maxSearchNodeCount, dtNavMesh* nav);
|
||||||
|
|
||||||
|
void update(const int maxIters);
|
||||||
|
|
||||||
|
dtPathQueueRef request(dtPolyRef startRef, dtPolyRef endRef,
|
||||||
|
const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
dtStatus getRequestStatus(dtPathQueueRef ref) const;
|
||||||
|
|
||||||
|
dtStatus getPathResult(dtPathQueueRef ref, dtPolyRef* path, int* pathSize, const int maxPath);
|
||||||
|
|
||||||
|
inline const dtNavMeshQuery* getNavQuery() const { return m_navquery; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DETOURPATHQUEUE_H
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURPROXIMITYGRID_H
|
||||||
|
#define DETOURPROXIMITYGRID_H
|
||||||
|
|
||||||
|
class dtProximityGrid
|
||||||
|
{
|
||||||
|
int m_maxItems;
|
||||||
|
float m_cellSize;
|
||||||
|
float m_invCellSize;
|
||||||
|
|
||||||
|
struct Item
|
||||||
|
{
|
||||||
|
unsigned short id;
|
||||||
|
short x,y;
|
||||||
|
unsigned short next;
|
||||||
|
};
|
||||||
|
Item* m_pool;
|
||||||
|
int m_poolHead;
|
||||||
|
int m_poolSize;
|
||||||
|
|
||||||
|
unsigned short* m_buckets;
|
||||||
|
int m_bucketsSize;
|
||||||
|
|
||||||
|
int m_bounds[4];
|
||||||
|
|
||||||
|
public:
|
||||||
|
dtProximityGrid();
|
||||||
|
~dtProximityGrid();
|
||||||
|
|
||||||
|
bool init(const int maxItems, const float cellSize);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void addItem(const unsigned short id,
|
||||||
|
const float minx, const float miny,
|
||||||
|
const float maxx, const float maxy);
|
||||||
|
|
||||||
|
int queryItems(const float minx, const float miny,
|
||||||
|
const float maxx, const float maxy,
|
||||||
|
unsigned short* ids, const int maxIds) const;
|
||||||
|
|
||||||
|
int getItemCountAt(const int x, const int y) const;
|
||||||
|
|
||||||
|
inline const int* getBounds() const { return m_bounds; }
|
||||||
|
inline float getCellSize() const { return m_cellSize; }
|
||||||
|
};
|
||||||
|
|
||||||
|
dtProximityGrid* dtAllocProximityGrid();
|
||||||
|
void dtFreeProximityGrid(dtProximityGrid* ptr);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DETOURPROXIMITYGRID_H
|
||||||
|
|
||||||
1446
dep/recastnavigation/DetourCrowd/Source/DetourCrowd.cpp
Normal file
1446
dep/recastnavigation/DetourCrowd/Source/DetourCrowd.cpp
Normal file
File diff suppressed because it is too large
Load diff
137
dep/recastnavigation/DetourCrowd/Source/DetourLocalBoundary.cpp
Normal file
137
dep/recastnavigation/DetourCrowd/Source/DetourLocalBoundary.cpp
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
//
|
||||||
|
// 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 <float.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "DetourLocalBoundary.h"
|
||||||
|
#include "DetourNavMeshQuery.h"
|
||||||
|
#include "DetourCommon.h"
|
||||||
|
#include "DetourAssert.h"
|
||||||
|
|
||||||
|
|
||||||
|
dtLocalBoundary::dtLocalBoundary() :
|
||||||
|
m_nsegs(0),
|
||||||
|
m_npolys(0)
|
||||||
|
{
|
||||||
|
dtVset(m_center, FLT_MAX,FLT_MAX,FLT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtLocalBoundary::~dtLocalBoundary()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtLocalBoundary::reset()
|
||||||
|
{
|
||||||
|
dtVset(m_center, FLT_MAX,FLT_MAX,FLT_MAX);
|
||||||
|
m_npolys = 0;
|
||||||
|
m_nsegs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtLocalBoundary::addSegment(const float dist, const float* s)
|
||||||
|
{
|
||||||
|
// Insert neighbour based on the distance.
|
||||||
|
Segment* seg = 0;
|
||||||
|
if (!m_nsegs)
|
||||||
|
{
|
||||||
|
// First, trivial accept.
|
||||||
|
seg = &m_segs[0];
|
||||||
|
}
|
||||||
|
else if (dist >= m_segs[m_nsegs-1].d)
|
||||||
|
{
|
||||||
|
// Further than the last segment, skip.
|
||||||
|
if (m_nsegs >= MAX_LOCAL_SEGS)
|
||||||
|
return;
|
||||||
|
// Last, trivial accept.
|
||||||
|
seg = &m_segs[m_nsegs];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Insert inbetween.
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < m_nsegs; ++i)
|
||||||
|
if (dist <= m_segs[i].d)
|
||||||
|
break;
|
||||||
|
const int tgt = i+1;
|
||||||
|
const int n = dtMin(m_nsegs-i, MAX_LOCAL_SEGS-tgt);
|
||||||
|
dtAssert(tgt+n <= MAX_LOCAL_SEGS);
|
||||||
|
if (n > 0)
|
||||||
|
memmove(&m_segs[tgt], &m_segs[i], sizeof(Segment)*n);
|
||||||
|
seg = &m_segs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
seg->d = dist;
|
||||||
|
memcpy(seg->s, s, sizeof(float)*6);
|
||||||
|
|
||||||
|
if (m_nsegs < MAX_LOCAL_SEGS)
|
||||||
|
m_nsegs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtLocalBoundary::update(dtPolyRef ref, const float* pos, const float collisionQueryRange,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
|
{
|
||||||
|
static const int MAX_SEGS_PER_POLY = DT_VERTS_PER_POLYGON*3;
|
||||||
|
|
||||||
|
if (!ref)
|
||||||
|
{
|
||||||
|
dtVset(m_center, FLT_MAX,FLT_MAX,FLT_MAX);
|
||||||
|
m_nsegs = 0;
|
||||||
|
m_npolys = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtVcopy(m_center, pos);
|
||||||
|
|
||||||
|
// First query non-overlapping polygons.
|
||||||
|
navquery->findLocalNeighbourhood(ref, pos, collisionQueryRange,
|
||||||
|
filter, m_polys, 0, &m_npolys, MAX_LOCAL_POLYS);
|
||||||
|
|
||||||
|
// Secondly, store all polygon edges.
|
||||||
|
m_nsegs = 0;
|
||||||
|
float segs[MAX_SEGS_PER_POLY*6];
|
||||||
|
int nsegs = 0;
|
||||||
|
for (int j = 0; j < m_npolys; ++j)
|
||||||
|
{
|
||||||
|
navquery->getPolyWallSegments(m_polys[j], filter, segs, 0, &nsegs, MAX_SEGS_PER_POLY);
|
||||||
|
for (int k = 0; k < nsegs; ++k)
|
||||||
|
{
|
||||||
|
const float* s = &segs[k*6];
|
||||||
|
// Skip too distant segments.
|
||||||
|
float tseg;
|
||||||
|
const float distSqr = dtDistancePtSegSqr2D(pos, s, s+3, tseg);
|
||||||
|
if (distSqr > dtSqr(collisionQueryRange))
|
||||||
|
continue;
|
||||||
|
addSegment(distSqr, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dtLocalBoundary::isValid(dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
|
{
|
||||||
|
if (!m_npolys)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check that all polygons still pass query filter.
|
||||||
|
for (int i = 0; i < m_npolys; ++i)
|
||||||
|
{
|
||||||
|
if (!navquery->isValidPolyRef(m_polys[i], filter))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -18,13 +18,14 @@
|
||||||
|
|
||||||
#include "DetourObstacleAvoidance.h"
|
#include "DetourObstacleAvoidance.h"
|
||||||
#include "DetourCommon.h"
|
#include "DetourCommon.h"
|
||||||
|
#include "DetourMath.h"
|
||||||
#include "DetourAlloc.h"
|
#include "DetourAlloc.h"
|
||||||
#include "DetourAssert.h"
|
#include "DetourAssert.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
|
static const float DT_PI = 3.14159265f;
|
||||||
|
|
||||||
static int sweepCircleCircle(const float* c0, const float r0, const float* v,
|
static int sweepCircleCircle(const float* c0, const float r0, const float* v,
|
||||||
const float* c1, const float r1,
|
const float* c1, const float r1,
|
||||||
|
|
@ -57,7 +58,7 @@ static int isectRaySeg(const float* ap, const float* u,
|
||||||
dtVsub(v,bq,bp);
|
dtVsub(v,bq,bp);
|
||||||
dtVsub(w,ap,bp);
|
dtVsub(w,ap,bp);
|
||||||
float d = dtVperp2D(u,v);
|
float d = dtVperp2D(u,v);
|
||||||
if (fabsf(d) < 1e-6f) return 0;
|
if (dtMathFabs(d) < 1e-6f) return 0;
|
||||||
d = 1.0f/d;
|
d = 1.0f/d;
|
||||||
t = dtVperp2D(v,w) * d;
|
t = dtVperp2D(v,w) * d;
|
||||||
if (t < 0 || t > 1) return 0;
|
if (t < 0 || t > 1) return 0;
|
||||||
|
|
@ -206,12 +207,6 @@ void dtFreeObstacleAvoidanceQuery(dtObstacleAvoidanceQuery* ptr)
|
||||||
|
|
||||||
|
|
||||||
dtObstacleAvoidanceQuery::dtObstacleAvoidanceQuery() :
|
dtObstacleAvoidanceQuery::dtObstacleAvoidanceQuery() :
|
||||||
m_velBias(0.0f),
|
|
||||||
m_weightDesVel(0.0f),
|
|
||||||
m_weightCurVel(0.0f),
|
|
||||||
m_weightSide(0.0f),
|
|
||||||
m_weightToi(0.0f),
|
|
||||||
m_horizTime(0.0f),
|
|
||||||
m_maxCircles(0),
|
m_maxCircles(0),
|
||||||
m_circles(0),
|
m_circles(0),
|
||||||
m_ncircles(0),
|
m_ncircles(0),
|
||||||
|
|
@ -318,11 +313,11 @@ void dtObstacleAvoidanceQuery::prepare(const float* pos, const float* dvel)
|
||||||
|
|
||||||
float dtObstacleAvoidanceQuery::processSample(const float* vcand, const float cs,
|
float dtObstacleAvoidanceQuery::processSample(const float* vcand, const float cs,
|
||||||
const float* pos, const float rad,
|
const float* pos, const float rad,
|
||||||
const float vmax, const float* vel, const float* dvel,
|
const float* vel, const float* dvel,
|
||||||
dtObstacleAvoidanceDebugData* debug)
|
dtObstacleAvoidanceDebugData* debug)
|
||||||
{
|
{
|
||||||
// Find min time of impact and exit amongst all obstacles.
|
// Find min time of impact and exit amongst all obstacles.
|
||||||
float tmin = m_horizTime;
|
float tmin = m_params.horizTime;
|
||||||
float side = 0;
|
float side = 0;
|
||||||
int nside = 0;
|
int nside = 0;
|
||||||
|
|
||||||
|
|
@ -395,11 +390,10 @@ float dtObstacleAvoidanceQuery::processSample(const float* vcand, const float cs
|
||||||
if (nside)
|
if (nside)
|
||||||
side /= nside;
|
side /= nside;
|
||||||
|
|
||||||
const float ivmax = 1.0f / vmax;
|
const float vpen = m_params.weightDesVel * (dtVdist2D(vcand, dvel) * m_invVmax);
|
||||||
const float vpen = m_weightDesVel * (dtVdist2D(vcand, dvel) * ivmax);
|
const float vcpen = m_params.weightCurVel * (dtVdist2D(vcand, vel) * m_invVmax);
|
||||||
const float vcpen = m_weightCurVel * (dtVdist2D(vcand, vel) * ivmax);
|
const float spen = m_params.weightSide * side;
|
||||||
const float spen = m_weightSide * side;
|
const float tpen = m_params.weightToi * (1.0f/(0.1f+tmin*m_invHorizTime));
|
||||||
const float tpen = m_weightToi * (1.0f/(0.1f+tmin / m_horizTime));
|
|
||||||
|
|
||||||
const float penalty = vpen + vcpen + spen + tpen;
|
const float penalty = vpen + vcpen + spen + tpen;
|
||||||
|
|
||||||
|
|
@ -410,28 +404,34 @@ float dtObstacleAvoidanceQuery::processSample(const float* vcand, const float cs
|
||||||
return penalty;
|
return penalty;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dtObstacleAvoidanceQuery::sampleVelocityGrid(const float* pos, const float rad, const float vmax,
|
int dtObstacleAvoidanceQuery::sampleVelocityGrid(const float* pos, const float rad, const float vmax,
|
||||||
const float* vel, const float* dvel,
|
const float* vel, const float* dvel, float* nvel,
|
||||||
float* nvel, const int gsize,
|
const dtObstacleAvoidanceParams* params,
|
||||||
dtObstacleAvoidanceDebugData* debug)
|
dtObstacleAvoidanceDebugData* debug)
|
||||||
{
|
{
|
||||||
prepare(pos, dvel);
|
prepare(pos, dvel);
|
||||||
|
|
||||||
|
memcpy(&m_params, params, sizeof(dtObstacleAvoidanceParams));
|
||||||
|
m_invHorizTime = 1.0f / m_params.horizTime;
|
||||||
|
m_vmax = vmax;
|
||||||
|
m_invVmax = 1.0f / vmax;
|
||||||
|
|
||||||
dtVset(nvel, 0,0,0);
|
dtVset(nvel, 0,0,0);
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
debug->reset();
|
debug->reset();
|
||||||
|
|
||||||
const float cvx = dvel[0] * m_velBias;
|
const float cvx = dvel[0] * m_params.velBias;
|
||||||
const float cvz = dvel[2] * m_velBias;
|
const float cvz = dvel[2] * m_params.velBias;
|
||||||
const float cs = vmax * 2 * (1 - m_velBias) / (float)(gsize-1);
|
const float cs = vmax * 2 * (1 - m_params.velBias) / (float)(m_params.gridSize-1);
|
||||||
const float half = (gsize-1)*cs*0.5f;
|
const float half = (m_params.gridSize-1)*cs*0.5f;
|
||||||
|
|
||||||
float minPenalty = FLT_MAX;
|
float minPenalty = FLT_MAX;
|
||||||
|
int ns = 0;
|
||||||
|
|
||||||
for (int y = 0; y < gsize; ++y)
|
for (int y = 0; y < m_params.gridSize; ++y)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < gsize; ++x)
|
for (int x = 0; x < m_params.gridSize; ++x)
|
||||||
{
|
{
|
||||||
float vcand[3];
|
float vcand[3];
|
||||||
vcand[0] = cvx + x*cs - half;
|
vcand[0] = cvx + x*cs - half;
|
||||||
|
|
@ -440,7 +440,8 @@ void dtObstacleAvoidanceQuery::sampleVelocityGrid(const float* pos, const float
|
||||||
|
|
||||||
if (dtSqr(vcand[0])+dtSqr(vcand[2]) > dtSqr(vmax+cs/2)) continue;
|
if (dtSqr(vcand[0])+dtSqr(vcand[2]) > dtSqr(vmax+cs/2)) continue;
|
||||||
|
|
||||||
const float penalty = processSample(vcand, cs, pos,rad,vmax,vel,dvel, debug);
|
const float penalty = processSample(vcand, cs, pos,rad,vel,dvel, debug);
|
||||||
|
ns++;
|
||||||
if (penalty < minPenalty)
|
if (penalty < minPenalty)
|
||||||
{
|
{
|
||||||
minPenalty = penalty;
|
minPenalty = penalty;
|
||||||
|
|
@ -448,33 +449,40 @@ void dtObstacleAvoidanceQuery::sampleVelocityGrid(const float* pos, const float
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const float DT_PI = 3.14159265f;
|
int dtObstacleAvoidanceQuery::sampleVelocityAdaptive(const float* pos, const float rad, const float vmax,
|
||||||
|
|
||||||
void dtObstacleAvoidanceQuery::sampleVelocityAdaptive(const float* pos, const float rad, const float vmax,
|
|
||||||
const float* vel, const float* dvel, float* nvel,
|
const float* vel, const float* dvel, float* nvel,
|
||||||
const int ndivs, const int nrings, const int depth,
|
const dtObstacleAvoidanceParams* params,
|
||||||
dtObstacleAvoidanceDebugData* debug)
|
dtObstacleAvoidanceDebugData* debug)
|
||||||
{
|
{
|
||||||
prepare(pos, dvel);
|
prepare(pos, dvel);
|
||||||
|
|
||||||
|
memcpy(&m_params, params, sizeof(dtObstacleAvoidanceParams));
|
||||||
|
m_invHorizTime = 1.0f / m_params.horizTime;
|
||||||
|
m_vmax = vmax;
|
||||||
|
m_invVmax = 1.0f / vmax;
|
||||||
|
|
||||||
dtVset(nvel, 0,0,0);
|
dtVset(nvel, 0,0,0);
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
debug->reset();
|
debug->reset();
|
||||||
|
|
||||||
// Build sampling pattern aligned to desired velocity.
|
// Build sampling pattern aligned to desired velocity.
|
||||||
static const int MAX_PATTERN_DIVS = 32;
|
float pat[(DT_MAX_PATTERN_DIVS*DT_MAX_PATTERN_RINGS+1)*2];
|
||||||
static const int MAX_PATTERN_RINGS = 4;
|
|
||||||
float pat[(MAX_PATTERN_DIVS*MAX_PATTERN_RINGS+1)*2];
|
|
||||||
int npat = 0;
|
int npat = 0;
|
||||||
|
|
||||||
const int nd = dtClamp(ndivs, 1, MAX_PATTERN_DIVS);
|
const int ndivs = (int)m_params.adaptiveDivs;
|
||||||
const int nr = dtClamp(nrings, 1, MAX_PATTERN_RINGS);
|
const int nrings= (int)m_params.adaptiveRings;
|
||||||
|
const int depth = (int)m_params.adaptiveDepth;
|
||||||
|
|
||||||
|
const int nd = dtClamp(ndivs, 1, DT_MAX_PATTERN_DIVS);
|
||||||
|
const int nr = dtClamp(nrings, 1, DT_MAX_PATTERN_RINGS);
|
||||||
const float da = (1.0f/nd) * DT_PI*2;
|
const float da = (1.0f/nd) * DT_PI*2;
|
||||||
const float dang = atan2f(dvel[2], dvel[0]);
|
const float dang = dtMathAtan2f(dvel[2], dvel[0]);
|
||||||
|
|
||||||
// Always add sample at zero
|
// Always add sample at zero
|
||||||
pat[npat*2+0] = 0;
|
pat[npat*2+0] = 0;
|
||||||
|
|
@ -483,21 +491,22 @@ void dtObstacleAvoidanceQuery::sampleVelocityAdaptive(const float* pos, const fl
|
||||||
|
|
||||||
for (int j = 0; j < nr; ++j)
|
for (int j = 0; j < nr; ++j)
|
||||||
{
|
{
|
||||||
const float rad = (float)(nr-j)/(float)nr;
|
const float r = (float)(nr-j)/(float)nr;
|
||||||
float a = dang + (j&1)*0.5f*da;
|
float a = dang + (j&1)*0.5f*da;
|
||||||
for (int i = 0; i < nd; ++i)
|
for (int i = 0; i < nd; ++i)
|
||||||
{
|
{
|
||||||
pat[npat*2+0] = cosf(a)*rad;
|
pat[npat*2+0] = cosf(a)*r;
|
||||||
pat[npat*2+1] = sinf(a)*rad;
|
pat[npat*2+1] = sinf(a)*r;
|
||||||
npat++;
|
npat++;
|
||||||
a += da;
|
a += da;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start sampling.
|
// Start sampling.
|
||||||
float cr = vmax * (1.0f-m_velBias);
|
float cr = vmax * (1.0f - m_params.velBias);
|
||||||
float res[3];
|
float res[3];
|
||||||
dtVset(res, dvel[0] * m_velBias, 0, dvel[2] * m_velBias);
|
dtVset(res, dvel[0] * m_params.velBias, 0, dvel[2] * m_params.velBias);
|
||||||
|
int ns = 0;
|
||||||
|
|
||||||
for (int k = 0; k < depth; ++k)
|
for (int k = 0; k < depth; ++k)
|
||||||
{
|
{
|
||||||
|
|
@ -514,7 +523,8 @@ void dtObstacleAvoidanceQuery::sampleVelocityAdaptive(const float* pos, const fl
|
||||||
|
|
||||||
if (dtSqr(vcand[0])+dtSqr(vcand[2]) > dtSqr(vmax+0.001f)) continue;
|
if (dtSqr(vcand[0])+dtSqr(vcand[2]) > dtSqr(vmax+0.001f)) continue;
|
||||||
|
|
||||||
const float penalty = processSample(vcand,cr/10, pos,rad,vmax,vel,dvel, debug);
|
const float penalty = processSample(vcand,cr/10, pos,rad,vel,dvel, debug);
|
||||||
|
ns++;
|
||||||
if (penalty < minPenalty)
|
if (penalty < minPenalty)
|
||||||
{
|
{
|
||||||
minPenalty = penalty;
|
minPenalty = penalty;
|
||||||
|
|
@ -528,5 +538,7 @@ void dtObstacleAvoidanceQuery::sampleVelocityAdaptive(const float* pos, const fl
|
||||||
}
|
}
|
||||||
|
|
||||||
dtVcopy(nvel, res);
|
dtVcopy(nvel, res);
|
||||||
|
|
||||||
|
return ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
597
dep/recastnavigation/DetourCrowd/Source/DetourPathCorridor.cpp
Normal file
597
dep/recastnavigation/DetourCrowd/Source/DetourPathCorridor.cpp
Normal file
|
|
@ -0,0 +1,597 @@
|
||||||
|
//
|
||||||
|
// 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 "DetourPathCorridor.h"
|
||||||
|
#include "DetourNavMeshQuery.h"
|
||||||
|
#include "DetourCommon.h"
|
||||||
|
#include "DetourAssert.h"
|
||||||
|
#include "DetourAlloc.h"
|
||||||
|
|
||||||
|
|
||||||
|
int dtMergeCorridorStartMoved(dtPolyRef* path, const int npath, const int maxPath,
|
||||||
|
const dtPolyRef* visited, const int nvisited)
|
||||||
|
{
|
||||||
|
int furthestPath = -1;
|
||||||
|
int furthestVisited = -1;
|
||||||
|
|
||||||
|
// Find furthest common polygon.
|
||||||
|
for (int i = npath-1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
for (int j = nvisited-1; j >= 0; --j)
|
||||||
|
{
|
||||||
|
if (path[i] == visited[j])
|
||||||
|
{
|
||||||
|
furthestPath = i;
|
||||||
|
furthestVisited = j;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no intersection found just return current path.
|
||||||
|
if (furthestPath == -1 || furthestVisited == -1)
|
||||||
|
return npath;
|
||||||
|
|
||||||
|
// Concatenate paths.
|
||||||
|
|
||||||
|
// Adjust beginning of the buffer to include the visited.
|
||||||
|
const int req = nvisited - furthestVisited;
|
||||||
|
const int orig = dtMin(furthestPath+1, npath);
|
||||||
|
int size = dtMax(0, npath-orig);
|
||||||
|
if (req+size > maxPath)
|
||||||
|
size = maxPath-req;
|
||||||
|
if (size)
|
||||||
|
memmove(path+req, path+orig, size*sizeof(dtPolyRef));
|
||||||
|
|
||||||
|
// Store visited
|
||||||
|
for (int i = 0; i < req; ++i)
|
||||||
|
path[i] = visited[(nvisited-1)-i];
|
||||||
|
|
||||||
|
return req+size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dtMergeCorridorEndMoved(dtPolyRef* path, const int npath, const int maxPath,
|
||||||
|
const dtPolyRef* visited, const int nvisited)
|
||||||
|
{
|
||||||
|
int furthestPath = -1;
|
||||||
|
int furthestVisited = -1;
|
||||||
|
|
||||||
|
// Find furthest common polygon.
|
||||||
|
for (int i = 0; i < npath; ++i)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
for (int j = nvisited-1; j >= 0; --j)
|
||||||
|
{
|
||||||
|
if (path[i] == visited[j])
|
||||||
|
{
|
||||||
|
furthestPath = i;
|
||||||
|
furthestVisited = j;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no intersection found just return current path.
|
||||||
|
if (furthestPath == -1 || furthestVisited == -1)
|
||||||
|
return npath;
|
||||||
|
|
||||||
|
// Concatenate paths.
|
||||||
|
const int ppos = furthestPath+1;
|
||||||
|
const int vpos = furthestVisited+1;
|
||||||
|
const int count = dtMin(nvisited-vpos, maxPath-ppos);
|
||||||
|
dtAssert(ppos+count <= maxPath);
|
||||||
|
if (count)
|
||||||
|
memcpy(path+ppos, visited+vpos, sizeof(dtPolyRef)*count);
|
||||||
|
|
||||||
|
return ppos+count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dtMergeCorridorStartShortcut(dtPolyRef* path, const int npath, const int maxPath,
|
||||||
|
const dtPolyRef* visited, const int nvisited)
|
||||||
|
{
|
||||||
|
int furthestPath = -1;
|
||||||
|
int furthestVisited = -1;
|
||||||
|
|
||||||
|
// Find furthest common polygon.
|
||||||
|
for (int i = npath-1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
for (int j = nvisited-1; j >= 0; --j)
|
||||||
|
{
|
||||||
|
if (path[i] == visited[j])
|
||||||
|
{
|
||||||
|
furthestPath = i;
|
||||||
|
furthestVisited = j;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no intersection found just return current path.
|
||||||
|
if (furthestPath == -1 || furthestVisited == -1)
|
||||||
|
return npath;
|
||||||
|
|
||||||
|
// Concatenate paths.
|
||||||
|
|
||||||
|
// Adjust beginning of the buffer to include the visited.
|
||||||
|
const int req = furthestVisited;
|
||||||
|
if (req <= 0)
|
||||||
|
return npath;
|
||||||
|
|
||||||
|
const int orig = furthestPath;
|
||||||
|
int size = dtMax(0, npath-orig);
|
||||||
|
if (req+size > maxPath)
|
||||||
|
size = maxPath-req;
|
||||||
|
if (size)
|
||||||
|
memmove(path+req, path+orig, size*sizeof(dtPolyRef));
|
||||||
|
|
||||||
|
// Store visited
|
||||||
|
for (int i = 0; i < req; ++i)
|
||||||
|
path[i] = visited[i];
|
||||||
|
|
||||||
|
return req+size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@class dtPathCorridor
|
||||||
|
@par
|
||||||
|
|
||||||
|
The corridor is loaded with a path, usually obtained from a #dtNavMeshQuery::findPath() query. The corridor
|
||||||
|
is then used to plan local movement, with the corridor automatically updating as needed to deal with inaccurate
|
||||||
|
agent locomotion.
|
||||||
|
|
||||||
|
Example of a common use case:
|
||||||
|
|
||||||
|
-# Construct the corridor object and call #init() to allocate its path buffer.
|
||||||
|
-# Obtain a path from a #dtNavMeshQuery object.
|
||||||
|
-# Use #reset() to set the agent's current position. (At the beginning of the path.)
|
||||||
|
-# Use #setCorridor() to load the path and target.
|
||||||
|
-# Use #findCorners() to plan movement. (This handles dynamic path straightening.)
|
||||||
|
-# Use #movePosition() to feed agent movement back into the corridor. (The corridor will automatically adjust as needed.)
|
||||||
|
-# If the target is moving, use #moveTargetPosition() to update the end of the corridor.
|
||||||
|
(The corridor will automatically adjust as needed.)
|
||||||
|
-# Repeat the previous 3 steps to continue to move the agent.
|
||||||
|
|
||||||
|
The corridor position and target are always constrained to the navigation mesh.
|
||||||
|
|
||||||
|
One of the difficulties in maintaining a path is that floating point errors, locomotion inaccuracies, and/or local
|
||||||
|
steering can result in the agent crossing the boundary of the path corridor, temporarily invalidating the path.
|
||||||
|
This class uses local mesh queries to detect and update the corridor as needed to handle these types of issues.
|
||||||
|
|
||||||
|
The fact that local mesh queries are used to move the position and target locations results in two beahviors that
|
||||||
|
need to be considered:
|
||||||
|
|
||||||
|
Every time a move function is used there is a chance that the path will become non-optimial. Basically, the further
|
||||||
|
the target is moved from its original location, and the further the position is moved outside the original corridor,
|
||||||
|
the more likely the path will become non-optimal. This issue can be addressed by periodically running the
|
||||||
|
#optimizePathTopology() and #optimizePathVisibility() methods.
|
||||||
|
|
||||||
|
All local mesh queries have distance limitations. (Review the #dtNavMeshQuery methods for details.) So the most accurate
|
||||||
|
use case is to move the position and target in small increments. If a large increment is used, then the corridor
|
||||||
|
may not be able to accurately find the new location. Because of this limiation, if a position is moved in a large
|
||||||
|
increment, then compare the desired and resulting polygon references. If the two do not match, then path replanning
|
||||||
|
may be needed. E.g. If you move the target, check #getLastPoly() to see if it is the expected polygon.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
dtPathCorridor::dtPathCorridor() :
|
||||||
|
m_path(0),
|
||||||
|
m_npath(0),
|
||||||
|
m_maxPath(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
dtPathCorridor::~dtPathCorridor()
|
||||||
|
{
|
||||||
|
dtFree(m_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// @warning Cannot be called more than once.
|
||||||
|
bool dtPathCorridor::init(const int maxPath)
|
||||||
|
{
|
||||||
|
dtAssert(!m_path);
|
||||||
|
m_path = (dtPolyRef*)dtAlloc(sizeof(dtPolyRef)*maxPath, DT_ALLOC_PERM);
|
||||||
|
if (!m_path)
|
||||||
|
return false;
|
||||||
|
m_npath = 0;
|
||||||
|
m_maxPath = maxPath;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// Essentially, the corridor is set of one polygon in size with the target
|
||||||
|
/// equal to the position.
|
||||||
|
void dtPathCorridor::reset(dtPolyRef ref, const float* pos)
|
||||||
|
{
|
||||||
|
dtAssert(m_path);
|
||||||
|
dtVcopy(m_pos, pos);
|
||||||
|
dtVcopy(m_target, pos);
|
||||||
|
m_path[0] = ref;
|
||||||
|
m_npath = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@par
|
||||||
|
|
||||||
|
This is the function used to plan local movement within the corridor. One or more corners can be
|
||||||
|
detected in order to plan movement. It performs essentially the same function as #dtNavMeshQuery::findStraightPath.
|
||||||
|
|
||||||
|
Due to internal optimizations, the maximum number of corners returned will be (@p maxCorners - 1)
|
||||||
|
For example: If the buffers are sized to hold 10 corners, the function will never return more than 9 corners.
|
||||||
|
So if 10 corners are needed, the buffers should be sized for 11 corners.
|
||||||
|
|
||||||
|
If the target is within range, it will be the last corner and have a polygon reference id of zero.
|
||||||
|
*/
|
||||||
|
int dtPathCorridor::findCorners(float* cornerVerts, unsigned char* cornerFlags,
|
||||||
|
dtPolyRef* cornerPolys, const int maxCorners,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* /*filter*/)
|
||||||
|
{
|
||||||
|
dtAssert(m_path);
|
||||||
|
dtAssert(m_npath);
|
||||||
|
|
||||||
|
static const float MIN_TARGET_DIST = 0.01f;
|
||||||
|
|
||||||
|
int ncorners = 0;
|
||||||
|
navquery->findStraightPath(m_pos, m_target, m_path, m_npath,
|
||||||
|
cornerVerts, cornerFlags, cornerPolys, &ncorners, maxCorners);
|
||||||
|
|
||||||
|
// Prune points in the beginning of the path which are too close.
|
||||||
|
while (ncorners)
|
||||||
|
{
|
||||||
|
if ((cornerFlags[0] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) ||
|
||||||
|
dtVdist2DSqr(&cornerVerts[0], m_pos) > dtSqr(MIN_TARGET_DIST))
|
||||||
|
break;
|
||||||
|
ncorners--;
|
||||||
|
if (ncorners)
|
||||||
|
{
|
||||||
|
memmove(cornerFlags, cornerFlags+1, sizeof(unsigned char)*ncorners);
|
||||||
|
memmove(cornerPolys, cornerPolys+1, sizeof(dtPolyRef)*ncorners);
|
||||||
|
memmove(cornerVerts, cornerVerts+3, sizeof(float)*3*ncorners);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prune points after an off-mesh connection.
|
||||||
|
for (int i = 0; i < ncorners; ++i)
|
||||||
|
{
|
||||||
|
if (cornerFlags[i] & DT_STRAIGHTPATH_OFFMESH_CONNECTION)
|
||||||
|
{
|
||||||
|
ncorners = i+1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ncorners;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@par
|
||||||
|
|
||||||
|
Inaccurate locomotion or dynamic obstacle avoidance can force the argent position significantly outside the
|
||||||
|
original corridor. Over time this can result in the formation of a non-optimal corridor. Non-optimal paths can
|
||||||
|
also form near the corners of tiles.
|
||||||
|
|
||||||
|
This function uses an efficient local visibility search to try to optimize the corridor
|
||||||
|
between the current position and @p next.
|
||||||
|
|
||||||
|
The corridor will change only if @p next is visible from the current position and moving directly toward the point
|
||||||
|
is better than following the existing path.
|
||||||
|
|
||||||
|
The more inaccurate the agent movement, the more beneficial this function becomes. Simply adjust the frequency
|
||||||
|
of the call to match the needs to the agent.
|
||||||
|
|
||||||
|
This function is not suitable for long distance searches.
|
||||||
|
*/
|
||||||
|
void dtPathCorridor::optimizePathVisibility(const float* next, const float pathOptimizationRange,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
|
{
|
||||||
|
dtAssert(m_path);
|
||||||
|
|
||||||
|
// Clamp the ray to max distance.
|
||||||
|
float goal[3];
|
||||||
|
dtVcopy(goal, next);
|
||||||
|
float dist = dtVdist2D(m_pos, goal);
|
||||||
|
|
||||||
|
// If too close to the goal, do not try to optimize.
|
||||||
|
if (dist < 0.01f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Overshoot a little. This helps to optimize open fields in tiled meshes.
|
||||||
|
dist = dtMin(dist+0.01f, pathOptimizationRange);
|
||||||
|
|
||||||
|
// Adjust ray length.
|
||||||
|
float delta[3];
|
||||||
|
dtVsub(delta, goal, m_pos);
|
||||||
|
dtVmad(goal, m_pos, delta, pathOptimizationRange/dist);
|
||||||
|
|
||||||
|
static const int MAX_RES = 32;
|
||||||
|
dtPolyRef res[MAX_RES];
|
||||||
|
float t, norm[3];
|
||||||
|
int nres = 0;
|
||||||
|
navquery->raycast(m_path[0], m_pos, goal, filter, &t, norm, res, &nres, MAX_RES);
|
||||||
|
if (nres > 1 && t > 0.99f)
|
||||||
|
{
|
||||||
|
m_npath = dtMergeCorridorStartShortcut(m_path, m_npath, m_maxPath, res, nres);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@par
|
||||||
|
|
||||||
|
Inaccurate locomotion or dynamic obstacle avoidance can force the agent position significantly outside the
|
||||||
|
original corridor. Over time this can result in the formation of a non-optimal corridor. This function will use a
|
||||||
|
local area path search to try to re-optimize the corridor.
|
||||||
|
|
||||||
|
The more inaccurate the agent movement, the more beneficial this function becomes. Simply adjust the frequency of
|
||||||
|
the call to match the needs to the agent.
|
||||||
|
*/
|
||||||
|
bool dtPathCorridor::optimizePathTopology(dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
|
{
|
||||||
|
dtAssert(navquery);
|
||||||
|
dtAssert(filter);
|
||||||
|
dtAssert(m_path);
|
||||||
|
|
||||||
|
if (m_npath < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
static const int MAX_ITER = 32;
|
||||||
|
static const int MAX_RES = 32;
|
||||||
|
|
||||||
|
dtPolyRef res[MAX_RES];
|
||||||
|
int nres = 0;
|
||||||
|
navquery->initSlicedFindPath(m_path[0], m_path[m_npath-1], m_pos, m_target, filter);
|
||||||
|
navquery->updateSlicedFindPath(MAX_ITER, 0);
|
||||||
|
dtStatus status = navquery->finalizeSlicedFindPathPartial(m_path, m_npath, res, &nres, MAX_RES);
|
||||||
|
|
||||||
|
if (dtStatusSucceed(status) && nres > 0)
|
||||||
|
{
|
||||||
|
m_npath = dtMergeCorridorStartShortcut(m_path, m_npath, m_maxPath, res, nres);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dtPathCorridor::moveOverOffmeshConnection(dtPolyRef offMeshConRef, dtPolyRef* refs,
|
||||||
|
float* startPos, float* endPos,
|
||||||
|
dtNavMeshQuery* navquery)
|
||||||
|
{
|
||||||
|
dtAssert(navquery);
|
||||||
|
dtAssert(m_path);
|
||||||
|
dtAssert(m_npath);
|
||||||
|
|
||||||
|
// Advance the path up to and over the off-mesh connection.
|
||||||
|
dtPolyRef prevRef = 0, polyRef = m_path[0];
|
||||||
|
int npos = 0;
|
||||||
|
while (npos < m_npath && polyRef != offMeshConRef)
|
||||||
|
{
|
||||||
|
prevRef = polyRef;
|
||||||
|
polyRef = m_path[npos];
|
||||||
|
npos++;
|
||||||
|
}
|
||||||
|
if (npos == m_npath)
|
||||||
|
{
|
||||||
|
// Could not find offMeshConRef
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prune path
|
||||||
|
for (int i = npos; i < m_npath; ++i)
|
||||||
|
m_path[i-npos] = m_path[i];
|
||||||
|
m_npath -= npos;
|
||||||
|
|
||||||
|
refs[0] = prevRef;
|
||||||
|
refs[1] = polyRef;
|
||||||
|
|
||||||
|
const dtNavMesh* nav = navquery->getAttachedNavMesh();
|
||||||
|
dtAssert(nav);
|
||||||
|
|
||||||
|
dtStatus status = nav->getOffMeshConnectionPolyEndPoints(refs[0], refs[1], startPos, endPos);
|
||||||
|
if (dtStatusSucceed(status))
|
||||||
|
{
|
||||||
|
dtVcopy(m_pos, endPos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@par
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
- The movement is constrained to the surface of the navigation mesh.
|
||||||
|
- The corridor is automatically adjusted (shorted or lengthened) in order to remain valid.
|
||||||
|
- The new position will be located in the adjusted corridor's first polygon.
|
||||||
|
|
||||||
|
The expected use case is that the desired position will be 'near' the current corridor. What is considered 'near'
|
||||||
|
depends on local polygon density, query search extents, etc.
|
||||||
|
|
||||||
|
The resulting position will differ from the desired position if the desired position is not on the navigation mesh,
|
||||||
|
or it can't be reached using a local search.
|
||||||
|
*/
|
||||||
|
bool dtPathCorridor::movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
|
{
|
||||||
|
dtAssert(m_path);
|
||||||
|
dtAssert(m_npath);
|
||||||
|
|
||||||
|
// Move along navmesh and update new position.
|
||||||
|
float result[3];
|
||||||
|
static const int MAX_VISITED = 16;
|
||||||
|
dtPolyRef visited[MAX_VISITED];
|
||||||
|
int nvisited = 0;
|
||||||
|
dtStatus status = navquery->moveAlongSurface(m_path[0], m_pos, npos, filter,
|
||||||
|
result, visited, &nvisited, MAX_VISITED);
|
||||||
|
if (dtStatusSucceed(status)) {
|
||||||
|
m_npath = dtMergeCorridorStartMoved(m_path, m_npath, m_maxPath, visited, nvisited);
|
||||||
|
|
||||||
|
// Adjust the position to stay on top of the navmesh.
|
||||||
|
float h = m_pos[1];
|
||||||
|
navquery->getPolyHeight(m_path[0], result, &h);
|
||||||
|
result[1] = h;
|
||||||
|
dtVcopy(m_pos, result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@par
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
- The movement is constrained to the surface of the navigation mesh.
|
||||||
|
- The corridor is automatically adjusted (shorted or lengthened) in order to remain valid.
|
||||||
|
- The new target will be located in the adjusted corridor's last polygon.
|
||||||
|
|
||||||
|
The expected use case is that the desired target will be 'near' the current corridor. What is considered 'near' depends on local polygon density, query search extents, etc.
|
||||||
|
|
||||||
|
The resulting target will differ from the desired target if the desired target is not on the navigation mesh, or it can't be reached using a local search.
|
||||||
|
*/
|
||||||
|
bool dtPathCorridor::moveTargetPosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
|
{
|
||||||
|
dtAssert(m_path);
|
||||||
|
dtAssert(m_npath);
|
||||||
|
|
||||||
|
// Move along navmesh and update new position.
|
||||||
|
float result[3];
|
||||||
|
static const int MAX_VISITED = 16;
|
||||||
|
dtPolyRef visited[MAX_VISITED];
|
||||||
|
int nvisited = 0;
|
||||||
|
dtStatus status = navquery->moveAlongSurface(m_path[m_npath-1], m_target, npos, filter,
|
||||||
|
result, visited, &nvisited, MAX_VISITED);
|
||||||
|
if (dtStatusSucceed(status))
|
||||||
|
{
|
||||||
|
m_npath = dtMergeCorridorEndMoved(m_path, m_npath, m_maxPath, visited, nvisited);
|
||||||
|
// TODO: should we do that?
|
||||||
|
// Adjust the position to stay on top of the navmesh.
|
||||||
|
/* float h = m_target[1];
|
||||||
|
navquery->getPolyHeight(m_path[m_npath-1], result, &h);
|
||||||
|
result[1] = h;*/
|
||||||
|
|
||||||
|
dtVcopy(m_target, result);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// The current corridor position is expected to be within the first polygon in the path. The target
|
||||||
|
/// is expected to be in the last polygon.
|
||||||
|
///
|
||||||
|
/// @warning The size of the path must not exceed the size of corridor's path buffer set during #init().
|
||||||
|
void dtPathCorridor::setCorridor(const float* target, const dtPolyRef* path, const int npath)
|
||||||
|
{
|
||||||
|
dtAssert(m_path);
|
||||||
|
dtAssert(npath > 0);
|
||||||
|
dtAssert(npath < m_maxPath);
|
||||||
|
|
||||||
|
dtVcopy(m_target, target);
|
||||||
|
memcpy(m_path, path, sizeof(dtPolyRef)*npath);
|
||||||
|
m_npath = npath;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dtPathCorridor::fixPathStart(dtPolyRef safeRef, const float* safePos)
|
||||||
|
{
|
||||||
|
dtAssert(m_path);
|
||||||
|
|
||||||
|
dtVcopy(m_pos, safePos);
|
||||||
|
if (m_npath < 3 && m_npath > 0)
|
||||||
|
{
|
||||||
|
m_path[2] = m_path[m_npath-1];
|
||||||
|
m_path[0] = safeRef;
|
||||||
|
m_path[1] = 0;
|
||||||
|
m_npath = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_path[0] = safeRef;
|
||||||
|
m_path[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dtPathCorridor::trimInvalidPath(dtPolyRef safeRef, const float* safePos,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
|
{
|
||||||
|
dtAssert(navquery);
|
||||||
|
dtAssert(filter);
|
||||||
|
dtAssert(m_path);
|
||||||
|
|
||||||
|
// Keep valid path as far as possible.
|
||||||
|
int n = 0;
|
||||||
|
while (n < m_npath && navquery->isValidPolyRef(m_path[n], filter)) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == m_npath)
|
||||||
|
{
|
||||||
|
// All valid, no need to fix.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (n == 0)
|
||||||
|
{
|
||||||
|
// The first polyref is bad, use current safe values.
|
||||||
|
dtVcopy(m_pos, safePos);
|
||||||
|
m_path[0] = safeRef;
|
||||||
|
m_npath = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The path is partially usable.
|
||||||
|
m_npath = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp target pos to last poly
|
||||||
|
float tgt[3];
|
||||||
|
dtVcopy(tgt, m_target);
|
||||||
|
navquery->closestPointOnPolyBoundary(m_path[m_npath-1], tgt, m_target);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// The path can be invalidated if there are structural changes to the underlying navigation mesh, or the state of
|
||||||
|
/// a polygon within the path changes resulting in it being filtered out. (E.g. An exclusion or inclusion flag changes.)
|
||||||
|
bool dtPathCorridor::isValid(const int maxLookAhead, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
|
{
|
||||||
|
// Check that all polygons still pass query filter.
|
||||||
|
const int n = dtMin(m_npath, maxLookAhead);
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
if (!navquery->isValidPolyRef(m_path[i], filter))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
200
dep/recastnavigation/DetourCrowd/Source/DetourPathQueue.cpp
Normal file
200
dep/recastnavigation/DetourCrowd/Source/DetourPathQueue.cpp
Normal file
|
|
@ -0,0 +1,200 @@
|
||||||
|
//
|
||||||
|
// 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 "DetourPathQueue.h"
|
||||||
|
#include "DetourNavMesh.h"
|
||||||
|
#include "DetourNavMeshQuery.h"
|
||||||
|
#include "DetourAlloc.h"
|
||||||
|
#include "DetourCommon.h"
|
||||||
|
|
||||||
|
|
||||||
|
dtPathQueue::dtPathQueue() :
|
||||||
|
m_nextHandle(1),
|
||||||
|
m_maxPathSize(0),
|
||||||
|
m_queueHead(0),
|
||||||
|
m_navquery(0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_QUEUE; ++i)
|
||||||
|
m_queue[i].path = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtPathQueue::~dtPathQueue()
|
||||||
|
{
|
||||||
|
purge();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtPathQueue::purge()
|
||||||
|
{
|
||||||
|
dtFreeNavMeshQuery(m_navquery);
|
||||||
|
m_navquery = 0;
|
||||||
|
for (int i = 0; i < MAX_QUEUE; ++i)
|
||||||
|
{
|
||||||
|
dtFree(m_queue[i].path);
|
||||||
|
m_queue[i].path = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dtPathQueue::init(const int maxPathSize, const int maxSearchNodeCount, dtNavMesh* nav)
|
||||||
|
{
|
||||||
|
purge();
|
||||||
|
|
||||||
|
m_navquery = dtAllocNavMeshQuery();
|
||||||
|
if (!m_navquery)
|
||||||
|
return false;
|
||||||
|
if (dtStatusFailed(m_navquery->init(nav, maxSearchNodeCount)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_maxPathSize = maxPathSize;
|
||||||
|
for (int i = 0; i < MAX_QUEUE; ++i)
|
||||||
|
{
|
||||||
|
m_queue[i].ref = DT_PATHQ_INVALID;
|
||||||
|
m_queue[i].path = (dtPolyRef*)dtAlloc(sizeof(dtPolyRef)*m_maxPathSize, DT_ALLOC_PERM);
|
||||||
|
if (!m_queue[i].path)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_queueHead = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtPathQueue::update(const int maxIters)
|
||||||
|
{
|
||||||
|
static const int MAX_KEEP_ALIVE = 2; // in update ticks.
|
||||||
|
|
||||||
|
// Update path request until there is nothing to update
|
||||||
|
// or upto maxIters pathfinder iterations has been consumed.
|
||||||
|
int iterCount = maxIters;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_QUEUE; ++i)
|
||||||
|
{
|
||||||
|
PathQuery& q = m_queue[m_queueHead % MAX_QUEUE];
|
||||||
|
|
||||||
|
// Skip inactive requests.
|
||||||
|
if (q.ref == DT_PATHQ_INVALID)
|
||||||
|
{
|
||||||
|
m_queueHead++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle completed request.
|
||||||
|
if (dtStatusSucceed(q.status) || dtStatusFailed(q.status))
|
||||||
|
{
|
||||||
|
// If the path result has not been read in few frames, free the slot.
|
||||||
|
q.keepAlive++;
|
||||||
|
if (q.keepAlive > MAX_KEEP_ALIVE)
|
||||||
|
{
|
||||||
|
q.ref = DT_PATHQ_INVALID;
|
||||||
|
q.status = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_queueHead++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle query start.
|
||||||
|
if (q.status == 0)
|
||||||
|
{
|
||||||
|
q.status = m_navquery->initSlicedFindPath(q.startRef, q.endRef, q.startPos, q.endPos, q.filter);
|
||||||
|
}
|
||||||
|
// Handle query in progress.
|
||||||
|
if (dtStatusInProgress(q.status))
|
||||||
|
{
|
||||||
|
int iters = 0;
|
||||||
|
q.status = m_navquery->updateSlicedFindPath(iterCount, &iters);
|
||||||
|
iterCount -= iters;
|
||||||
|
}
|
||||||
|
if (dtStatusSucceed(q.status))
|
||||||
|
{
|
||||||
|
q.status = m_navquery->finalizeSlicedFindPath(q.path, &q.npath, m_maxPathSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iterCount <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
m_queueHead++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dtPathQueueRef dtPathQueue::request(dtPolyRef startRef, dtPolyRef endRef,
|
||||||
|
const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter)
|
||||||
|
{
|
||||||
|
// Find empty slot
|
||||||
|
int slot = -1;
|
||||||
|
for (int i = 0; i < MAX_QUEUE; ++i)
|
||||||
|
{
|
||||||
|
if (m_queue[i].ref == DT_PATHQ_INVALID)
|
||||||
|
{
|
||||||
|
slot = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Could not find slot.
|
||||||
|
if (slot == -1)
|
||||||
|
return DT_PATHQ_INVALID;
|
||||||
|
|
||||||
|
dtPathQueueRef ref = m_nextHandle++;
|
||||||
|
if (m_nextHandle == DT_PATHQ_INVALID) m_nextHandle++;
|
||||||
|
|
||||||
|
PathQuery& q = m_queue[slot];
|
||||||
|
q.ref = ref;
|
||||||
|
dtVcopy(q.startPos, startPos);
|
||||||
|
q.startRef = startRef;
|
||||||
|
dtVcopy(q.endPos, endPos);
|
||||||
|
q.endRef = endRef;
|
||||||
|
|
||||||
|
q.status = 0;
|
||||||
|
q.npath = 0;
|
||||||
|
q.filter = filter;
|
||||||
|
q.keepAlive = 0;
|
||||||
|
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtStatus dtPathQueue::getRequestStatus(dtPathQueueRef ref) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_QUEUE; ++i)
|
||||||
|
{
|
||||||
|
if (m_queue[i].ref == ref)
|
||||||
|
return m_queue[i].status;
|
||||||
|
}
|
||||||
|
return DT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtStatus dtPathQueue::getPathResult(dtPathQueueRef ref, dtPolyRef* path, int* pathSize, const int maxPath)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_QUEUE; ++i)
|
||||||
|
{
|
||||||
|
if (m_queue[i].ref == ref)
|
||||||
|
{
|
||||||
|
PathQuery& q = m_queue[i];
|
||||||
|
dtStatus details = q.status & DT_STATUS_DETAIL_MASK;
|
||||||
|
// Free request for reuse.
|
||||||
|
q.ref = DT_PATHQ_INVALID;
|
||||||
|
q.status = 0;
|
||||||
|
// Copy path
|
||||||
|
int n = dtMin(q.npath, maxPath);
|
||||||
|
memcpy(path, q.path, sizeof(dtPolyRef)*n);
|
||||||
|
*pathSize = n;
|
||||||
|
return details | DT_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DT_FAILURE;
|
||||||
|
}
|
||||||
194
dep/recastnavigation/DetourCrowd/Source/DetourProximityGrid.cpp
Normal file
194
dep/recastnavigation/DetourCrowd/Source/DetourProximityGrid.cpp
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
//
|
||||||
|
// 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_maxItems(0),
|
||||||
|
m_cellSize(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;
|
||||||
|
}
|
||||||
212
dep/recastnavigation/DetourTileCache/Include/DetourTileCache.h
Normal file
212
dep/recastnavigation/DetourTileCache/Include/DetourTileCache.h
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
#ifndef DETOURTILECACHE_H
|
||||||
|
#define DETOURTILECACHE_H
|
||||||
|
|
||||||
|
#include "DetourStatus.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef unsigned int dtObstacleRef;
|
||||||
|
|
||||||
|
typedef unsigned int dtCompressedTileRef;
|
||||||
|
|
||||||
|
/// Flags for addTile
|
||||||
|
enum dtCompressedTileFlags
|
||||||
|
{
|
||||||
|
DT_COMPRESSEDTILE_FREE_DATA = 0x01, ///< Navmesh owns the tile memory and should free it.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtCompressedTile
|
||||||
|
{
|
||||||
|
unsigned int salt; ///< Counter describing modifications to the tile.
|
||||||
|
struct dtTileCacheLayerHeader* header;
|
||||||
|
unsigned char* compressed;
|
||||||
|
int compressedSize;
|
||||||
|
unsigned char* data;
|
||||||
|
int dataSize;
|
||||||
|
unsigned int flags;
|
||||||
|
dtCompressedTile* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ObstacleState
|
||||||
|
{
|
||||||
|
DT_OBSTACLE_EMPTY,
|
||||||
|
DT_OBSTACLE_PROCESSING,
|
||||||
|
DT_OBSTACLE_PROCESSED,
|
||||||
|
DT_OBSTACLE_REMOVING,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int DT_MAX_TOUCHED_TILES = 8;
|
||||||
|
struct dtTileCacheObstacle
|
||||||
|
{
|
||||||
|
float pos[3], radius, height;
|
||||||
|
dtCompressedTileRef touched[DT_MAX_TOUCHED_TILES];
|
||||||
|
dtCompressedTileRef pending[DT_MAX_TOUCHED_TILES];
|
||||||
|
unsigned short salt;
|
||||||
|
unsigned char state;
|
||||||
|
unsigned char ntouched;
|
||||||
|
unsigned char npending;
|
||||||
|
dtTileCacheObstacle* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtTileCacheParams
|
||||||
|
{
|
||||||
|
float orig[3];
|
||||||
|
float cs, ch;
|
||||||
|
int width, height;
|
||||||
|
float walkableHeight;
|
||||||
|
float walkableRadius;
|
||||||
|
float walkableClimb;
|
||||||
|
float maxSimplificationError;
|
||||||
|
int maxTiles;
|
||||||
|
int maxObstacles;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtTileCacheMeshProcess
|
||||||
|
{
|
||||||
|
virtual ~dtTileCacheMeshProcess() { }
|
||||||
|
|
||||||
|
virtual void process(struct dtNavMeshCreateParams* params,
|
||||||
|
unsigned char* polyAreas, unsigned short* polyFlags) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class dtTileCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dtTileCache();
|
||||||
|
~dtTileCache();
|
||||||
|
|
||||||
|
struct dtTileCacheAlloc* getAlloc() { return m_talloc; }
|
||||||
|
struct dtTileCacheCompressor* getCompressor() { return m_tcomp; }
|
||||||
|
const dtTileCacheParams* getParams() const { return &m_params; }
|
||||||
|
|
||||||
|
inline int getTileCount() const { return m_params.maxTiles; }
|
||||||
|
inline const dtCompressedTile* getTile(const int i) const { return &m_tiles[i]; }
|
||||||
|
|
||||||
|
inline int getObstacleCount() const { return m_params.maxObstacles; }
|
||||||
|
inline const dtTileCacheObstacle* getObstacle(const int i) const { return &m_obstacles[i]; }
|
||||||
|
|
||||||
|
const dtTileCacheObstacle* getObstacleByRef(dtObstacleRef ref);
|
||||||
|
|
||||||
|
dtObstacleRef getObstacleRef(const dtTileCacheObstacle* obmin) const;
|
||||||
|
|
||||||
|
dtStatus init(const dtTileCacheParams* params,
|
||||||
|
struct dtTileCacheAlloc* talloc,
|
||||||
|
struct dtTileCacheCompressor* tcomp,
|
||||||
|
struct dtTileCacheMeshProcess* tmproc);
|
||||||
|
|
||||||
|
int getTilesAt(const int tx, const int ty, dtCompressedTileRef* tiles, const int maxTiles) const ;
|
||||||
|
|
||||||
|
dtCompressedTile* getTileAt(const int tx, const int ty, const int tlayer);
|
||||||
|
dtCompressedTileRef getTileRef(const dtCompressedTile* tile) const;
|
||||||
|
const dtCompressedTile* getTileByRef(dtCompressedTileRef ref) const;
|
||||||
|
|
||||||
|
dtStatus addTile(unsigned char* data, const int dataSize, unsigned char flags, dtCompressedTileRef* result);
|
||||||
|
|
||||||
|
dtStatus removeTile(dtCompressedTileRef ref, unsigned char** data, int* dataSize);
|
||||||
|
|
||||||
|
dtStatus addObstacle(const float* pos, const float radius, const float height, dtObstacleRef* result);
|
||||||
|
dtStatus removeObstacle(const dtObstacleRef ref);
|
||||||
|
|
||||||
|
dtStatus queryTiles(const float* bmin, const float* bmax,
|
||||||
|
dtCompressedTileRef* results, int* resultCount, const int maxResults) const;
|
||||||
|
|
||||||
|
dtStatus update(const float /*dt*/, class dtNavMesh* navmesh);
|
||||||
|
|
||||||
|
dtStatus buildNavMeshTilesAt(const int tx, const int ty, class dtNavMesh* navmesh);
|
||||||
|
|
||||||
|
dtStatus buildNavMeshTile(const dtCompressedTileRef ref, class dtNavMesh* navmesh);
|
||||||
|
|
||||||
|
void calcTightTileBounds(const struct dtTileCacheLayerHeader* header, float* bmin, float* bmax) const;
|
||||||
|
|
||||||
|
void getObstacleBounds(const struct dtTileCacheObstacle* ob, float* bmin, float* bmax) const;
|
||||||
|
|
||||||
|
|
||||||
|
/// Encodes a tile id.
|
||||||
|
inline dtCompressedTileRef encodeTileId(unsigned int salt, unsigned int it) const
|
||||||
|
{
|
||||||
|
return ((dtCompressedTileRef)salt << m_tileBits) | (dtCompressedTileRef)it;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes a tile salt.
|
||||||
|
inline unsigned int decodeTileIdSalt(dtCompressedTileRef ref) const
|
||||||
|
{
|
||||||
|
const dtCompressedTileRef saltMask = ((dtCompressedTileRef)1<<m_saltBits)-1;
|
||||||
|
return (unsigned int)((ref >> m_tileBits) & saltMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes a tile id.
|
||||||
|
inline unsigned int decodeTileIdTile(dtCompressedTileRef ref) const
|
||||||
|
{
|
||||||
|
const dtCompressedTileRef tileMask = ((dtCompressedTileRef)1<<m_tileBits)-1;
|
||||||
|
return (unsigned int)(ref & tileMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encodes an obstacle id.
|
||||||
|
inline dtObstacleRef encodeObstacleId(unsigned int salt, unsigned int it) const
|
||||||
|
{
|
||||||
|
return ((dtObstacleRef)salt << 16) | (dtObstacleRef)it;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes an obstacle salt.
|
||||||
|
inline unsigned int decodeObstacleIdSalt(dtObstacleRef ref) const
|
||||||
|
{
|
||||||
|
const dtObstacleRef saltMask = ((dtObstacleRef)1<<16)-1;
|
||||||
|
return (unsigned int)((ref >> 16) & saltMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes an obstacle id.
|
||||||
|
inline unsigned int decodeObstacleIdObstacle(dtObstacleRef ref) const
|
||||||
|
{
|
||||||
|
const dtObstacleRef tileMask = ((dtObstacleRef)1<<16)-1;
|
||||||
|
return (unsigned int)(ref & tileMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum ObstacleRequestAction
|
||||||
|
{
|
||||||
|
REQUEST_ADD,
|
||||||
|
REQUEST_REMOVE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObstacleRequest
|
||||||
|
{
|
||||||
|
int action;
|
||||||
|
dtObstacleRef ref;
|
||||||
|
};
|
||||||
|
|
||||||
|
int m_tileLutSize; ///< Tile hash lookup size (must be pot).
|
||||||
|
int m_tileLutMask; ///< Tile hash lookup mask.
|
||||||
|
|
||||||
|
dtCompressedTile** m_posLookup; ///< Tile hash lookup.
|
||||||
|
dtCompressedTile* m_nextFreeTile; ///< Freelist of tiles.
|
||||||
|
dtCompressedTile* m_tiles; ///< List of tiles.
|
||||||
|
|
||||||
|
unsigned int m_saltBits; ///< Number of salt bits in the tile ID.
|
||||||
|
unsigned int m_tileBits; ///< Number of tile bits in the tile ID.
|
||||||
|
|
||||||
|
dtTileCacheParams m_params;
|
||||||
|
|
||||||
|
dtTileCacheAlloc* m_talloc;
|
||||||
|
dtTileCacheCompressor* m_tcomp;
|
||||||
|
dtTileCacheMeshProcess* m_tmproc;
|
||||||
|
|
||||||
|
dtTileCacheObstacle* m_obstacles;
|
||||||
|
dtTileCacheObstacle* m_nextFreeObstacle;
|
||||||
|
|
||||||
|
static const int MAX_REQUESTS = 64;
|
||||||
|
ObstacleRequest m_reqs[MAX_REQUESTS];
|
||||||
|
int m_nreqs;
|
||||||
|
|
||||||
|
static const int MAX_UPDATE = 64;
|
||||||
|
dtCompressedTileRef m_update[MAX_UPDATE];
|
||||||
|
int m_nupdate;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
dtTileCache* dtAllocTileCache();
|
||||||
|
void dtFreeTileCache(dtTileCache* tc);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURTILECACHEBUILDER_H
|
||||||
|
#define DETOURTILECACHEBUILDER_H
|
||||||
|
|
||||||
|
#include "DetourAlloc.h"
|
||||||
|
#include "DetourStatus.h"
|
||||||
|
|
||||||
|
static const int DT_TILECACHE_MAGIC = 'D'<<24 | 'T'<<16 | 'L'<<8 | 'R'; ///< 'DTLR';
|
||||||
|
static const int DT_TILECACHE_VERSION = 1;
|
||||||
|
|
||||||
|
static const unsigned char DT_TILECACHE_NULL_AREA = 0;
|
||||||
|
static const unsigned char DT_TILECACHE_WALKABLE_AREA = 63;
|
||||||
|
static const unsigned short DT_TILECACHE_NULL_IDX = 0xffff;
|
||||||
|
|
||||||
|
struct dtTileCacheLayerHeader
|
||||||
|
{
|
||||||
|
int magic; ///< Data magic
|
||||||
|
int version; ///< Data version
|
||||||
|
int tx,ty,tlayer;
|
||||||
|
float bmin[3], bmax[3];
|
||||||
|
unsigned short hmin, hmax; ///< Height min/max range
|
||||||
|
unsigned char width, height; ///< Dimension of the layer.
|
||||||
|
unsigned char minx, maxx, miny, maxy; ///< Usable sub-region.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtTileCacheLayer
|
||||||
|
{
|
||||||
|
dtTileCacheLayerHeader* header;
|
||||||
|
unsigned char regCount; ///< Region count.
|
||||||
|
unsigned char* heights;
|
||||||
|
unsigned char* areas;
|
||||||
|
unsigned char* cons;
|
||||||
|
unsigned char* regs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtTileCacheContour
|
||||||
|
{
|
||||||
|
int nverts;
|
||||||
|
unsigned char* verts;
|
||||||
|
unsigned char reg;
|
||||||
|
unsigned char area;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtTileCacheContourSet
|
||||||
|
{
|
||||||
|
int nconts;
|
||||||
|
dtTileCacheContour* conts;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtTileCachePolyMesh
|
||||||
|
{
|
||||||
|
int nvp;
|
||||||
|
int nverts; ///< Number of vertices.
|
||||||
|
int npolys; ///< Number of polygons.
|
||||||
|
unsigned short* verts; ///< Vertices of the mesh, 3 elements per vertex.
|
||||||
|
unsigned short* polys; ///< Polygons of the mesh, nvp*2 elements per polygon.
|
||||||
|
unsigned short* flags; ///< Per polygon flags.
|
||||||
|
unsigned char* areas; ///< Area ID of polygons.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct dtTileCacheAlloc
|
||||||
|
{
|
||||||
|
virtual ~dtTileCacheAlloc() { }
|
||||||
|
|
||||||
|
virtual void reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void* alloc(const int size)
|
||||||
|
{
|
||||||
|
return dtAlloc(size, DT_ALLOC_TEMP);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void free(void* ptr)
|
||||||
|
{
|
||||||
|
dtFree(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtTileCacheCompressor
|
||||||
|
{
|
||||||
|
virtual ~dtTileCacheCompressor() { }
|
||||||
|
|
||||||
|
virtual int maxCompressedSize(const int bufferSize) = 0;
|
||||||
|
virtual dtStatus compress(const unsigned char* buffer, const int bufferSize,
|
||||||
|
unsigned char* compressed, const int maxCompressedSize, int* compressedSize) = 0;
|
||||||
|
virtual dtStatus decompress(const unsigned char* compressed, const int compressedSize,
|
||||||
|
unsigned char* buffer, const int maxBufferSize, int* bufferSize) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
dtStatus dtBuildTileCacheLayer(dtTileCacheCompressor* comp,
|
||||||
|
dtTileCacheLayerHeader* header,
|
||||||
|
const unsigned char* heights,
|
||||||
|
const unsigned char* areas,
|
||||||
|
const unsigned char* cons,
|
||||||
|
unsigned char** outData, int* outDataSize);
|
||||||
|
|
||||||
|
void dtFreeTileCacheLayer(dtTileCacheAlloc* alloc, dtTileCacheLayer* layer);
|
||||||
|
|
||||||
|
dtStatus dtDecompressTileCacheLayer(dtTileCacheAlloc* alloc, dtTileCacheCompressor* comp,
|
||||||
|
unsigned char* compressed, const int compressedSize,
|
||||||
|
dtTileCacheLayer** layerOut);
|
||||||
|
|
||||||
|
dtTileCacheContourSet* dtAllocTileCacheContourSet(dtTileCacheAlloc* alloc);
|
||||||
|
void dtFreeTileCacheContourSet(dtTileCacheAlloc* alloc, dtTileCacheContourSet* cset);
|
||||||
|
|
||||||
|
dtTileCachePolyMesh* dtAllocTileCachePolyMesh(dtTileCacheAlloc* alloc);
|
||||||
|
void dtFreeTileCachePolyMesh(dtTileCacheAlloc* alloc, dtTileCachePolyMesh* lmesh);
|
||||||
|
|
||||||
|
dtStatus dtMarkCylinderArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch,
|
||||||
|
const float* pos, const float radius, const float height, const unsigned char areaId);
|
||||||
|
|
||||||
|
dtStatus dtBuildTileCacheRegions(dtTileCacheAlloc* alloc,
|
||||||
|
dtTileCacheLayer& layer,
|
||||||
|
const int walkableClimb);
|
||||||
|
|
||||||
|
dtStatus dtBuildTileCacheContours(dtTileCacheAlloc* alloc,
|
||||||
|
dtTileCacheLayer& layer,
|
||||||
|
const int walkableClimb, const float maxError,
|
||||||
|
dtTileCacheContourSet& lcset);
|
||||||
|
|
||||||
|
dtStatus dtBuildTileCachePolyMesh(dtTileCacheAlloc* alloc,
|
||||||
|
dtTileCacheContourSet& lcset,
|
||||||
|
dtTileCachePolyMesh& mesh);
|
||||||
|
|
||||||
|
/// Swaps the endianess of the compressed tile data's header (#dtTileCacheLayerHeader).
|
||||||
|
/// Tile layer data does not need endian swapping as it consits only of bytes.
|
||||||
|
/// @param[in,out] data The tile data array.
|
||||||
|
/// @param[in] dataSize The size of the data array.
|
||||||
|
bool dtTileCacheHeaderSwapEndian(unsigned char* data, const int dataSize);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DETOURTILECACHEBUILDER_H
|
||||||
704
dep/recastnavigation/DetourTileCache/Source/DetourTileCache.cpp
Normal file
704
dep/recastnavigation/DetourTileCache/Source/DetourTileCache.cpp
Normal file
|
|
@ -0,0 +1,704 @@
|
||||||
|
#include "DetourTileCache.h"
|
||||||
|
#include "DetourTileCacheBuilder.h"
|
||||||
|
#include "DetourNavMeshBuilder.h"
|
||||||
|
#include "DetourNavMesh.h"
|
||||||
|
#include "DetourCommon.h"
|
||||||
|
#include "DetourMath.h"
|
||||||
|
#include "DetourAlloc.h"
|
||||||
|
#include "DetourAssert.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
dtTileCache* dtAllocTileCache()
|
||||||
|
{
|
||||||
|
void* mem = dtAlloc(sizeof(dtTileCache), DT_ALLOC_PERM);
|
||||||
|
if (!mem) return 0;
|
||||||
|
return new(mem) dtTileCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtFreeTileCache(dtTileCache* tc)
|
||||||
|
{
|
||||||
|
if (!tc) return;
|
||||||
|
tc->~dtTileCache();
|
||||||
|
dtFree(tc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool contains(const dtCompressedTileRef* a, const int n, const dtCompressedTileRef v)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
if (a[i] == v)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int computeTileHash(int x, int y, const int mask)
|
||||||
|
{
|
||||||
|
const unsigned int h1 = 0x8da6b343; // Large multiplicative constants;
|
||||||
|
const unsigned int h2 = 0xd8163841; // here arbitrarily chosen primes
|
||||||
|
unsigned int n = h1 * x + h2 * y;
|
||||||
|
return (int)(n & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct BuildContext
|
||||||
|
{
|
||||||
|
inline BuildContext(struct dtTileCacheAlloc* a) : layer(0), lcset(0), lmesh(0), alloc(a) {}
|
||||||
|
inline ~BuildContext() { purge(); }
|
||||||
|
void purge()
|
||||||
|
{
|
||||||
|
dtFreeTileCacheLayer(alloc, layer);
|
||||||
|
layer = 0;
|
||||||
|
dtFreeTileCacheContourSet(alloc, lcset);
|
||||||
|
lcset = 0;
|
||||||
|
dtFreeTileCachePolyMesh(alloc, lmesh);
|
||||||
|
lmesh = 0;
|
||||||
|
}
|
||||||
|
struct dtTileCacheLayer* layer;
|
||||||
|
struct dtTileCacheContourSet* lcset;
|
||||||
|
struct dtTileCachePolyMesh* lmesh;
|
||||||
|
struct dtTileCacheAlloc* alloc;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
dtTileCache::dtTileCache() :
|
||||||
|
m_tileLutSize(0),
|
||||||
|
m_tileLutMask(0),
|
||||||
|
m_posLookup(0),
|
||||||
|
m_nextFreeTile(0),
|
||||||
|
m_tiles(0),
|
||||||
|
m_saltBits(0),
|
||||||
|
m_tileBits(0),
|
||||||
|
m_talloc(0),
|
||||||
|
m_tcomp(0),
|
||||||
|
m_tmproc(0),
|
||||||
|
m_obstacles(0),
|
||||||
|
m_nextFreeObstacle(0),
|
||||||
|
m_nreqs(0),
|
||||||
|
m_nupdate(0)
|
||||||
|
{
|
||||||
|
memset(&m_params, 0, sizeof(m_params));
|
||||||
|
}
|
||||||
|
|
||||||
|
dtTileCache::~dtTileCache()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_params.maxTiles; ++i)
|
||||||
|
{
|
||||||
|
if (m_tiles[i].flags & DT_COMPRESSEDTILE_FREE_DATA)
|
||||||
|
{
|
||||||
|
dtFree(m_tiles[i].data);
|
||||||
|
m_tiles[i].data = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dtFree(m_obstacles);
|
||||||
|
m_obstacles = 0;
|
||||||
|
dtFree(m_posLookup);
|
||||||
|
m_posLookup = 0;
|
||||||
|
dtFree(m_tiles);
|
||||||
|
m_tiles = 0;
|
||||||
|
m_nreqs = 0;
|
||||||
|
m_nupdate = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dtCompressedTile* dtTileCache::getTileByRef(dtCompressedTileRef ref) const
|
||||||
|
{
|
||||||
|
if (!ref)
|
||||||
|
return 0;
|
||||||
|
unsigned int tileIndex = decodeTileIdTile(ref);
|
||||||
|
unsigned int tileSalt = decodeTileIdSalt(ref);
|
||||||
|
if ((int)tileIndex >= m_params.maxTiles)
|
||||||
|
return 0;
|
||||||
|
const dtCompressedTile* tile = &m_tiles[tileIndex];
|
||||||
|
if (tile->salt != tileSalt)
|
||||||
|
return 0;
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dtStatus dtTileCache::init(const dtTileCacheParams* params,
|
||||||
|
dtTileCacheAlloc* talloc,
|
||||||
|
dtTileCacheCompressor* tcomp,
|
||||||
|
dtTileCacheMeshProcess* tmproc)
|
||||||
|
{
|
||||||
|
m_talloc = talloc;
|
||||||
|
m_tcomp = tcomp;
|
||||||
|
m_tmproc = tmproc;
|
||||||
|
m_nreqs = 0;
|
||||||
|
memcpy(&m_params, params, sizeof(m_params));
|
||||||
|
|
||||||
|
// Alloc space for obstacles.
|
||||||
|
m_obstacles = (dtTileCacheObstacle*)dtAlloc(sizeof(dtTileCacheObstacle)*m_params.maxObstacles, DT_ALLOC_PERM);
|
||||||
|
if (!m_obstacles)
|
||||||
|
return DT_FAILURE | DT_OUT_OF_MEMORY;
|
||||||
|
memset(m_obstacles, 0, sizeof(dtTileCacheObstacle)*m_params.maxObstacles);
|
||||||
|
m_nextFreeObstacle = 0;
|
||||||
|
for (int i = m_params.maxObstacles-1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
m_obstacles[i].salt = 1;
|
||||||
|
m_obstacles[i].next = m_nextFreeObstacle;
|
||||||
|
m_nextFreeObstacle = &m_obstacles[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init tiles
|
||||||
|
m_tileLutSize = dtNextPow2(m_params.maxTiles/4);
|
||||||
|
if (!m_tileLutSize) m_tileLutSize = 1;
|
||||||
|
m_tileLutMask = m_tileLutSize-1;
|
||||||
|
|
||||||
|
m_tiles = (dtCompressedTile*)dtAlloc(sizeof(dtCompressedTile)*m_params.maxTiles, DT_ALLOC_PERM);
|
||||||
|
if (!m_tiles)
|
||||||
|
return DT_FAILURE | DT_OUT_OF_MEMORY;
|
||||||
|
m_posLookup = (dtCompressedTile**)dtAlloc(sizeof(dtCompressedTile*)*m_tileLutSize, DT_ALLOC_PERM);
|
||||||
|
if (!m_posLookup)
|
||||||
|
return DT_FAILURE | DT_OUT_OF_MEMORY;
|
||||||
|
memset(m_tiles, 0, sizeof(dtCompressedTile)*m_params.maxTiles);
|
||||||
|
memset(m_posLookup, 0, sizeof(dtCompressedTile*)*m_tileLutSize);
|
||||||
|
m_nextFreeTile = 0;
|
||||||
|
for (int i = m_params.maxTiles-1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
m_tiles[i].salt = 1;
|
||||||
|
m_tiles[i].next = m_nextFreeTile;
|
||||||
|
m_nextFreeTile = &m_tiles[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init ID generator values.
|
||||||
|
m_tileBits = dtIlog2(dtNextPow2((unsigned int)m_params.maxTiles));
|
||||||
|
// 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);
|
||||||
|
if (m_saltBits < 10)
|
||||||
|
return DT_FAILURE | DT_INVALID_PARAM;
|
||||||
|
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dtTileCache::getTilesAt(const int tx, const int ty, dtCompressedTileRef* tiles, const int maxTiles) const
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
// Find tile based on hash.
|
||||||
|
int h = computeTileHash(tx,ty,m_tileLutMask);
|
||||||
|
dtCompressedTile* tile = m_posLookup[h];
|
||||||
|
while (tile)
|
||||||
|
{
|
||||||
|
if (tile->header &&
|
||||||
|
tile->header->tx == tx &&
|
||||||
|
tile->header->ty == ty)
|
||||||
|
{
|
||||||
|
if (n < maxTiles)
|
||||||
|
tiles[n++] = getTileRef(tile);
|
||||||
|
}
|
||||||
|
tile = tile->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtCompressedTile* dtTileCache::getTileAt(const int tx, const int ty, const int tlayer)
|
||||||
|
{
|
||||||
|
// Find tile based on hash.
|
||||||
|
int h = computeTileHash(tx,ty,m_tileLutMask);
|
||||||
|
dtCompressedTile* tile = m_posLookup[h];
|
||||||
|
while (tile)
|
||||||
|
{
|
||||||
|
if (tile->header &&
|
||||||
|
tile->header->tx == tx &&
|
||||||
|
tile->header->ty == ty &&
|
||||||
|
tile->header->tlayer == tlayer)
|
||||||
|
{
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
tile = tile->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtCompressedTileRef dtTileCache::getTileRef(const dtCompressedTile* tile) const
|
||||||
|
{
|
||||||
|
if (!tile) return 0;
|
||||||
|
const unsigned int it = (unsigned int)(tile - m_tiles);
|
||||||
|
return (dtCompressedTileRef)encodeTileId(tile->salt, it);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtObstacleRef dtTileCache::getObstacleRef(const dtTileCacheObstacle* ob) const
|
||||||
|
{
|
||||||
|
if (!ob) return 0;
|
||||||
|
const unsigned int idx = (unsigned int)(ob - m_obstacles);
|
||||||
|
return encodeObstacleId(ob->salt, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dtTileCacheObstacle* dtTileCache::getObstacleByRef(dtObstacleRef ref)
|
||||||
|
{
|
||||||
|
if (!ref)
|
||||||
|
return 0;
|
||||||
|
unsigned int idx = decodeObstacleIdObstacle(ref);
|
||||||
|
if ((int)idx >= m_params.maxObstacles)
|
||||||
|
return 0;
|
||||||
|
const dtTileCacheObstacle* ob = &m_obstacles[idx];
|
||||||
|
unsigned int salt = decodeObstacleIdSalt(ref);
|
||||||
|
if (ob->salt != salt)
|
||||||
|
return 0;
|
||||||
|
return ob;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtStatus dtTileCache::addTile(unsigned char* data, const int dataSize, unsigned char flags, dtCompressedTileRef* result)
|
||||||
|
{
|
||||||
|
// Make sure the data is in right format.
|
||||||
|
dtTileCacheLayerHeader* header = (dtTileCacheLayerHeader*)data;
|
||||||
|
if (header->magic != DT_TILECACHE_MAGIC)
|
||||||
|
return DT_FAILURE | DT_WRONG_MAGIC;
|
||||||
|
if (header->version != DT_TILECACHE_VERSION)
|
||||||
|
return DT_FAILURE | DT_WRONG_VERSION;
|
||||||
|
|
||||||
|
// Make sure the location is free.
|
||||||
|
if (getTileAt(header->tx, header->ty, header->tlayer))
|
||||||
|
return DT_FAILURE;
|
||||||
|
|
||||||
|
// Allocate a tile.
|
||||||
|
dtCompressedTile* tile = 0;
|
||||||
|
if (m_nextFreeTile)
|
||||||
|
{
|
||||||
|
tile = m_nextFreeTile;
|
||||||
|
m_nextFreeTile = tile->next;
|
||||||
|
tile->next = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we could allocate a tile.
|
||||||
|
if (!tile)
|
||||||
|
return DT_FAILURE | DT_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
// Insert tile into the position lut.
|
||||||
|
int h = computeTileHash(header->tx, header->ty, m_tileLutMask);
|
||||||
|
tile->next = m_posLookup[h];
|
||||||
|
m_posLookup[h] = tile;
|
||||||
|
|
||||||
|
// Init tile.
|
||||||
|
const int headerSize = dtAlign4(sizeof(dtTileCacheLayerHeader));
|
||||||
|
tile->header = (dtTileCacheLayerHeader*)data;
|
||||||
|
tile->data = data;
|
||||||
|
tile->dataSize = dataSize;
|
||||||
|
tile->compressed = tile->data + headerSize;
|
||||||
|
tile->compressedSize = tile->dataSize - headerSize;
|
||||||
|
tile->flags = flags;
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
*result = getTileRef(tile);
|
||||||
|
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtStatus dtTileCache::removeTile(dtCompressedTileRef ref, unsigned char** data, int* dataSize)
|
||||||
|
{
|
||||||
|
if (!ref)
|
||||||
|
return DT_FAILURE | DT_INVALID_PARAM;
|
||||||
|
unsigned int tileIndex = decodeTileIdTile(ref);
|
||||||
|
unsigned int tileSalt = decodeTileIdSalt(ref);
|
||||||
|
if ((int)tileIndex >= m_params.maxTiles)
|
||||||
|
return DT_FAILURE | DT_INVALID_PARAM;
|
||||||
|
dtCompressedTile* tile = &m_tiles[tileIndex];
|
||||||
|
if (tile->salt != tileSalt)
|
||||||
|
return DT_FAILURE | DT_INVALID_PARAM;
|
||||||
|
|
||||||
|
// Remove tile from hash lookup.
|
||||||
|
const int h = computeTileHash(tile->header->tx,tile->header->ty,m_tileLutMask);
|
||||||
|
dtCompressedTile* prev = 0;
|
||||||
|
dtCompressedTile* cur = m_posLookup[h];
|
||||||
|
while (cur)
|
||||||
|
{
|
||||||
|
if (cur == tile)
|
||||||
|
{
|
||||||
|
if (prev)
|
||||||
|
prev->next = cur->next;
|
||||||
|
else
|
||||||
|
m_posLookup[h] = cur->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = cur;
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset tile.
|
||||||
|
if (tile->flags & DT_COMPRESSEDTILE_FREE_DATA)
|
||||||
|
{
|
||||||
|
// Owns data
|
||||||
|
dtFree(tile->data);
|
||||||
|
tile->data = 0;
|
||||||
|
tile->dataSize = 0;
|
||||||
|
if (data) *data = 0;
|
||||||
|
if (dataSize) *dataSize = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (data) *data = tile->data;
|
||||||
|
if (dataSize) *dataSize = tile->dataSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
tile->header = 0;
|
||||||
|
tile->data = 0;
|
||||||
|
tile->dataSize = 0;
|
||||||
|
tile->compressed = 0;
|
||||||
|
tile->compressedSize = 0;
|
||||||
|
tile->flags = 0;
|
||||||
|
|
||||||
|
// Update salt, salt should never be zero.
|
||||||
|
tile->salt = (tile->salt+1) & ((1<<m_saltBits)-1);
|
||||||
|
if (tile->salt == 0)
|
||||||
|
tile->salt++;
|
||||||
|
|
||||||
|
// Add to free list.
|
||||||
|
tile->next = m_nextFreeTile;
|
||||||
|
m_nextFreeTile = tile;
|
||||||
|
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dtObstacleRef dtTileCache::addObstacle(const float* pos, const float radius, const float height, dtObstacleRef* result)
|
||||||
|
{
|
||||||
|
if (m_nreqs >= MAX_REQUESTS)
|
||||||
|
return DT_FAILURE | DT_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
|
dtTileCacheObstacle* ob = 0;
|
||||||
|
if (m_nextFreeObstacle)
|
||||||
|
{
|
||||||
|
ob = m_nextFreeObstacle;
|
||||||
|
m_nextFreeObstacle = ob->next;
|
||||||
|
ob->next = 0;
|
||||||
|
}
|
||||||
|
if (!ob)
|
||||||
|
return DT_FAILURE | DT_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
unsigned short salt = ob->salt;
|
||||||
|
memset(ob, 0, sizeof(dtTileCacheObstacle));
|
||||||
|
ob->salt = salt;
|
||||||
|
ob->state = DT_OBSTACLE_PROCESSING;
|
||||||
|
dtVcopy(ob->pos, pos);
|
||||||
|
ob->radius = radius;
|
||||||
|
ob->height = height;
|
||||||
|
|
||||||
|
ObstacleRequest* req = &m_reqs[m_nreqs++];
|
||||||
|
memset(req, 0, sizeof(ObstacleRequest));
|
||||||
|
req->action = REQUEST_ADD;
|
||||||
|
req->ref = getObstacleRef(ob);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
*result = req->ref;
|
||||||
|
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtObstacleRef dtTileCache::removeObstacle(const dtObstacleRef ref)
|
||||||
|
{
|
||||||
|
if (!ref)
|
||||||
|
return DT_SUCCESS;
|
||||||
|
if (m_nreqs >= MAX_REQUESTS)
|
||||||
|
return DT_FAILURE | DT_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
|
ObstacleRequest* req = &m_reqs[m_nreqs++];
|
||||||
|
memset(req, 0, sizeof(ObstacleRequest));
|
||||||
|
req->action = REQUEST_REMOVE;
|
||||||
|
req->ref = ref;
|
||||||
|
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtStatus dtTileCache::queryTiles(const float* bmin, const float* bmax,
|
||||||
|
dtCompressedTileRef* results, int* resultCount, const int maxResults) const
|
||||||
|
{
|
||||||
|
const int MAX_TILES = 32;
|
||||||
|
dtCompressedTileRef tiles[MAX_TILES];
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
const float tw = m_params.width * m_params.cs;
|
||||||
|
const float th = m_params.height * m_params.cs;
|
||||||
|
const int tx0 = (int)dtMathFloorf((bmin[0]-m_params.orig[0]) / tw);
|
||||||
|
const int tx1 = (int)dtMathFloorf((bmax[0]-m_params.orig[0]) / tw);
|
||||||
|
const int ty0 = (int)dtMathFloorf((bmin[2]-m_params.orig[2]) / th);
|
||||||
|
const int ty1 = (int)dtMathFloorf((bmax[2]-m_params.orig[2]) / th);
|
||||||
|
|
||||||
|
for (int ty = ty0; ty <= ty1; ++ty)
|
||||||
|
{
|
||||||
|
for (int tx = tx0; tx <= tx1; ++tx)
|
||||||
|
{
|
||||||
|
const int ntiles = getTilesAt(tx,ty,tiles,MAX_TILES);
|
||||||
|
|
||||||
|
for (int i = 0; i < ntiles; ++i)
|
||||||
|
{
|
||||||
|
const dtCompressedTile* tile = &m_tiles[decodeTileIdTile(tiles[i])];
|
||||||
|
float tbmin[3], tbmax[3];
|
||||||
|
calcTightTileBounds(tile->header, tbmin, tbmax);
|
||||||
|
|
||||||
|
if (dtOverlapBounds(bmin,bmax, tbmin,tbmax))
|
||||||
|
{
|
||||||
|
if (n < maxResults)
|
||||||
|
results[n++] = tiles[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*resultCount = n;
|
||||||
|
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh)
|
||||||
|
{
|
||||||
|
if (m_nupdate == 0)
|
||||||
|
{
|
||||||
|
// Process requests.
|
||||||
|
for (int i = 0; i < m_nreqs; ++i)
|
||||||
|
{
|
||||||
|
ObstacleRequest* req = &m_reqs[i];
|
||||||
|
|
||||||
|
unsigned int idx = decodeObstacleIdObstacle(req->ref);
|
||||||
|
if ((int)idx >= m_params.maxObstacles)
|
||||||
|
continue;
|
||||||
|
dtTileCacheObstacle* ob = &m_obstacles[idx];
|
||||||
|
unsigned int salt = decodeObstacleIdSalt(req->ref);
|
||||||
|
if (ob->salt != salt)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (req->action == REQUEST_ADD)
|
||||||
|
{
|
||||||
|
// Find touched tiles.
|
||||||
|
float bmin[3], bmax[3];
|
||||||
|
getObstacleBounds(ob, bmin, bmax);
|
||||||
|
|
||||||
|
int ntouched = 0;
|
||||||
|
queryTiles(bmin, bmax, ob->touched, &ntouched, DT_MAX_TOUCHED_TILES);
|
||||||
|
ob->ntouched = (unsigned char)ntouched;
|
||||||
|
// Add tiles to update list.
|
||||||
|
ob->npending = 0;
|
||||||
|
for (int j = 0; j < ob->ntouched; ++j)
|
||||||
|
{
|
||||||
|
if (m_nupdate < MAX_UPDATE)
|
||||||
|
{
|
||||||
|
if (!contains(m_update, m_nupdate, ob->touched[j]))
|
||||||
|
m_update[m_nupdate++] = ob->touched[j];
|
||||||
|
ob->pending[ob->npending++] = ob->touched[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (req->action == REQUEST_REMOVE)
|
||||||
|
{
|
||||||
|
// Prepare to remove obstacle.
|
||||||
|
ob->state = DT_OBSTACLE_REMOVING;
|
||||||
|
// Add tiles to update list.
|
||||||
|
ob->npending = 0;
|
||||||
|
for (int j = 0; j < ob->ntouched; ++j)
|
||||||
|
{
|
||||||
|
if (m_nupdate < MAX_UPDATE)
|
||||||
|
{
|
||||||
|
if (!contains(m_update, m_nupdate, ob->touched[j]))
|
||||||
|
m_update[m_nupdate++] = ob->touched[j];
|
||||||
|
ob->pending[ob->npending++] = ob->touched[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_nreqs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process updates
|
||||||
|
if (m_nupdate)
|
||||||
|
{
|
||||||
|
// Build mesh
|
||||||
|
const dtCompressedTileRef ref = m_update[0];
|
||||||
|
dtStatus status = buildNavMeshTile(ref, navmesh);
|
||||||
|
m_nupdate--;
|
||||||
|
if (m_nupdate > 0)
|
||||||
|
memmove(m_update, m_update+1, m_nupdate*sizeof(dtCompressedTileRef));
|
||||||
|
|
||||||
|
// Update obstacle states.
|
||||||
|
for (int i = 0; i < m_params.maxObstacles; ++i)
|
||||||
|
{
|
||||||
|
dtTileCacheObstacle* ob = &m_obstacles[i];
|
||||||
|
if (ob->state == DT_OBSTACLE_PROCESSING || ob->state == DT_OBSTACLE_REMOVING)
|
||||||
|
{
|
||||||
|
// Remove handled tile from pending list.
|
||||||
|
for (int j = 0; j < (int)ob->npending; j++)
|
||||||
|
{
|
||||||
|
if (ob->pending[j] == ref)
|
||||||
|
{
|
||||||
|
ob->pending[j] = ob->pending[(int)ob->npending-1];
|
||||||
|
ob->npending--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all pending tiles processed, change state.
|
||||||
|
if (ob->npending == 0)
|
||||||
|
{
|
||||||
|
if (ob->state == DT_OBSTACLE_PROCESSING)
|
||||||
|
{
|
||||||
|
ob->state = DT_OBSTACLE_PROCESSED;
|
||||||
|
}
|
||||||
|
else if (ob->state == DT_OBSTACLE_REMOVING)
|
||||||
|
{
|
||||||
|
ob->state = DT_OBSTACLE_EMPTY;
|
||||||
|
// Update salt, salt should never be zero.
|
||||||
|
ob->salt = (ob->salt+1) & ((1<<16)-1);
|
||||||
|
if (ob->salt == 0)
|
||||||
|
ob->salt++;
|
||||||
|
// Return obstacle to free list.
|
||||||
|
ob->next = m_nextFreeObstacle;
|
||||||
|
m_nextFreeObstacle = ob;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dtStatusFailed(status))
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dtStatus dtTileCache::buildNavMeshTilesAt(const int tx, const int ty, dtNavMesh* navmesh)
|
||||||
|
{
|
||||||
|
const int MAX_TILES = 32;
|
||||||
|
dtCompressedTileRef tiles[MAX_TILES];
|
||||||
|
const int ntiles = getTilesAt(tx,ty,tiles,MAX_TILES);
|
||||||
|
|
||||||
|
for (int i = 0; i < ntiles; ++i)
|
||||||
|
{
|
||||||
|
dtStatus status = buildNavMeshTile(tiles[i], navmesh);
|
||||||
|
if (dtStatusFailed(status))
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* navmesh)
|
||||||
|
{
|
||||||
|
dtAssert(m_talloc);
|
||||||
|
dtAssert(m_tcomp);
|
||||||
|
|
||||||
|
unsigned int idx = decodeTileIdTile(ref);
|
||||||
|
if (idx > (unsigned int)m_params.maxTiles)
|
||||||
|
return DT_FAILURE | DT_INVALID_PARAM;
|
||||||
|
const dtCompressedTile* tile = &m_tiles[idx];
|
||||||
|
unsigned int salt = decodeTileIdSalt(ref);
|
||||||
|
if (tile->salt != salt)
|
||||||
|
return DT_FAILURE | DT_INVALID_PARAM;
|
||||||
|
|
||||||
|
m_talloc->reset();
|
||||||
|
|
||||||
|
BuildContext bc(m_talloc);
|
||||||
|
const int walkableClimbVx = (int)(m_params.walkableClimb / m_params.ch);
|
||||||
|
dtStatus status;
|
||||||
|
|
||||||
|
// Decompress tile layer data.
|
||||||
|
status = dtDecompressTileCacheLayer(m_talloc, m_tcomp, tile->data, tile->dataSize, &bc.layer);
|
||||||
|
if (dtStatusFailed(status))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// Rasterize obstacles.
|
||||||
|
for (int i = 0; i < m_params.maxObstacles; ++i)
|
||||||
|
{
|
||||||
|
const dtTileCacheObstacle* ob = &m_obstacles[i];
|
||||||
|
if (ob->state == DT_OBSTACLE_EMPTY || ob->state == DT_OBSTACLE_REMOVING)
|
||||||
|
continue;
|
||||||
|
if (contains(ob->touched, ob->ntouched, ref))
|
||||||
|
{
|
||||||
|
dtMarkCylinderArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
|
||||||
|
ob->pos, ob->radius, ob->height, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build navmesh
|
||||||
|
status = dtBuildTileCacheRegions(m_talloc, *bc.layer, walkableClimbVx);
|
||||||
|
if (dtStatusFailed(status))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
bc.lcset = dtAllocTileCacheContourSet(m_talloc);
|
||||||
|
if (!bc.lcset)
|
||||||
|
return status;
|
||||||
|
status = dtBuildTileCacheContours(m_talloc, *bc.layer, walkableClimbVx,
|
||||||
|
m_params.maxSimplificationError, *bc.lcset);
|
||||||
|
if (dtStatusFailed(status))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
bc.lmesh = dtAllocTileCachePolyMesh(m_talloc);
|
||||||
|
if (!bc.lmesh)
|
||||||
|
return status;
|
||||||
|
status = dtBuildTileCachePolyMesh(m_talloc, *bc.lcset, *bc.lmesh);
|
||||||
|
if (dtStatusFailed(status))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// Early out if the mesh tile is empty.
|
||||||
|
if (!bc.lmesh->npolys)
|
||||||
|
return DT_SUCCESS;
|
||||||
|
|
||||||
|
dtNavMeshCreateParams params;
|
||||||
|
memset(¶ms, 0, sizeof(params));
|
||||||
|
params.verts = bc.lmesh->verts;
|
||||||
|
params.vertCount = bc.lmesh->nverts;
|
||||||
|
params.polys = bc.lmesh->polys;
|
||||||
|
params.polyAreas = bc.lmesh->areas;
|
||||||
|
params.polyFlags = bc.lmesh->flags;
|
||||||
|
params.polyCount = bc.lmesh->npolys;
|
||||||
|
params.nvp = DT_VERTS_PER_POLYGON;
|
||||||
|
params.walkableHeight = m_params.walkableHeight;
|
||||||
|
params.walkableRadius = m_params.walkableRadius;
|
||||||
|
params.walkableClimb = m_params.walkableClimb;
|
||||||
|
params.tileX = tile->header->tx;
|
||||||
|
params.tileY = tile->header->ty;
|
||||||
|
params.tileLayer = tile->header->tlayer;
|
||||||
|
params.cs = m_params.cs;
|
||||||
|
params.ch = m_params.ch;
|
||||||
|
params.buildBvTree = false;
|
||||||
|
dtVcopy(params.bmin, tile->header->bmin);
|
||||||
|
dtVcopy(params.bmax, tile->header->bmax);
|
||||||
|
|
||||||
|
if (m_tmproc)
|
||||||
|
{
|
||||||
|
m_tmproc->process(¶ms, bc.lmesh->areas, bc.lmesh->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* navData = 0;
|
||||||
|
int navDataSize = 0;
|
||||||
|
if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize))
|
||||||
|
return DT_FAILURE;
|
||||||
|
|
||||||
|
// Remove existing tile.
|
||||||
|
navmesh->removeTile(navmesh->getTileRefAt(tile->header->tx,tile->header->ty,tile->header->tlayer),0,0);
|
||||||
|
|
||||||
|
// Add new tile, or leave the location empty.
|
||||||
|
if (navData)
|
||||||
|
{
|
||||||
|
// Let the navmesh own the data.
|
||||||
|
status = navmesh->addTile(navData,navDataSize,DT_TILE_FREE_DATA,0,0);
|
||||||
|
if (dtStatusFailed(status))
|
||||||
|
{
|
||||||
|
dtFree(navData);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtTileCache::calcTightTileBounds(const dtTileCacheLayerHeader* header, float* bmin, float* bmax) const
|
||||||
|
{
|
||||||
|
const float cs = m_params.cs;
|
||||||
|
bmin[0] = header->bmin[0] + header->minx*cs;
|
||||||
|
bmin[1] = header->bmin[1];
|
||||||
|
bmin[2] = header->bmin[2] + header->miny*cs;
|
||||||
|
bmax[0] = header->bmin[0] + (header->maxx+1)*cs;
|
||||||
|
bmax[1] = header->bmax[1];
|
||||||
|
bmax[2] = header->bmin[2] + (header->maxy+1)*cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtTileCache::getObstacleBounds(const struct dtTileCacheObstacle* ob, float* bmin, float* bmax) const
|
||||||
|
{
|
||||||
|
bmin[0] = ob->pos[0] - ob->radius;
|
||||||
|
bmin[1] = ob->pos[1];
|
||||||
|
bmin[2] = ob->pos[2] - ob->radius;
|
||||||
|
bmax[0] = ob->pos[0] + ob->radius;
|
||||||
|
bmax[1] = ob->pos[1] + ob->height;
|
||||||
|
bmax[2] = ob->pos[2] + ob->radius;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
27
dep/recastnavigation/Docs/Conceptual/license_c.txt
Normal file
27
dep/recastnavigation/Docs/Conceptual/license_c.txt
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
|
||||||
|
/**
|
||||||
|
@page License License
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
Copyright (c) 2009-2011 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.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
*/
|
||||||
95
dep/recastnavigation/Docs/Conceptual/mainpage_c.txt
Normal file
95
dep/recastnavigation/Docs/Conceptual/mainpage_c.txt
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
/// @mainpage Recast Navigation
|
||||||
|
///
|
||||||
|
/// @image html recast_intro.png
|
||||||
|
///
|
||||||
|
/// <h2>Recast</h2>
|
||||||
|
///
|
||||||
|
/// _Recast_ is state of the art navigation mesh construction toolset for
|
||||||
|
/// games.
|
||||||
|
///
|
||||||
|
/// - It is automatic, which means that you can throw any level
|
||||||
|
/// geometry at it and you will get a robust mesh out.
|
||||||
|
/// - It is fast which means swift turnaround times for level designers.
|
||||||
|
/// - It is open source so it comes with full source and you can
|
||||||
|
/// customize it to your hearts content.
|
||||||
|
///
|
||||||
|
/// The latest version can be found on
|
||||||
|
/// <a href="https://github.com/memononen/recastnavigation">GitHub</a>.
|
||||||
|
///
|
||||||
|
/// The _Recast_ process starts with constructing a voxel mold from level
|
||||||
|
/// geometry and then casting a navigation mesh over it. The process
|
||||||
|
/// consists of three steps, building the voxel mold, partitioning the
|
||||||
|
/// mold into simple regions, and peeling off the regions as simple polygons.
|
||||||
|
///
|
||||||
|
/// -# The voxel mold is built from the input triangle mesh by
|
||||||
|
/// rasterizing the triangles into a multi-layer heightfield. Some
|
||||||
|
/// simple filters are then applied to the mold to prune out locations
|
||||||
|
/// where the character would not be able to move.
|
||||||
|
/// -# The walkable areas described by the mold are divided into simple
|
||||||
|
/// overlayed 2D regions. The resulting regions have only one
|
||||||
|
/// non-overlapping contour, which simplifies the final step of the
|
||||||
|
/// process tremendously.
|
||||||
|
/// -# The navigation polygons are peeled off from the regions by first
|
||||||
|
/// tracing the boundaries and then simplifying them. The resulting
|
||||||
|
/// polygons are finally converted to convex polygons which makes them
|
||||||
|
/// perfect for pathfinding and spatial reasoning about the level.
|
||||||
|
///
|
||||||
|
/// <h2>Detour</h2>
|
||||||
|
///
|
||||||
|
/// _Recast_ is accompanied by _Detour_, a path-finding and spatial reasoning
|
||||||
|
/// toolkit. You can use any navigation mesh with _Detour_, but of course
|
||||||
|
/// the data generated by _Recast_ fits perfectly.
|
||||||
|
///
|
||||||
|
/// _Detour_ offers a simple static navigation mesh that is suitable for
|
||||||
|
/// many simple cases, as well as a tiled navigation mesh that allows you
|
||||||
|
/// to add and remove pieces of the mesh. The tiled mesh allows you to
|
||||||
|
/// create systems where you stream new navigation data in and out as
|
||||||
|
/// the player progresses the level, or regenerate tiles as the
|
||||||
|
/// world changes.
|
||||||
|
///
|
||||||
|
/// <h2>Recast Demo</h2>
|
||||||
|
///
|
||||||
|
/// You can find a comprehensive demo project in the `RecastDemo` folder. It
|
||||||
|
/// is a kitchen sink demo containing all the functionality of the library.
|
||||||
|
/// If you are new to _Recast_ & _Detour_, check out
|
||||||
|
/// <a href="https://github.com/memononen/recastnavigation/blob/master/RecastDemo/Source/Sample_SoloMesh.cpp">
|
||||||
|
/// Sample_SoloMesh.cpp</a> to get started with building navmeshes and
|
||||||
|
/// <a href="https://github.com/memononen/recastnavigation/blob/master/RecastDemo/Source/NavMeshTesterTool.cpp">
|
||||||
|
/// NavMeshTesterTool.cpp</a> to see how _Detour_ can be used to find paths.
|
||||||
|
///
|
||||||
|
/// <h3>Building RecastDemo</h3>
|
||||||
|
///
|
||||||
|
/// _RecastDemo_ uses <a href="http://industriousone.com/premake">premake4</a>
|
||||||
|
/// to build platform specific projects, now is good time to install it if
|
||||||
|
/// you don't have it already. To build _RecastDemo_, in your favourite terminal
|
||||||
|
/// navigate into the `RecastDemo` folder, then:
|
||||||
|
///
|
||||||
|
/// - OS X: `premake4 xcode4`
|
||||||
|
/// - Windows: `premake4 vs2010`
|
||||||
|
/// - Linux: `premake4 gmake`
|
||||||
|
///
|
||||||
|
/// See the _premake4_ documentation for full list of supported build file types.
|
||||||
|
/// The projects will be created in the `RecastDemo/Build` folder. After you have
|
||||||
|
/// compiled the project, the _RecastDemo_ executable will be located in
|
||||||
|
/// `RecastDemo/Bin` folder.
|
||||||
|
///
|
||||||
|
/// <h2>Integrating With Your Own Project</h2>
|
||||||
|
///
|
||||||
|
/// It is recommended to add the source directories `DebugUtils`, `Detour`,
|
||||||
|
/// `DetourCrowd`, `DetourTileCache`, and `Recast` into your own project
|
||||||
|
/// depending on which parts of the project you need. For example your
|
||||||
|
/// level building tool could include `DebugUtils`, `Recast`, and `Detour`,
|
||||||
|
/// and your game runtime could just include `Detour`.
|
||||||
|
///
|
||||||
|
/// <h2>Discuss</h2>
|
||||||
|
///
|
||||||
|
/// - Discuss _Recast_ and _Detour_:
|
||||||
|
/// <a href="http://groups.google.com/group/recastnavigation">
|
||||||
|
/// Recast Navigation Group</a>
|
||||||
|
/// - Development Blog:
|
||||||
|
/// <a href="http://digestingduck.blogspot.com/">Digesting Duck</a>
|
||||||
|
///
|
||||||
|
/// <h2>License</h2>
|
||||||
|
///
|
||||||
|
/// _Recast Navigation_ is licensed under the ZLib license.
|
||||||
|
///
|
||||||
194
dep/recastnavigation/Docs/DoxygenLayout.xml
Normal file
194
dep/recastnavigation/Docs/DoxygenLayout.xml
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
<doxygenlayout version="1.0">
|
||||||
|
<!-- Generated by doxygen 1.8.6 -->
|
||||||
|
<!-- Navigation index tabs for HTML output -->
|
||||||
|
<navindex>
|
||||||
|
<tab type="mainpage" visible="yes" title=""/>
|
||||||
|
<tab type="pages" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="modules" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="namespaces" visible="no" title="">
|
||||||
|
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="namespacemembers" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="classes" visible="yes" title="">
|
||||||
|
<tab type="classlist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="classindex" visible="yes" title=""/>
|
||||||
|
<tab type="hierarchy" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="classmembers" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="files" visible="yes" title="">
|
||||||
|
<tab type="filelist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="globals" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="examples" visible="yes" title="" intro=""/>
|
||||||
|
</navindex>
|
||||||
|
|
||||||
|
<!-- Layout definition for a class page -->
|
||||||
|
<class>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||||
|
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||||
|
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
|
||||||
|
<memberdecl>
|
||||||
|
<nestedclasses visible="yes" title=""/>
|
||||||
|
<publictypes title=""/>
|
||||||
|
<services title=""/>
|
||||||
|
<interfaces title=""/>
|
||||||
|
<publicslots title=""/>
|
||||||
|
<signals title=""/>
|
||||||
|
<publicmethods title=""/>
|
||||||
|
<publicstaticmethods title=""/>
|
||||||
|
<publicattributes title=""/>
|
||||||
|
<publicstaticattributes title=""/>
|
||||||
|
<protectedtypes title=""/>
|
||||||
|
<protectedslots title=""/>
|
||||||
|
<protectedmethods title=""/>
|
||||||
|
<protectedstaticmethods title=""/>
|
||||||
|
<protectedattributes title=""/>
|
||||||
|
<protectedstaticattributes title=""/>
|
||||||
|
<packagetypes title=""/>
|
||||||
|
<packagemethods title=""/>
|
||||||
|
<packagestaticmethods title=""/>
|
||||||
|
<packageattributes title=""/>
|
||||||
|
<packagestaticattributes title=""/>
|
||||||
|
<properties title=""/>
|
||||||
|
<events title=""/>
|
||||||
|
<privatetypes title=""/>
|
||||||
|
<privateslots title=""/>
|
||||||
|
<privatemethods title=""/>
|
||||||
|
<privatestaticmethods title=""/>
|
||||||
|
<privateattributes title=""/>
|
||||||
|
<privatestaticattributes title=""/>
|
||||||
|
<friends title=""/>
|
||||||
|
<related title="" subtitle=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription title="Description"/>
|
||||||
|
<memberdef>
|
||||||
|
<inlineclasses title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<services title=""/>
|
||||||
|
<interfaces title=""/>
|
||||||
|
<constructors title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<related title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
<properties title=""/>
|
||||||
|
<events title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<allmemberslink visible="yes"/>
|
||||||
|
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<!-- Layout definition for a namespace page -->
|
||||||
|
<namespace>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<nestednamespaces visible="yes" title=""/>
|
||||||
|
<constantgroups visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription title="Description"/>
|
||||||
|
<memberdef>
|
||||||
|
<inlineclasses title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</namespace>
|
||||||
|
|
||||||
|
<!-- Layout definition for a file page -->
|
||||||
|
<file>
|
||||||
|
<briefdescription visible="Description"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
|
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||||
|
<includegraph visible="$INCLUDE_GRAPH"/>
|
||||||
|
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
|
||||||
|
<sourcelink visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<namespaces visible="yes" title=""/>
|
||||||
|
<constantgroups visible="yes" title=""/>
|
||||||
|
<defines title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<memberdef>
|
||||||
|
<inlineclasses title=""/>
|
||||||
|
<defines title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<authorsection/>
|
||||||
|
</file>
|
||||||
|
|
||||||
|
<!-- Layout definition for a group page -->
|
||||||
|
<group>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<groupgraph visible="$GROUP_GRAPHS"/>
|
||||||
|
<memberdecl>
|
||||||
|
<nestedgroups visible="yes" title=""/>
|
||||||
|
<dirs visible="yes" title=""/>
|
||||||
|
<files visible="yes" title=""/>
|
||||||
|
<namespaces visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<defines title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<enumvalues title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
<signals title=""/>
|
||||||
|
<publicslots title=""/>
|
||||||
|
<protectedslots title=""/>
|
||||||
|
<privateslots title=""/>
|
||||||
|
<events title=""/>
|
||||||
|
<properties title=""/>
|
||||||
|
<friends title=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription title="Description"/>
|
||||||
|
<memberdef>
|
||||||
|
<pagedocs/>
|
||||||
|
<inlineclasses title=""/>
|
||||||
|
<defines title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<enumvalues title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
<signals title=""/>
|
||||||
|
<publicslots title=""/>
|
||||||
|
<protectedslots title=""/>
|
||||||
|
<privateslots title=""/>
|
||||||
|
<events title=""/>
|
||||||
|
<properties title=""/>
|
||||||
|
<friends title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<!-- Layout definition for a directory page -->
|
||||||
|
<directory>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<directorygraph visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<dirs visible="yes"/>
|
||||||
|
<files visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription title=""/>
|
||||||
|
</directory>
|
||||||
|
</doxygenlayout>
|
||||||
587
dep/recastnavigation/Docs/Extern/Recast_api.txt
vendored
Normal file
587
dep/recastnavigation/Docs/Extern/Recast_api.txt
vendored
Normal file
|
|
@ -0,0 +1,587 @@
|
||||||
|
// This file contains the detail API documentation for
|
||||||
|
// elements defined in the Recast.h.
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
@defgroup recast Recast
|
||||||
|
|
||||||
|
Members in this module are used to create mesh data that is then
|
||||||
|
used to create Detour navigation meshes.
|
||||||
|
|
||||||
|
The are a large number of possible ways to building navigation mesh data.
|
||||||
|
One of the simple piplines is as follows:
|
||||||
|
|
||||||
|
-# Prepare the input triangle mesh.
|
||||||
|
-# Build a #rcHeightfield.
|
||||||
|
-# Build a #rcCompactHeightfield.
|
||||||
|
-# Build a #rcContourSet.
|
||||||
|
-# Build a #rcPolyMesh.
|
||||||
|
-# Build a #rcPolyMeshDetail.
|
||||||
|
-# Use the rcPolyMesh and rcPolyMeshDetail to build a Detour navigation mesh
|
||||||
|
tile.
|
||||||
|
|
||||||
|
The general life-cycle of the main classes is as follows:
|
||||||
|
|
||||||
|
-# Allocate the object using the Recast allocator. (E.g. #rcAllocHeightfield)
|
||||||
|
-# Initialize or build the object. (E.g. #rcCreateHeightfield)
|
||||||
|
-# Update the object as needed. (E.g. #rcRasterizeTriangles)
|
||||||
|
-# Use the object as part of the pipeline.
|
||||||
|
-# Free the object using the Recast allocator. (E.g. #rcFreeHeightField)
|
||||||
|
|
||||||
|
@note This is a summary list of members. Use the index or search
|
||||||
|
feature to find minor members.
|
||||||
|
|
||||||
|
@struct rcConfig
|
||||||
|
@par
|
||||||
|
|
||||||
|
The is a convenience structure that represents an aggregation of parameters
|
||||||
|
used at different stages in the Recast build process. Some
|
||||||
|
values are derived during the build process. Not all parameters
|
||||||
|
are used for all build processes.
|
||||||
|
|
||||||
|
Units are usually in voxels (vx) or world units (wu). The units for voxels,
|
||||||
|
grid size, and cell size are all based on the values of #cs and #ch.
|
||||||
|
|
||||||
|
In this documentation, the term 'field' refers to heightfield and
|
||||||
|
contour data structures that define spacial information using an integer
|
||||||
|
grid.
|
||||||
|
|
||||||
|
The upper and lower limits for the various parameters often depend on
|
||||||
|
the platform's floating point accuraccy as well as interdependencies between
|
||||||
|
the values of multiple parameters. See the individual parameter
|
||||||
|
documentation for details.
|
||||||
|
|
||||||
|
@var rcConfig::borderSize
|
||||||
|
@par
|
||||||
|
|
||||||
|
This value represents the the closest the walkable area of the heightfield
|
||||||
|
should come to the xz-plane AABB of the field. It does not have any
|
||||||
|
impact on the borders around internal obstructions.
|
||||||
|
|
||||||
|
@var rcConfig::tileSize
|
||||||
|
@par
|
||||||
|
|
||||||
|
This field is only used when building multi-tile meshes.
|
||||||
|
|
||||||
|
@var rcConfig::cs
|
||||||
|
@par
|
||||||
|
|
||||||
|
@p cs and #ch define voxel/grid/cell size. So their values have significant
|
||||||
|
side effects on all parameters defined in voxel units.
|
||||||
|
|
||||||
|
The minimum value for this parameter depends on the platform's floating point
|
||||||
|
accuracy, with the practical minimum usually around 0.05.
|
||||||
|
|
||||||
|
@var rcConfig::ch
|
||||||
|
@par
|
||||||
|
|
||||||
|
#cs and @p ch define voxel/grid/cell size. So their values have significant
|
||||||
|
side effects on all parameters defined in voxel units.
|
||||||
|
|
||||||
|
The minimum value for this parameter depends on the platform's floating point
|
||||||
|
accuracy, with the practical minimum usually around 0.05.
|
||||||
|
|
||||||
|
@var rcConfig::walkableSlopeAngle
|
||||||
|
@par
|
||||||
|
|
||||||
|
The practical upper limit for this parameter is usually around 85 degrees.
|
||||||
|
|
||||||
|
@var rcConfig::walkableHeight
|
||||||
|
@par
|
||||||
|
|
||||||
|
Permits detection of overhangs in the source geometry that make the geometry
|
||||||
|
below un-walkable. The value is usually set to the maximum agent height.
|
||||||
|
|
||||||
|
@var rcConfig::walkableClimb
|
||||||
|
@par
|
||||||
|
|
||||||
|
Allows the mesh to flow over low lying obstructions such as curbs and
|
||||||
|
up/down stairways. The value is usually set to how far up/down an agent can step.
|
||||||
|
|
||||||
|
@var rcConfig::walkableRadius
|
||||||
|
@par
|
||||||
|
|
||||||
|
In general, this is the closest any part of the final mesh should get to an
|
||||||
|
obstruction in the source geometry. It is usually set to the maximum
|
||||||
|
agent radius.
|
||||||
|
|
||||||
|
While a value of zero is legal, it is not recommended and can result in
|
||||||
|
odd edge case issues.
|
||||||
|
|
||||||
|
@var rcConfig::maxEdgeLen
|
||||||
|
@par
|
||||||
|
|
||||||
|
Extra vertices will be inserted as needed to keep contour edges below this
|
||||||
|
length. A value of zero effectively disables this feature.
|
||||||
|
|
||||||
|
@var rcConfig::maxSimplificationError
|
||||||
|
@par
|
||||||
|
|
||||||
|
The effect of this parameter only applies to the xz-plane.
|
||||||
|
|
||||||
|
@var rcConfig::minRegionArea
|
||||||
|
@par
|
||||||
|
|
||||||
|
Any regions that are smaller than this area will be marked as unwalkable.
|
||||||
|
This is useful in removing useless regions that can sometimes form on
|
||||||
|
geometry such as table tops, box tops, etc.
|
||||||
|
|
||||||
|
@var rcConfig::maxVertsPerPoly
|
||||||
|
@par
|
||||||
|
|
||||||
|
If the mesh data is to be used to construct a Detour navigation mesh, then the upper limit
|
||||||
|
is limited to <= #DT_VERTS_PER_POLYGON.
|
||||||
|
|
||||||
|
|
||||||
|
@struct rcHeightfield
|
||||||
|
@par
|
||||||
|
|
||||||
|
The grid of a heightfield is layed out on the xz-plane based on the
|
||||||
|
value of #cs. Spans exist within the grid columns with the span
|
||||||
|
min/max values at increments of #ch from the base of the grid. The smallest
|
||||||
|
possible span size is <tt>(#cs width) * (#cs depth) * (#ch height)</tt>. (Which is a single voxel.)
|
||||||
|
|
||||||
|
The standard process for buidling a heightfield is to allocate it using
|
||||||
|
#rcAllocHeightfield, initialize it using #rcCreateHeightfield, then
|
||||||
|
add spans using the various helper functions such as #rcRasterizeTriangle.
|
||||||
|
|
||||||
|
Building a heightfield is one of the first steps in creating a polygon mesh
|
||||||
|
from source geometry. After it is populated, it is used to build a
|
||||||
|
rcCompactHeightfield.
|
||||||
|
|
||||||
|
Example of iterating the spans in a heightfield:
|
||||||
|
@code
|
||||||
|
// Where hf is a reference to an heightfield object.
|
||||||
|
|
||||||
|
const float* orig = hf.bmin;
|
||||||
|
const float cs = hf.cs;
|
||||||
|
const float ch = hf.ch;
|
||||||
|
|
||||||
|
const int w = hf.width;
|
||||||
|
const int h = hf.height;
|
||||||
|
|
||||||
|
for (int y = 0; y < h; ++y)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < w; ++x)
|
||||||
|
{
|
||||||
|
// Deriving the minimum corner of the grid location.
|
||||||
|
float fx = orig[0] + x*cs;
|
||||||
|
float fz = orig[2] + y*cs;
|
||||||
|
// The base span in the column. (May be null.)
|
||||||
|
const rcSpan* s = hf.spans[x + y*w];
|
||||||
|
while (s)
|
||||||
|
{
|
||||||
|
// Detriving the minium and maximum world position of the span.
|
||||||
|
float fymin = orig[1]+s->smin*ch;
|
||||||
|
float fymax = orig[1] + s->smax*ch;
|
||||||
|
// Do other things with the span before moving up the column.
|
||||||
|
s = s->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see rcAllocHeightfield, rcFreeHeightField, rcCreateHeightfield
|
||||||
|
|
||||||
|
@struct rcCompactCell
|
||||||
|
@par
|
||||||
|
|
||||||
|
See the rcCompactHeightfield documentation for an example of how compact cells
|
||||||
|
are used to iterate the heightfield.
|
||||||
|
|
||||||
|
Useful instances of this type can only by obtained from a #rcCompactHeightfield object.
|
||||||
|
|
||||||
|
@see rcCompactHeightfield
|
||||||
|
|
||||||
|
@struct rcCompactSpan
|
||||||
|
@par
|
||||||
|
|
||||||
|
The span represents open, unobstructed space within a compact heightfield column.
|
||||||
|
See the rcCompactHeightfield documentation for an example of iterating spans and searching
|
||||||
|
span connections.
|
||||||
|
|
||||||
|
Useful instances of this type can only by obtained from a #rcCompactHeightfield object.
|
||||||
|
|
||||||
|
@see rcCompactHeightfield
|
||||||
|
|
||||||
|
|
||||||
|
@struct rcCompactHeightfield
|
||||||
|
@par
|
||||||
|
|
||||||
|
For this type of heightfield, the spans represent the open (unobstructed)
|
||||||
|
space above the solid surfaces of a voxel field. It is usually created from
|
||||||
|
a #rcHeightfield object. Data is stored in a compact, efficient manner,
|
||||||
|
but the structure is not condusive to adding and removing spans.
|
||||||
|
|
||||||
|
The standard process for buidling a compact heightfield is to allocate it
|
||||||
|
using #rcAllocCompactHeightfield, build it using #rcBuildCompactHeightfield,
|
||||||
|
then run it through the various helper functions to generate neighbor
|
||||||
|
and region data.
|
||||||
|
|
||||||
|
Connected neighbor spans form non-overlapping surfaces. When neighbor
|
||||||
|
information is generated, spans will include data that can be used to
|
||||||
|
locate axis-neighbors. Axis-neighbors are connected
|
||||||
|
spans that are offset from the current cell column as follows:
|
||||||
|
<pre>
|
||||||
|
Direction 0 = (-1, 0)
|
||||||
|
Direction 1 = (0, 1)
|
||||||
|
Direction 2 = (1, 0)
|
||||||
|
Direction 3 = (0, -1)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Example of iterating and inspecting spans, including connected neighbors:
|
||||||
|
|
||||||
|
@code
|
||||||
|
// Where chf is an instance of a rcCompactHeightfield.
|
||||||
|
|
||||||
|
const float cs = chf.cs;
|
||||||
|
const float ch = chf.ch;
|
||||||
|
|
||||||
|
for (int y = 0; y < chf.height; ++y)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < chf.width; ++x)
|
||||||
|
{
|
||||||
|
// Deriving the minimum corner of the grid location.
|
||||||
|
const float fx = chf.bmin[0] + x*cs;
|
||||||
|
const float fz = chf.bmin[2] + y*cs;
|
||||||
|
|
||||||
|
// Get the cell for the grid location then iterate
|
||||||
|
// up the column.
|
||||||
|
const rcCompactCell& c = chf.cells[x+y*chf.width];
|
||||||
|
for (unsigned i = c.index, ni = c.index+c.count; i < ni; ++i)
|
||||||
|
{
|
||||||
|
const rcCompactSpan& s = chf.spans[i];
|
||||||
|
|
||||||
|
Deriving the minimum (floor) of the span.
|
||||||
|
const float fy = chf.bmin[1] + (s.y+1)*ch;
|
||||||
|
|
||||||
|
// Testing the area assignment of the span.
|
||||||
|
if (chf.areas[i] == RC_WALKABLE_AREA)
|
||||||
|
{
|
||||||
|
// The span is in the default 'walkable area'.
|
||||||
|
}
|
||||||
|
else if (chf.areas[i] == RC_NULL_AREA)
|
||||||
|
{
|
||||||
|
// The surface is not considered walkable.
|
||||||
|
// E.g. It was filtered out during the build processes.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Do something. (Only applicable for custom build
|
||||||
|
// build processes.)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterating the connected axis-neighbor spans.
|
||||||
|
for (int dir = 0; dir < 4; ++dir)
|
||||||
|
{
|
||||||
|
if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
|
||||||
|
{
|
||||||
|
// There is a neighbor in this direction.
|
||||||
|
const int nx = x + rcGetDirOffsetX(dir);
|
||||||
|
const int ny = y + rcGetDirOffsetY(dir);
|
||||||
|
const int ni = (int)chf.cells[nx+ny*w].index + rcGetCon(s, 0);
|
||||||
|
const rcCompactSpan& ns = chf.spans[ni];
|
||||||
|
// Do something with the neighbor span.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see rcAllocCompactHeightfield, rcFreeCompactHeightfield, rcBuildCompactHeightfield
|
||||||
|
|
||||||
|
@struct rcContour
|
||||||
|
@par
|
||||||
|
|
||||||
|
A contour only exists within the context of a #rcContourSet object.
|
||||||
|
|
||||||
|
While the height of the contour's border may vary, the contour will always
|
||||||
|
form a simple polygon when projected onto the xz-plane.
|
||||||
|
|
||||||
|
Example of converting vertices into world space:
|
||||||
|
|
||||||
|
@code
|
||||||
|
// Where cset is the rcContourSet object to which the contour belongs.
|
||||||
|
float worldX = cset.bmin[0] + vertX * cset.cs;
|
||||||
|
float worldY = cset.bmin[1] + vertY * cset.ch;
|
||||||
|
float worldZ = cset.bmin[2] + vertZ * cset.cs;
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see rcContourSet
|
||||||
|
|
||||||
|
@var rcContour::verts
|
||||||
|
@par
|
||||||
|
|
||||||
|
The simplified contour is a version of the raw contour with all
|
||||||
|
'unnecessary' vertices removed. Whether a vertex is
|
||||||
|
considered unnecessary depends on the contour build process.
|
||||||
|
|
||||||
|
The data format is as follows: (x, y, z, r) * #nverts
|
||||||
|
|
||||||
|
A contour edge is formed by the current and next vertex. The r-value
|
||||||
|
represents region and connection information for the edge. For example:
|
||||||
|
|
||||||
|
@code
|
||||||
|
int r = verts[i*4+3];
|
||||||
|
|
||||||
|
int regionId = r & RC_CONTOUR_REG_MASK;
|
||||||
|
|
||||||
|
if (r & RC_BORDER_VERTEX)
|
||||||
|
{
|
||||||
|
// The edge represents a solid border.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r & RC_AREA_BORDER)
|
||||||
|
{
|
||||||
|
// The edge represents a transition between different areas.
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@var rcContour::rverts
|
||||||
|
@par
|
||||||
|
|
||||||
|
See #verts for information on element layout.
|
||||||
|
|
||||||
|
@struct rcContourSet
|
||||||
|
@par
|
||||||
|
|
||||||
|
All contours within the set share the minimum bounds and cell sizes of the set.
|
||||||
|
|
||||||
|
The standard process for building a contour set is to allocate it
|
||||||
|
using #rcAllocContourSet, then initialize it using #rcBuildContours.
|
||||||
|
|
||||||
|
@see rcAllocContourSet, rcFreeContourSet, rcBuildContours
|
||||||
|
|
||||||
|
@struct rcPolyMesh
|
||||||
|
@par
|
||||||
|
|
||||||
|
A mesh of potentially overlapping convex polygons of between three
|
||||||
|
and #nvp vertices. The mesh exists within the context of an axis-aligned
|
||||||
|
bounding box (AABB) with vertices laid out in an evenly spaced grid, based
|
||||||
|
on the values of #cs and #ch.
|
||||||
|
|
||||||
|
The standard process for building a contour set is to allocate it using
|
||||||
|
#rcAllocPolyMesh, the initialize it using #rcBuildPolyMesh
|
||||||
|
|
||||||
|
Example of iterating the polygons:
|
||||||
|
|
||||||
|
@code
|
||||||
|
// Where mesh is a reference to a rcPolyMesh object.
|
||||||
|
|
||||||
|
const int nvp = mesh.nvp;
|
||||||
|
const float cs = mesh.cs;
|
||||||
|
const float ch = mesh.ch;
|
||||||
|
const float* orig = mesh.bmin;
|
||||||
|
|
||||||
|
for (int i = 0; i < mesh.npolys; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* p = &mesh.polys[i*nvp*2];
|
||||||
|
|
||||||
|
// Iterate the vertices.
|
||||||
|
unsigned short vi[3]; // The vertex indices.
|
||||||
|
for (int j = 0; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == RC_MESH_NULL_IDX)
|
||||||
|
break; // End of vertices.
|
||||||
|
|
||||||
|
if (p[j + nvp] == RC_MESH_NULL_IDX)
|
||||||
|
{
|
||||||
|
// The edge beginning with this vertex is a solid border.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The edge beginning with this vertex connects to
|
||||||
|
// polygon p[j + nvp].
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to world space.
|
||||||
|
const unsigned short* v = &mesh.verts[p[j]*3];
|
||||||
|
const float x = orig[0] + v[0]*cs;
|
||||||
|
const float y = orig[1] + v[1]*ch;
|
||||||
|
const float z = orig[2] + v[2]*cs;
|
||||||
|
// Do something with the vertices.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see rcAllocPolyMesh, rcFreePolyMesh, rcBuildPolyMesh
|
||||||
|
|
||||||
|
@var rcPolyMesh::verts
|
||||||
|
@par
|
||||||
|
|
||||||
|
The values of #bmin ,#cs, and #ch are used to convert vertex coordinates
|
||||||
|
to world space as follows:
|
||||||
|
|
||||||
|
@code
|
||||||
|
float worldX = bmin[0] + verts[i*3+0] * cs
|
||||||
|
float worldY = bmin[1] + verts[i*3+1] * ch
|
||||||
|
float worldZ = bmin[2] + verts[i*3+2] * cs
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@var rcPolyMesh::polys
|
||||||
|
@par
|
||||||
|
|
||||||
|
Each entry is <tt>2 * #nvp</tt> in length. The first half of the entry
|
||||||
|
contains the indices of the polygon. The first instance of #RC_MESH_NULL_IDX
|
||||||
|
indicates the end of the indices for the entry. The second half contains
|
||||||
|
indices to neighbor polygons. A value of #RC_MESH_NULL_IDX indicates no
|
||||||
|
connection for the associated edge. (I.e. The edge is a solid border.)
|
||||||
|
|
||||||
|
For example:
|
||||||
|
<pre>
|
||||||
|
nvp = 6
|
||||||
|
For the entry: (1, 3, 4, 8, RC_MESH_NULL_IDX, RC_MESH_NULL_IDX,
|
||||||
|
18, RC_MESH_NULL_IDX , 21, RC_MESH_NULL_IDX, RC_MESH_NULL_IDX, RC_MESH_NULL_IDX)
|
||||||
|
|
||||||
|
(1, 3, 4, 8) defines a polygon with 4 vertices.
|
||||||
|
Edge 1->3 is shared with polygon 18.
|
||||||
|
Edge 4->8 is shared with polygon 21.
|
||||||
|
Edges 3->4 and 4->8 are border edges not shared with any other polygon.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
@var rcPolyMesh::areas
|
||||||
|
@par
|
||||||
|
|
||||||
|
The standard build process assigns the value of #RC_WALKABLE_AREA to all walkable polygons.
|
||||||
|
This value can then be changed to meet user requirements.
|
||||||
|
|
||||||
|
@struct rcPolyMeshDetail
|
||||||
|
@par
|
||||||
|
|
||||||
|
The detail mesh is made up of triangle sub-meshes that provide extra
|
||||||
|
height detail for each polygon in its assoicated polygon mesh.
|
||||||
|
|
||||||
|
The standard process for building a detail mesh is to allocate it
|
||||||
|
using #rcAllocPolyMeshDetail, then build it using #rcBuildPolyMeshDetail.
|
||||||
|
|
||||||
|
See the individual field definitions for details realted to the structure
|
||||||
|
the mesh.
|
||||||
|
|
||||||
|
@see rcAllocPolyMeshDetail, rcFreePolyMeshDetail, rcBuildPolyMeshDetail, rcPolyMesh
|
||||||
|
|
||||||
|
@var rcPolyMeshDetail::meshes
|
||||||
|
@par
|
||||||
|
|
||||||
|
[(baseVertIndex, vertCount, baseTriIndex, triCount) * #nmeshes]
|
||||||
|
|
||||||
|
Maximum number of vertices per sub-mesh: 127<br/>
|
||||||
|
Maximum number of triangles per sub-mesh: 255
|
||||||
|
|
||||||
|
The sub-meshes are stored in the same order as the polygons from the
|
||||||
|
rcPolyMesh they represent. E.g. rcPolyMeshDetail sub-mesh 5 is associated
|
||||||
|
with #rcPolyMesh polygon 5.
|
||||||
|
|
||||||
|
Example of iterating the triangles in a sub-mesh.
|
||||||
|
|
||||||
|
@code
|
||||||
|
// Where dmesh is a reference to a rcPolyMeshDetail object.
|
||||||
|
|
||||||
|
// Iterate the sub-meshes. (One for each source polygon.)
|
||||||
|
for (int i = 0; i < dmesh.nmeshes; ++i)
|
||||||
|
{
|
||||||
|
const unsigned int* meshDef = &dmesh.meshes[i*4];
|
||||||
|
const unsigned int baseVerts = meshDef[0];
|
||||||
|
const unsigned int baseTri = meshDef[2];
|
||||||
|
const int ntris = (int)meshDef[3];
|
||||||
|
|
||||||
|
const float* verts = &dmesh.verts[baseVerts*3];
|
||||||
|
const unsigned char* tris = &dmesh.tris[baseTri*4];
|
||||||
|
|
||||||
|
// Iterate the sub-mesh's triangles.
|
||||||
|
for (int j = 0; j < ntris; ++j)
|
||||||
|
{
|
||||||
|
const float x = verts[tris[j*4+0]*3];
|
||||||
|
const float y = verts[tris[j*4+1]*3];
|
||||||
|
const float z = verts[tris[j*4+2]*3];
|
||||||
|
// Do something with the vertex.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@var rcPolyMeshDetail::verts
|
||||||
|
@par
|
||||||
|
|
||||||
|
[(x, y, z) * #nverts]
|
||||||
|
|
||||||
|
The vertices are grouped by sub-mesh and will contain duplicates since
|
||||||
|
each sub-mesh is independently defined.
|
||||||
|
|
||||||
|
The first group of vertices for each sub-mesh are in the same order as
|
||||||
|
the vertices for the sub-mesh's associated PolyMesh polygon. These
|
||||||
|
vertices are followed by any additional detail vertices. So it the
|
||||||
|
associated polygon has 5 vertices, the sub-mesh will have a minimum
|
||||||
|
of 5 vertices and the first 5 vertices will be equivalent to the 5
|
||||||
|
polygon vertices.
|
||||||
|
|
||||||
|
@var rcPolyMeshDetail::tris
|
||||||
|
@par
|
||||||
|
|
||||||
|
[(vertIndexA, vertIndexB, vertIndexC, flags) * #ntris]
|
||||||
|
|
||||||
|
The triangles are grouped by sub-mesh.
|
||||||
|
|
||||||
|
<b>Vertex Indices</b>
|
||||||
|
|
||||||
|
The vertex indices in the triangle array are local to the sub-mesh, not global.
|
||||||
|
To translate into an global index in the vertices array, the values must be
|
||||||
|
offset by the sub-mesh's base vertex index.
|
||||||
|
|
||||||
|
Example: If the baseVertexIndex for the sub-mesh is 5 and the triangle entry
|
||||||
|
is (4, 8, 7, 0), then the actual indices for the vertices are (4 + 5, 8 + 5, 7 + 5).
|
||||||
|
|
||||||
|
@b Flags
|
||||||
|
|
||||||
|
The flags entry indicates which edges are internal and which are external to
|
||||||
|
the sub-mesh. Internal edges connect to other triangles within the same sub-mesh.
|
||||||
|
External edges represent portals to other sub-meshes or the null region.
|
||||||
|
|
||||||
|
Each flag is stored in a 2-bit position. Where position 0 is the lowest 2-bits
|
||||||
|
and position 4 is the highest 2-bits:
|
||||||
|
|
||||||
|
<tt>
|
||||||
|
Position 0: Edge AB (>> 0)<br/>
|
||||||
|
Position 1: Edge BC (>> 2)<br/>
|
||||||
|
Position 2: Edge CA (>> 4)<br/>
|
||||||
|
Position 4: Unused<br/>
|
||||||
|
</tt>
|
||||||
|
|
||||||
|
Testing can be performed as follows:
|
||||||
|
|
||||||
|
@code
|
||||||
|
if (((flags >> 2) & 0x3) != 0)
|
||||||
|
{
|
||||||
|
// Edge BC is an external edge.
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@fn void rcSetCon(rcCompactSpan &s, int dir, int i)
|
||||||
|
@par
|
||||||
|
|
||||||
|
This function is used by the build process. It is rarely of use to end users.
|
||||||
|
|
||||||
|
@see #rcCompactHeightfield, #rcCompactSpan
|
||||||
|
|
||||||
|
@fn int rcGetCon(const rcCompactSpan &s, int dir)
|
||||||
|
@par
|
||||||
|
|
||||||
|
Can be used to locate neighbor spans in a compact heightfield. See the
|
||||||
|
#rcCompactHeightfield documentation for details on its use.
|
||||||
|
|
||||||
|
@see #rcCompactHeightfield, #rcCompactSpan
|
||||||
|
|
||||||
|
@fn int rcGetDirOffsetX(int dir)
|
||||||
|
@par
|
||||||
|
|
||||||
|
The value of @p dir will be automatically wrapped. So a value of 6 will be interpreted as 2.
|
||||||
|
|
||||||
|
See the #rcCompactHeightfield documentation for usage details.
|
||||||
|
|
||||||
|
@fn int rcGetDirOffsetY(int dir)
|
||||||
|
@par
|
||||||
|
|
||||||
|
The value of @p dir will be automatically wrapped. So a value of 6 will be interpreted as 2.
|
||||||
|
|
||||||
|
See the #rcCompactHeightfield documentation for usage details.
|
||||||
|
|
||||||
|
*/
|
||||||
BIN
dep/recastnavigation/Docs/Images/recast_intro.png
Normal file
BIN
dep/recastnavigation/Docs/Images/recast_intro.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 370 KiB |
64
dep/recastnavigation/Docs/Readme.txt
Normal file
64
dep/recastnavigation/Docs/Readme.txt
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
This directory contains source for the documentation. It is also the
|
||||||
|
build target for doxygen output.
|
||||||
|
|
||||||
|
Directory Layout
|
||||||
|
|
||||||
|
. (Docs root)
|
||||||
|
|
||||||
|
High level content and format files. (E.g. css, header, footer.)
|
||||||
|
|
||||||
|
./Conceptual
|
||||||
|
|
||||||
|
Conceptual (non-api) documentation such as overviews, how-to's, etc.
|
||||||
|
The main index page content is also in this directory.
|
||||||
|
|
||||||
|
./Extern
|
||||||
|
|
||||||
|
API documentation that is located outside the source files.
|
||||||
|
|
||||||
|
When the API documentation gets too big or complex for the header
|
||||||
|
and source files, it goes in this directory.
|
||||||
|
|
||||||
|
./Images
|
||||||
|
|
||||||
|
Images related to the documentation.
|
||||||
|
|
||||||
|
./html
|
||||||
|
|
||||||
|
The target for the Doxygen build. (Created during the build process.)
|
||||||
|
|
||||||
|
Miscellany
|
||||||
|
|
||||||
|
One of the requirements for the API documentation is that it
|
||||||
|
has the minimum possible impact on the declarations in the
|
||||||
|
header files. So, in general, the header file declarations only
|
||||||
|
contain summary documentation. The detail documentation
|
||||||
|
is placed as follows:
|
||||||
|
|
||||||
|
1. If an element is defined in a cpp file, then place
|
||||||
|
the detail documentation in the source file.
|
||||||
|
2. If an element does not have an associated cpp file, then
|
||||||
|
place the detail documentation at the end of the header file.
|
||||||
|
3. If there is a lot of detail documentation cluttering up
|
||||||
|
the end of a header file, then the content is moved to
|
||||||
|
a separate file in the Extern directory.
|
||||||
|
|
||||||
|
Building the Documentation
|
||||||
|
|
||||||
|
1. Download and install the appropriate Doxygen version. (See the first
|
||||||
|
line in the Doxyfile for the current version.)
|
||||||
|
2. Run "doxygen" in the project root directory. (The location of the Doxyfile.)
|
||||||
|
No arguments are required.
|
||||||
|
|
||||||
|
The generated html files will be located in the /Docs/html directory.
|
||||||
|
|
||||||
|
If you want to "version" the documentation, you can set the PROJECT_NUMBER
|
||||||
|
setting in the Doxyfile. E.g. PROJECT_NUMBER = "(2014-04-23)". The project
|
||||||
|
number will be added to the header of the documentation.
|
||||||
|
E.g. "Recast Navigation (2014-04-23)"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
21
dep/recastnavigation/Docs/footer.html
Normal file
21
dep/recastnavigation/Docs/footer.html
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<!-- HTML footer for doxygen 1.8.6-->
|
||||||
|
<!-- start footer part -->
|
||||||
|
<!--BEGIN GENERATE_TREEVIEW-->
|
||||||
|
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
|
||||||
|
<ul>
|
||||||
|
$navpath
|
||||||
|
<a href="https://github.com/memononen/recastnavigation">Project Home</a>
|
||||||
|
| <a href="./License.html">Licence: ZLib</a>
|
||||||
|
| Copyright (c) 2009-2014 Mikko Mononen
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<!--END GENERATE_TREEVIEW-->
|
||||||
|
<!--BEGIN !GENERATE_TREEVIEW-->
|
||||||
|
<hr class="footer"/><address class="footer"><small>
|
||||||
|
<a href="https://github.com/memononen/recastnavigation">Project Home</a>
|
||||||
|
| <a href="./License.html">Licence: ZLib</a>
|
||||||
|
| Copyright (c) 2009-2014 Mikko Mononen
|
||||||
|
</small></address>
|
||||||
|
<!--END !GENERATE_TREEVIEW-->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
55
dep/recastnavigation/Docs/header.html
Normal file
55
dep/recastnavigation/Docs/header.html
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
<!-- HTML header for doxygen 1.8.6-->
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||||
|
<meta name="generator" content="Doxygen $doxygenversion"/>
|
||||||
|
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
|
||||||
|
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
|
||||||
|
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
||||||
|
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
||||||
|
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
||||||
|
$treeview
|
||||||
|
$search
|
||||||
|
$mathjax
|
||||||
|
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
||||||
|
$extrastylesheet
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||||
|
|
||||||
|
<!--BEGIN TITLEAREA-->
|
||||||
|
<div id="titlearea">
|
||||||
|
<table cellspacing="0" cellpadding="0">
|
||||||
|
<tbody>
|
||||||
|
<tr style="height: 56px;">
|
||||||
|
<!--BEGIN PROJECT_LOGO-->
|
||||||
|
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
|
||||||
|
<!--END PROJECT_LOGO-->
|
||||||
|
<!--BEGIN PROJECT_NAME-->
|
||||||
|
<td style="padding-left: 0.5em;">
|
||||||
|
<div id="projectname">$projectname
|
||||||
|
<!--BEGIN PROJECT_NUMBER--> <span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
|
||||||
|
</div>
|
||||||
|
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
|
||||||
|
</td>
|
||||||
|
<!--END PROJECT_NAME-->
|
||||||
|
<!--BEGIN !PROJECT_NAME-->
|
||||||
|
<!--BEGIN PROJECT_BRIEF-->
|
||||||
|
<td style="padding-left: 0.5em;">
|
||||||
|
<div id="projectbrief">$projectbrief</div>
|
||||||
|
</td>
|
||||||
|
<!--END PROJECT_BRIEF-->
|
||||||
|
<!--END !PROJECT_NAME-->
|
||||||
|
<!--BEGIN DISABLE_INDEX-->
|
||||||
|
<!--BEGIN SEARCHENGINE-->
|
||||||
|
<td>$searchbox</td>
|
||||||
|
<!--END SEARCHENGINE-->
|
||||||
|
<!--END DISABLE_INDEX-->
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--END TITLEAREA-->
|
||||||
|
<!-- end header part -->
|
||||||
2342
dep/recastnavigation/Doxyfile
Normal file
2342
dep/recastnavigation/Doxyfile
Normal file
File diff suppressed because it is too large
Load diff
62
dep/recastnavigation/README.md
Normal file
62
dep/recastnavigation/README.md
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
|
||||||
|
Recast & Detour
|
||||||
|
===============
|
||||||
|
|
||||||
|
[](https://bitdeli.com/free "Bitdeli Badge")
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Recast
|
||||||
|
|
||||||
|
Recast is state of the art navigation mesh construction toolset for games.
|
||||||
|
|
||||||
|
* It is automatic, which means that you can throw any level geometry at it and you will get robust mesh out
|
||||||
|
* It is fast which means swift turnaround times for level designers
|
||||||
|
* It is open source so it comes with full source and you can customize it to your heart's content.
|
||||||
|
|
||||||
|
The Recast process starts with constructing a voxel mold from a level geometry
|
||||||
|
and then casting a navigation mesh over it. The process consists of three steps,
|
||||||
|
building the voxel mold, partitioning the mold into simple regions, peeling off
|
||||||
|
the regions as simple polygons.
|
||||||
|
|
||||||
|
1. The voxel mold is build from the input triangle mesh by rasterizing the triangles into a multi-layer heightfield. Some simple filters are then applied to the mold to prune out locations where the character would not be able to move.
|
||||||
|
2. The walkable areas described by the mold are divided into simple overlayed 2D regions. The resulting regions have only one non-overlapping contour, which simplifies the final step of the process tremendously.
|
||||||
|
3. The navigation polygons are peeled off from the regions by first tracing the boundaries and then simplifying them. The resulting polygons are finally converted to convex polygons which makes them perfect for pathfinding and spatial reasoning about the level.
|
||||||
|
|
||||||
|
|
||||||
|
## Detour
|
||||||
|
|
||||||
|
Recast is accompanied with Detour, path-finding and spatial reasoning toolkit. You can use any navigation mesh with Detour, but of course the data generated with Recast fits perfectly.
|
||||||
|
|
||||||
|
Detour offers simple static navigation mesh which is suitable for many simple cases, as well as tiled navigation mesh which allows you to plug in and out pieces of the mesh. The tiled mesh allows you to create systems where you stream new navigation data in and out as the player progresses the level, or you may regenerate tiles as the world changes.
|
||||||
|
|
||||||
|
|
||||||
|
## Recast Demo
|
||||||
|
|
||||||
|
You can find a comprehensive demo project in RecastDemo folder. It is a kitchen sink demo containing all the functionality of the library. If you are new to Recast & Detour, check out [Sample_SoloMesh.cpp](/RecastDemo/Source/Sample_SoloMesh.cpp) to get started with building navmeshes and [NavMeshTesterTool.cpp](/RecastDemo/Source/NavMeshTesterTool.cpp) to see how Detour can be used to find paths.
|
||||||
|
|
||||||
|
### Building RecastDemo
|
||||||
|
|
||||||
|
RecastDemo uses [premake4](http://industriousone.com/premake) to build platform specific projects, now is good time to install it if you don't have it already. To build *RecasDemo*, in your favorite terminal navigate into the `RecastDemo` folder, then:
|
||||||
|
|
||||||
|
- *OS X*: `premake4 xcode4`
|
||||||
|
- *Windows*: `premake4 vs2010`
|
||||||
|
- *Linux*: `premake4 gmake`
|
||||||
|
|
||||||
|
See premake4 documentation for full list of supported build file types. The projects will be created in `RecastDemo/Build` folder. And after you have compiled the project, the *RecastDemo* executable will be located in `RecastDemo/Bin` folder.
|
||||||
|
|
||||||
|
|
||||||
|
## Integrating with your own project
|
||||||
|
|
||||||
|
It is recommended to add the source directories `DebugUtils`, `Detour`, `DetourCrowd`, `DetourTileCache`, and `Recast` into your own project depending on which parts of the project you need. For example your level building tool could include DebugUtils, Recast, and Detour, and your game runtime could just include Detour.
|
||||||
|
|
||||||
|
|
||||||
|
## Discuss
|
||||||
|
|
||||||
|
- Discuss Recast & Detour: http://groups.google.com/group/recastnavigation
|
||||||
|
- Development blog: http://digestingduck.blogspot.com/
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Recast & Detour is licensed under ZLib license, see License.txt for more information.
|
||||||
40
dep/recastnavigation/Recast/CMakeLists.txt
Normal file
40
dep/recastnavigation/Recast/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# MaNGOS is a full featured server for World of Warcraft, supporting
|
||||||
|
# the following clients: 1.12.x, 2.4.3, 3.2.5a, 4.2.3 and 5.4.8
|
||||||
|
#
|
||||||
|
# Copyright (C) 2005-2014 MaNGOS project <http://getmangos.eu>
|
||||||
|
#
|
||||||
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# ***** END GPL LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
# World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||||
|
# and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# Define the Recast library
|
||||||
|
file(GLOB sources Source/*.cpp)
|
||||||
|
file(GLOB headers Include/*.h)
|
||||||
|
|
||||||
|
set(Recast_LIB_SRCS ${sources} ${headers})
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/Include"
|
||||||
|
)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# Build the Recast library
|
||||||
|
add_library(recast STATIC ${Recast_LIB_SRCS})
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,23 +19,45 @@
|
||||||
#ifndef RECASTALLOC_H
|
#ifndef RECASTALLOC_H
|
||||||
#define RECASTALLOC_H
|
#define RECASTALLOC_H
|
||||||
|
|
||||||
|
/// Provides hint values to the memory allocator on how long the
|
||||||
|
/// memory is expected to be used.
|
||||||
enum rcAllocHint
|
enum rcAllocHint
|
||||||
{
|
{
|
||||||
RC_ALLOC_PERM, // Memory persist after a function call.
|
RC_ALLOC_PERM, ///< Memory will persist after a function call.
|
||||||
RC_ALLOC_TEMP // Memory used temporarily within a function.
|
RC_ALLOC_TEMP ///< Memory used temporarily within a function.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A memory allocation function.
|
||||||
|
// @param[in] size The size, in bytes of memory, to allocate.
|
||||||
|
// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use.
|
||||||
|
// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||||
|
/// @see rcAllocSetCustom
|
||||||
typedef void* (rcAllocFunc)(int size, rcAllocHint hint);
|
typedef void* (rcAllocFunc)(int size, rcAllocHint hint);
|
||||||
|
|
||||||
|
/// A memory deallocation function.
|
||||||
|
/// @param[in] ptr A pointer to a memory block previously allocated using #rcAllocFunc.
|
||||||
|
/// @see rcAllocSetCustom
|
||||||
typedef void (rcFreeFunc)(void* ptr);
|
typedef void (rcFreeFunc)(void* ptr);
|
||||||
|
|
||||||
|
/// Sets the base custom allocation functions to be used by Recast.
|
||||||
|
/// @param[in] allocFunc The memory allocation function to be used by #rcAlloc
|
||||||
|
/// @param[in] freeFunc The memory de-allocation function to be used by #rcFree
|
||||||
void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc);
|
void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc);
|
||||||
|
|
||||||
|
/// Allocates a memory block.
|
||||||
|
/// @param[in] size The size, in bytes of memory, to allocate.
|
||||||
|
/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
|
||||||
|
/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||||
|
/// @see rcFree
|
||||||
void* rcAlloc(int size, rcAllocHint hint);
|
void* rcAlloc(int size, rcAllocHint hint);
|
||||||
|
|
||||||
|
/// Deallocates a memory block.
|
||||||
|
/// @param[in] ptr A pointer to a memory block previously allocated using #rcAlloc.
|
||||||
|
/// @see rcAlloc
|
||||||
void rcFree(void* ptr);
|
void rcFree(void* ptr);
|
||||||
|
|
||||||
|
|
||||||
|
/// A simple dynamic array of integers.
|
||||||
// Simple dynamic array ints.
|
|
||||||
class rcIntArray
|
class rcIntArray
|
||||||
{
|
{
|
||||||
int* m_data;
|
int* m_data;
|
||||||
|
|
@ -43,26 +65,59 @@ class rcIntArray
|
||||||
inline rcIntArray(const rcIntArray&);
|
inline rcIntArray(const rcIntArray&);
|
||||||
inline rcIntArray& operator=(const rcIntArray&);
|
inline rcIntArray& operator=(const rcIntArray&);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/// Constructs an instance with an initial array size of zero.
|
||||||
inline rcIntArray() : m_data(0), m_size(0), m_cap(0) {}
|
inline rcIntArray() : m_data(0), m_size(0), m_cap(0) {}
|
||||||
|
|
||||||
|
/// Constructs an instance initialized to the specified size.
|
||||||
|
/// @param[in] n The initial size of the integer array.
|
||||||
inline rcIntArray(int n) : m_data(0), m_size(0), m_cap(0) { resize(n); }
|
inline rcIntArray(int n) : m_data(0), m_size(0), m_cap(0) { resize(n); }
|
||||||
inline ~rcIntArray() { rcFree(m_data); }
|
inline ~rcIntArray() { rcFree(m_data); }
|
||||||
|
|
||||||
|
/// Specifies the new size of the integer array.
|
||||||
|
/// @param[in] n The new size of the integer array.
|
||||||
void resize(int n);
|
void resize(int n);
|
||||||
|
|
||||||
|
/// Push the specified integer onto the end of the array and increases the size by one.
|
||||||
|
/// @param[in] item The new value.
|
||||||
inline void push(int item) { resize(m_size+1); m_data[m_size-1] = item; }
|
inline void push(int item) { resize(m_size+1); m_data[m_size-1] = item; }
|
||||||
|
|
||||||
|
/// Returns the value at the end of the array and reduces the size by one.
|
||||||
|
/// @return The value at the end of the array.
|
||||||
inline int pop() { if (m_size > 0) m_size--; return m_data[m_size]; }
|
inline int pop() { if (m_size > 0) m_size--; return m_data[m_size]; }
|
||||||
|
|
||||||
|
/// The value at the specified array index.
|
||||||
|
/// @warning Does not provide overflow protection.
|
||||||
|
/// @param[in] i The index of the value.
|
||||||
inline const int& operator[](int i) const { return m_data[i]; }
|
inline const int& operator[](int i) const { return m_data[i]; }
|
||||||
|
|
||||||
|
/// The value at the specified array index.
|
||||||
|
/// @warning Does not provide overflow protection.
|
||||||
|
/// @param[in] i The index of the value.
|
||||||
inline int& operator[](int i) { return m_data[i]; }
|
inline int& operator[](int i) { return m_data[i]; }
|
||||||
|
|
||||||
|
/// The current size of the integer array.
|
||||||
inline int size() const { return m_size; }
|
inline int size() const { return m_size; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Simple internal helper class to delete array in scope
|
/// A simple helper class used to delete an array when it goes out of scope.
|
||||||
|
/// @note This class is rarely if ever used by the end user.
|
||||||
template<class T> class rcScopedDelete
|
template<class T> class rcScopedDelete
|
||||||
{
|
{
|
||||||
T* ptr;
|
T* ptr;
|
||||||
inline T* operator=(T* p);
|
inline T* operator=(T* p);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/// Constructs an instance with a null pointer.
|
||||||
inline rcScopedDelete() : ptr(0) {}
|
inline rcScopedDelete() : ptr(0) {}
|
||||||
|
|
||||||
|
/// Constructs an instance with the specified pointer.
|
||||||
|
/// @param[in] p An pointer to an allocated array.
|
||||||
inline rcScopedDelete(T* p) : ptr(p) {}
|
inline rcScopedDelete(T* p) : ptr(p) {}
|
||||||
inline ~rcScopedDelete() { rcFree(ptr); }
|
inline ~rcScopedDelete() { rcFree(ptr); }
|
||||||
|
|
||||||
|
/// The root array pointer.
|
||||||
|
/// @return The root array pointer.
|
||||||
inline operator T*() { return ptr; }
|
inline operator T*() { return ptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
|
// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
|
||||||
# define rcAssert(x) do { (void)sizeof(x); } while(__LINE__==-1,false)
|
# define rcAssert(x) do { (void)sizeof(x); } while((void)(__LINE__==-1),false)
|
||||||
#else
|
#else
|
||||||
# include <assert.h>
|
# include <assert.h>
|
||||||
# define rcAssert assert
|
# define rcAssert assert
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,26 @@ float rcSqrt(float x)
|
||||||
return sqrtf(x);
|
return sqrtf(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @class rcContext
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// This class does not provide logging or timer functionality on its
|
||||||
|
/// own. Both must be provided by a concrete implementation
|
||||||
|
/// by overriding the protected member functions. Also, this class does not
|
||||||
|
/// provide an interface for extracting log messages. (Only adding them.)
|
||||||
|
/// So concrete implementations must provide one.
|
||||||
|
///
|
||||||
|
/// If no logging or timers are required, just pass an instance of this
|
||||||
|
/// class through the Recast build process.
|
||||||
|
///
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// @code
|
||||||
|
/// // Where ctx is an instance of rcContext and filepath is a char array.
|
||||||
|
/// ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath);
|
||||||
|
/// @endcode
|
||||||
void rcContext::log(const rcLogCategory category, const char* format, ...)
|
void rcContext::log(const rcLogCategory category, const char* format, ...)
|
||||||
{
|
{
|
||||||
if (!m_logEnabled)
|
if (!m_logEnabled)
|
||||||
|
|
@ -90,6 +109,28 @@ void rcFreeCompactHeightfield(rcCompactHeightfield* chf)
|
||||||
rcFree(chf);
|
rcFree(chf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet()
|
||||||
|
{
|
||||||
|
rcHeightfieldLayerSet* lset = (rcHeightfieldLayerSet*)rcAlloc(sizeof(rcHeightfieldLayerSet), RC_ALLOC_PERM);
|
||||||
|
memset(lset, 0, sizeof(rcHeightfieldLayerSet));
|
||||||
|
return lset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset)
|
||||||
|
{
|
||||||
|
if (!lset) return;
|
||||||
|
for (int i = 0; i < lset->nlayers; ++i)
|
||||||
|
{
|
||||||
|
rcFree(lset->layers[i].heights);
|
||||||
|
rcFree(lset->layers[i].areas);
|
||||||
|
rcFree(lset->layers[i].cons);
|
||||||
|
}
|
||||||
|
rcFree(lset->layers);
|
||||||
|
rcFree(lset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
rcContourSet* rcAllocContourSet()
|
rcContourSet* rcAllocContourSet()
|
||||||
{
|
{
|
||||||
rcContourSet* cset = (rcContourSet*)rcAlloc(sizeof(rcContourSet), RC_ALLOC_PERM);
|
rcContourSet* cset = (rcContourSet*)rcAlloc(sizeof(rcContourSet), RC_ALLOC_PERM);
|
||||||
|
|
@ -143,7 +184,6 @@ void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh)
|
||||||
rcFree(dmesh);
|
rcFree(dmesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax)
|
void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax)
|
||||||
{
|
{
|
||||||
// Calculate bounding box.
|
// Calculate bounding box.
|
||||||
|
|
@ -163,12 +203,16 @@ void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int*
|
||||||
*h = (int)((bmax[2] - bmin[2])/cs+0.5f);
|
*h = (int)((bmax[2] - bmin[2])/cs+0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rcCreateHeightfield(rcContext* /*ctx*/, rcHeightfield& hf, int width, int height,
|
/// @par
|
||||||
|
///
|
||||||
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
|
///
|
||||||
|
/// @see rcAllocHeightfield, rcHeightfield
|
||||||
|
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.
|
rcIgnoreUnused(ctx);
|
||||||
// rcAssert(ctx);
|
|
||||||
|
|
||||||
hf.width = width;
|
hf.width = width;
|
||||||
hf.height = height;
|
hf.height = height;
|
||||||
|
|
@ -192,13 +236,20 @@ static void calcTriNormal(const float* v0, const float* v1, const float* v2, flo
|
||||||
rcVnormalize(norm);
|
rcVnormalize(norm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
|
/// @par
|
||||||
|
///
|
||||||
|
/// Only sets the aread id's for the walkable triangles. Does not alter the
|
||||||
|
/// area id's for unwalkable triangles.
|
||||||
|
///
|
||||||
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
|
///
|
||||||
|
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
|
||||||
|
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.
|
rcIgnoreUnused(ctx);
|
||||||
// rcAssert(ctx);
|
|
||||||
|
|
||||||
const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
|
const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
|
||||||
|
|
||||||
|
|
@ -214,13 +265,20 @@ void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rcClearUnwalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
|
/// @par
|
||||||
|
///
|
||||||
|
/// Only sets the aread id's for the unwalkable triangles. Does not alter the
|
||||||
|
/// area id's for walkable triangles.
|
||||||
|
///
|
||||||
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
|
///
|
||||||
|
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
|
||||||
|
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.
|
rcIgnoreUnused(ctx);
|
||||||
// rcAssert(ctx);
|
|
||||||
|
|
||||||
const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
|
const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
|
||||||
|
|
||||||
|
|
@ -236,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.
|
rcIgnoreUnused(ctx);
|
||||||
// rcAssert(ctx);
|
|
||||||
|
|
||||||
const int w = hf.width;
|
const int w = hf.width;
|
||||||
const int h = hf.height;
|
const int h = hf.height;
|
||||||
|
|
@ -258,6 +315,15 @@ int rcGetHeightFieldSpanCount(rcContext* /*ctx*/, rcHeightfield& hf)
|
||||||
return spanCount;
|
return spanCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// This is just the beginning of the process of fully building a compact heightfield.
|
||||||
|
/// Various filters may be applied applied, then the distance field and regions built.
|
||||||
|
/// E.g: #rcBuildDistanceField and #rcBuildRegions
|
||||||
|
///
|
||||||
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
|
///
|
||||||
|
/// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig
|
||||||
bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb,
|
bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb,
|
||||||
rcHeightfield& hf, rcCompactHeightfield& chf)
|
rcHeightfield& hf, rcCompactHeightfield& chf)
|
||||||
{
|
{
|
||||||
|
|
@ -369,13 +435,13 @@ bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const i
|
||||||
if ((top - bot) >= walkableHeight && rcAbs((int)ns.y - (int)s.y) <= walkableClimb)
|
if ((top - bot) >= walkableHeight && rcAbs((int)ns.y - (int)s.y) <= walkableClimb)
|
||||||
{
|
{
|
||||||
// Mark direction as walkable.
|
// Mark direction as walkable.
|
||||||
const int idx = k - (int)nc.index;
|
const int lidx = k - (int)nc.index;
|
||||||
if (idx < 0 || idx > MAX_LAYERS)
|
if (lidx < 0 || lidx > MAX_LAYERS)
|
||||||
{
|
{
|
||||||
tooHighNeighbour = rcMax(tooHighNeighbour, idx);
|
tooHighNeighbour = rcMax(tooHighNeighbour, lidx);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
rcSetCon(s, dir, idx);
|
rcSetCon(s, dir, lidx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,24 +33,45 @@ static void rcFreeDefault(void *ptr)
|
||||||
static rcAllocFunc* sRecastAllocFunc = rcAllocDefault;
|
static rcAllocFunc* sRecastAllocFunc = rcAllocDefault;
|
||||||
static rcFreeFunc* sRecastFreeFunc = rcFreeDefault;
|
static rcFreeFunc* sRecastFreeFunc = rcFreeDefault;
|
||||||
|
|
||||||
|
/// @see rcAlloc, rcFree
|
||||||
void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc)
|
void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc)
|
||||||
{
|
{
|
||||||
sRecastAllocFunc = allocFunc ? allocFunc : rcAllocDefault;
|
sRecastAllocFunc = allocFunc ? allocFunc : rcAllocDefault;
|
||||||
sRecastFreeFunc = freeFunc ? freeFunc : rcFreeDefault;
|
sRecastFreeFunc = freeFunc ? freeFunc : rcFreeDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @see rcAllocSetCustom
|
||||||
void* rcAlloc(int size, rcAllocHint hint)
|
void* rcAlloc(int size, rcAllocHint hint)
|
||||||
{
|
{
|
||||||
return sRecastAllocFunc(size, hint);
|
return sRecastAllocFunc(size, hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// @warning This function leaves the value of @p ptr unchanged. So it still
|
||||||
|
/// points to the same (now invalid) location, and not to null.
|
||||||
|
///
|
||||||
|
/// @see rcAllocSetCustom
|
||||||
void rcFree(void* ptr)
|
void rcFree(void* ptr)
|
||||||
{
|
{
|
||||||
if (ptr)
|
if (ptr)
|
||||||
sRecastFreeFunc(ptr);
|
sRecastFreeFunc(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @class rcIntArray
|
||||||
|
///
|
||||||
|
/// While it is possible to pre-allocate a specific array size during
|
||||||
|
/// construction or by using the #resize method, certain methods will
|
||||||
|
/// automatically resize the array as needed.
|
||||||
|
///
|
||||||
|
/// @warning The array memory is not initialized to zero when the size is
|
||||||
|
/// manually set during construction or when using #resize.
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// Using this method ensures the array is at least large enough to hold
|
||||||
|
/// the specified number of elements. This can improve performance by
|
||||||
|
/// avoiding auto-resizing during use.
|
||||||
void rcIntArray::resize(int n)
|
void rcIntArray::resize(int n)
|
||||||
{
|
{
|
||||||
if (n > m_cap)
|
if (n > m_cap)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,14 @@
|
||||||
#include "RecastAlloc.h"
|
#include "RecastAlloc.h"
|
||||||
#include "RecastAssert.h"
|
#include "RecastAssert.h"
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// Basically, any spans that are closer to a boundary or obstruction than the specified radius
|
||||||
|
/// are marked as unwalkable.
|
||||||
|
///
|
||||||
|
/// This method is usually called immediately after the heightfield has been built.
|
||||||
|
///
|
||||||
|
/// @see rcCompactHeightfield, rcBuildCompactHeightfield, rcConfig::walkableRadius
|
||||||
bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf)
|
bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf)
|
||||||
{
|
{
|
||||||
rcAssert(ctx);
|
rcAssert(ctx);
|
||||||
|
|
@ -54,15 +61,27 @@ bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf)
|
||||||
const rcCompactCell& c = chf.cells[x+y*w];
|
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 i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||||
{
|
{
|
||||||
if (chf.areas[i] != RC_NULL_AREA)
|
if (chf.areas[i] == RC_NULL_AREA)
|
||||||
|
{
|
||||||
|
dist[i] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
const rcCompactSpan& s = chf.spans[i];
|
const rcCompactSpan& s = chf.spans[i];
|
||||||
int nc = 0;
|
int nc = 0;
|
||||||
for (int dir = 0; dir < 4; ++dir)
|
for (int dir = 0; dir < 4; ++dir)
|
||||||
{
|
{
|
||||||
if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
|
if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
|
||||||
|
{
|
||||||
|
const int nx = x + rcGetDirOffsetX(dir);
|
||||||
|
const int ny = y + rcGetDirOffsetY(dir);
|
||||||
|
const int nidx = (int)chf.cells[nx+ny*w].index + rcGetCon(s, dir);
|
||||||
|
if (chf.areas[nidx] != RC_NULL_AREA)
|
||||||
|
{
|
||||||
nc++;
|
nc++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// At least one missing neighbour.
|
// At least one missing neighbour.
|
||||||
if (nc != 4)
|
if (nc != 4)
|
||||||
dist[i] = 0;
|
dist[i] = 0;
|
||||||
|
|
@ -213,7 +232,12 @@ static void insertSort(unsigned char* a, const int n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// This filter is usually applied after applying area id's using functions
|
||||||
|
/// such as #rcMarkBoxArea, #rcMarkConvexPolyArea, and #rcMarkCylinderArea.
|
||||||
|
///
|
||||||
|
/// @see rcCompactHeightfield
|
||||||
bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf)
|
bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf)
|
||||||
{
|
{
|
||||||
rcAssert(ctx);
|
rcAssert(ctx);
|
||||||
|
|
@ -288,6 +312,11 @@ bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// The value of spacial parameters are in world units.
|
||||||
|
///
|
||||||
|
/// @see rcCompactHeightfield, rcMedianFilterWalkableArea
|
||||||
void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigned char areaId,
|
void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigned char areaId,
|
||||||
rcCompactHeightfield& chf)
|
rcCompactHeightfield& chf)
|
||||||
{
|
{
|
||||||
|
|
@ -322,6 +351,7 @@ void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigne
|
||||||
rcCompactSpan& s = chf.spans[i];
|
rcCompactSpan& s = chf.spans[i];
|
||||||
if ((int)s.y >= miny && (int)s.y <= maxy)
|
if ((int)s.y >= miny && (int)s.y <= maxy)
|
||||||
{
|
{
|
||||||
|
if (chf.areas[i] != RC_NULL_AREA)
|
||||||
chf.areas[i] = areaId;
|
chf.areas[i] = areaId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -347,6 +377,14 @@ static int pointInPoly(int nvert, const float* verts, const float* p)
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// The value of spacial parameters are in world units.
|
||||||
|
///
|
||||||
|
/// The y-values of the polygon vertices are ignored. So the polygon is effectively
|
||||||
|
/// projected onto the xz-plane at @p hmin, then extruded to @p hmax.
|
||||||
|
///
|
||||||
|
/// @see rcCompactHeightfield, rcMedianFilterWalkableArea
|
||||||
void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts,
|
void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts,
|
||||||
const float hmin, const float hmax, unsigned char areaId,
|
const float hmin, const float hmax, unsigned char areaId,
|
||||||
rcCompactHeightfield& chf)
|
rcCompactHeightfield& chf)
|
||||||
|
|
@ -393,6 +431,8 @@ void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts,
|
||||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||||
{
|
{
|
||||||
rcCompactSpan& s = chf.spans[i];
|
rcCompactSpan& s = chf.spans[i];
|
||||||
|
if (chf.areas[i] == RC_NULL_AREA)
|
||||||
|
continue;
|
||||||
if ((int)s.y >= miny && (int)s.y <= maxy)
|
if ((int)s.y >= miny && (int)s.y <= maxy)
|
||||||
{
|
{
|
||||||
float p[3];
|
float p[3];
|
||||||
|
|
@ -411,3 +451,152 @@ void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts,
|
||||||
|
|
||||||
ctx->stopTimer(RC_TIMER_MARK_CONVEXPOLY_AREA);
|
ctx->stopTimer(RC_TIMER_MARK_CONVEXPOLY_AREA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rcOffsetPoly(const float* verts, const int nverts, const float offset,
|
||||||
|
float* outVerts, const int maxOutVerts)
|
||||||
|
{
|
||||||
|
const float MITER_LIMIT = 1.20f;
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < nverts; i++)
|
||||||
|
{
|
||||||
|
const int a = (i+nverts-1) % nverts;
|
||||||
|
const int b = i;
|
||||||
|
const int c = (i+1) % nverts;
|
||||||
|
const float* va = &verts[a*3];
|
||||||
|
const float* vb = &verts[b*3];
|
||||||
|
const float* vc = &verts[c*3];
|
||||||
|
float dx0 = vb[0] - va[0];
|
||||||
|
float dy0 = vb[2] - va[2];
|
||||||
|
float d0 = dx0*dx0 + dy0*dy0;
|
||||||
|
if (d0 > 1e-6f)
|
||||||
|
{
|
||||||
|
d0 = 1.0f/rcSqrt(d0);
|
||||||
|
dx0 *= d0;
|
||||||
|
dy0 *= d0;
|
||||||
|
}
|
||||||
|
float dx1 = vc[0] - vb[0];
|
||||||
|
float dy1 = vc[2] - vb[2];
|
||||||
|
float d1 = dx1*dx1 + dy1*dy1;
|
||||||
|
if (d1 > 1e-6f)
|
||||||
|
{
|
||||||
|
d1 = 1.0f/rcSqrt(d1);
|
||||||
|
dx1 *= d1;
|
||||||
|
dy1 *= d1;
|
||||||
|
}
|
||||||
|
const float dlx0 = -dy0;
|
||||||
|
const float dly0 = dx0;
|
||||||
|
const float dlx1 = -dy1;
|
||||||
|
const float dly1 = dx1;
|
||||||
|
float cross = dx1*dy0 - dx0*dy1;
|
||||||
|
float dmx = (dlx0 + dlx1) * 0.5f;
|
||||||
|
float dmy = (dly0 + dly1) * 0.5f;
|
||||||
|
float dmr2 = dmx*dmx + dmy*dmy;
|
||||||
|
bool bevel = dmr2 * MITER_LIMIT*MITER_LIMIT < 1.0f;
|
||||||
|
if (dmr2 > 1e-6f)
|
||||||
|
{
|
||||||
|
const float scale = 1.0f / dmr2;
|
||||||
|
dmx *= scale;
|
||||||
|
dmy *= scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bevel && cross < 0.0f)
|
||||||
|
{
|
||||||
|
if (n+2 >= maxOutVerts)
|
||||||
|
return 0;
|
||||||
|
float d = (1.0f - (dx0*dx1 + dy0*dy1))*0.5f;
|
||||||
|
outVerts[n*3+0] = vb[0] + (-dlx0+dx0*d)*offset;
|
||||||
|
outVerts[n*3+1] = vb[1];
|
||||||
|
outVerts[n*3+2] = vb[2] + (-dly0+dy0*d)*offset;
|
||||||
|
n++;
|
||||||
|
outVerts[n*3+0] = vb[0] + (-dlx1-dx1*d)*offset;
|
||||||
|
outVerts[n*3+1] = vb[1];
|
||||||
|
outVerts[n*3+2] = vb[2] + (-dly1-dy1*d)*offset;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (n+1 >= maxOutVerts)
|
||||||
|
return 0;
|
||||||
|
outVerts[n*3+0] = vb[0] - dmx*offset;
|
||||||
|
outVerts[n*3+1] = vb[1];
|
||||||
|
outVerts[n*3+2] = vb[2] - dmy*offset;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// The value of spacial parameters are in world units.
|
||||||
|
///
|
||||||
|
/// @see rcCompactHeightfield, rcMedianFilterWalkableArea
|
||||||
|
void rcMarkCylinderArea(rcContext* ctx, const float* pos,
|
||||||
|
const float r, const float h, unsigned char areaId,
|
||||||
|
rcCompactHeightfield& chf)
|
||||||
|
{
|
||||||
|
rcAssert(ctx);
|
||||||
|
|
||||||
|
ctx->startTimer(RC_TIMER_MARK_CYLINDER_AREA);
|
||||||
|
|
||||||
|
float bmin[3], bmax[3];
|
||||||
|
bmin[0] = pos[0] - r;
|
||||||
|
bmin[1] = pos[1];
|
||||||
|
bmin[2] = pos[2] - r;
|
||||||
|
bmax[0] = pos[0] + r;
|
||||||
|
bmax[1] = pos[1] + h;
|
||||||
|
bmax[2] = pos[2] + r;
|
||||||
|
const float r2 = r*r;
|
||||||
|
|
||||||
|
int minx = (int)((bmin[0]-chf.bmin[0])/chf.cs);
|
||||||
|
int miny = (int)((bmin[1]-chf.bmin[1])/chf.ch);
|
||||||
|
int minz = (int)((bmin[2]-chf.bmin[2])/chf.cs);
|
||||||
|
int maxx = (int)((bmax[0]-chf.bmin[0])/chf.cs);
|
||||||
|
int maxy = (int)((bmax[1]-chf.bmin[1])/chf.ch);
|
||||||
|
int maxz = (int)((bmax[2]-chf.bmin[2])/chf.cs);
|
||||||
|
|
||||||
|
if (maxx < 0) return;
|
||||||
|
if (minx >= chf.width) return;
|
||||||
|
if (maxz < 0) return;
|
||||||
|
if (minz >= chf.height) return;
|
||||||
|
|
||||||
|
if (minx < 0) minx = 0;
|
||||||
|
if (maxx >= chf.width) maxx = chf.width-1;
|
||||||
|
if (minz < 0) minz = 0;
|
||||||
|
if (maxz >= chf.height) maxz = chf.height-1;
|
||||||
|
|
||||||
|
|
||||||
|
for (int z = minz; z <= maxz; ++z)
|
||||||
|
{
|
||||||
|
for (int x = minx; x <= maxx; ++x)
|
||||||
|
{
|
||||||
|
const rcCompactCell& c = chf.cells[x+z*chf.width];
|
||||||
|
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||||
|
{
|
||||||
|
rcCompactSpan& s = chf.spans[i];
|
||||||
|
|
||||||
|
if (chf.areas[i] == RC_NULL_AREA)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((int)s.y >= miny && (int)s.y <= maxy)
|
||||||
|
{
|
||||||
|
const float sx = chf.bmin[0] + (x+0.5f)*chf.cs;
|
||||||
|
const float sz = chf.bmin[2] + (z+0.5f)*chf.cs;
|
||||||
|
const float dx = sx - pos[0];
|
||||||
|
const float dz = sz - pos[2];
|
||||||
|
|
||||||
|
if (dx*dx + dz*dz < r2)
|
||||||
|
{
|
||||||
|
chf.areas[i] = areaId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->stopTimer(RC_TIMER_MARK_CYLINDER_AREA);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include "Recast.h"
|
#include "Recast.h"
|
||||||
#include "RecastAlloc.h"
|
#include "RecastAlloc.h"
|
||||||
#include "RecastAssert.h"
|
#include "RecastAssert.h"
|
||||||
|
|
@ -187,27 +188,6 @@ static float distancePtSeg(const int x, const int z,
|
||||||
const int px, const int pz,
|
const int px, const int pz,
|
||||||
const int qx, const int qz)
|
const int qx, const int qz)
|
||||||
{
|
{
|
||||||
/* float pqx = (float)(qx - px);
|
|
||||||
float pqy = (float)(qy - py);
|
|
||||||
float pqz = (float)(qz - pz);
|
|
||||||
float dx = (float)(x - px);
|
|
||||||
float dy = (float)(y - py);
|
|
||||||
float dz = (float)(z - pz);
|
|
||||||
float d = pqx*pqx + pqy*pqy + pqz*pqz;
|
|
||||||
float t = pqx*dx + pqy*dy + pqz*dz;
|
|
||||||
if (d > 0)
|
|
||||||
t /= d;
|
|
||||||
if (t < 0)
|
|
||||||
t = 0;
|
|
||||||
else if (t > 1)
|
|
||||||
t = 1;
|
|
||||||
|
|
||||||
dx = px + t*pqx - x;
|
|
||||||
dy = py + t*pqy - y;
|
|
||||||
dz = pz + t*pqz - z;
|
|
||||||
|
|
||||||
return dx*dx + dy*dy + dz*dz;*/
|
|
||||||
|
|
||||||
float pqx = (float)(qx - px);
|
float pqx = (float)(qx - px);
|
||||||
float pqz = (float)(qz - pz);
|
float pqz = (float)(qz - pz);
|
||||||
float dx = (float)(x - px);
|
float dx = (float)(x - px);
|
||||||
|
|
@ -311,13 +291,13 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
|
||||||
{
|
{
|
||||||
int ii = (i+1) % (simplified.size()/4);
|
int ii = (i+1) % (simplified.size()/4);
|
||||||
|
|
||||||
const int ax = simplified[i*4+0];
|
int ax = simplified[i*4+0];
|
||||||
const int az = simplified[i*4+2];
|
int az = simplified[i*4+2];
|
||||||
const int ai = simplified[i*4+3];
|
int ai = simplified[i*4+3];
|
||||||
|
|
||||||
const int bx = simplified[ii*4+0];
|
int bx = simplified[ii*4+0];
|
||||||
const int bz = simplified[ii*4+2];
|
int bz = simplified[ii*4+2];
|
||||||
const int bi = simplified[ii*4+3];
|
int bi = simplified[ii*4+3];
|
||||||
|
|
||||||
// Find maximum deviation from the segment.
|
// Find maximum deviation from the segment.
|
||||||
float maxd = 0;
|
float maxd = 0;
|
||||||
|
|
@ -338,9 +318,11 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
|
||||||
cinc = pn-1;
|
cinc = pn-1;
|
||||||
ci = (bi+cinc) % pn;
|
ci = (bi+cinc) % pn;
|
||||||
endi = ai;
|
endi = ai;
|
||||||
|
rcSwap(ax, bx);
|
||||||
|
rcSwap(az, bz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tessellate only outer edges oredges between areas.
|
// Tessellate only outer edges or edges between areas.
|
||||||
if ((points[ci*4+3] & RC_CONTOUR_REG_MASK) == 0 ||
|
if ((points[ci*4+3] & RC_CONTOUR_REG_MASK) == 0 ||
|
||||||
(points[ci*4+3] & RC_AREA_BORDER))
|
(points[ci*4+3] & RC_AREA_BORDER))
|
||||||
{
|
{
|
||||||
|
|
@ -420,14 +402,12 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
|
||||||
// Round based on the segments in lexilogical order so that the
|
// Round based on the segments in lexilogical order so that the
|
||||||
// max tesselation is consistent regardles in which direction
|
// max tesselation is consistent regardles in which direction
|
||||||
// segments are traversed.
|
// segments are traversed.
|
||||||
|
const int n = bi < ai ? (bi+pn - ai) : (bi - ai);
|
||||||
|
if (n > 1)
|
||||||
|
{
|
||||||
if (bx > ax || (bx == ax && bz > az))
|
if (bx > ax || (bx == ax && bz > az))
|
||||||
{
|
|
||||||
const int n = bi < ai ? (bi+pn - ai) : (bi - ai);
|
|
||||||
maxi = (ai + n/2) % pn;
|
maxi = (ai + n/2) % pn;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
const int n = bi < ai ? (bi+pn - ai) : (bi - ai);
|
|
||||||
maxi = (ai + (n+1)/2) % pn;
|
maxi = (ai + (n+1)/2) % pn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -466,37 +446,11 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
|
||||||
// and the neighbour region is take from the next raw point.
|
// and the neighbour region is take from the next raw point.
|
||||||
const int ai = (simplified[i*4+3]+1) % pn;
|
const int ai = (simplified[i*4+3]+1) % pn;
|
||||||
const int bi = simplified[i*4+3];
|
const int bi = simplified[i*4+3];
|
||||||
simplified[i*4+3] = (points[ai*4+3] & RC_CONTOUR_REG_MASK) | (points[bi*4+3] & RC_BORDER_VERTEX);
|
simplified[i*4+3] = (points[ai*4+3] & (RC_CONTOUR_REG_MASK|RC_AREA_BORDER)) | (points[bi*4+3] & RC_BORDER_VERTEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void removeDegenerateSegments(rcIntArray& simplified)
|
|
||||||
{
|
|
||||||
// Remove adjacent vertices which are equal on xz-plane,
|
|
||||||
// or else the triangulator will get confused.
|
|
||||||
for (int i = 0; i < simplified.size()/4; ++i)
|
|
||||||
{
|
|
||||||
int ni = i+1;
|
|
||||||
if (ni >= (simplified.size()/4))
|
|
||||||
ni = 0;
|
|
||||||
|
|
||||||
if (simplified[i*4+0] == simplified[ni*4+0] &&
|
|
||||||
simplified[i*4+2] == simplified[ni*4+2])
|
|
||||||
{
|
|
||||||
// Degenerate segment, remove.
|
|
||||||
for (int j = i; j < simplified.size()/4-1; ++j)
|
|
||||||
{
|
|
||||||
simplified[j*4+0] = simplified[(j+1)*4+0];
|
|
||||||
simplified[j*4+1] = simplified[(j+1)*4+1];
|
|
||||||
simplified[j*4+2] = simplified[(j+1)*4+2];
|
|
||||||
simplified[j*4+3] = simplified[(j+1)*4+3];
|
|
||||||
}
|
|
||||||
simplified.resize(simplified.size()-4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int calcAreaOfPolygon2D(const int* verts, const int nverts)
|
static int calcAreaOfPolygon2D(const int* verts, const int nverts)
|
||||||
{
|
{
|
||||||
int area = 0;
|
int area = 0;
|
||||||
|
|
@ -509,45 +463,146 @@ static int calcAreaOfPolygon2D(const int* verts, const int nverts)
|
||||||
return (area+1) / 2;
|
return (area+1) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool ileft(const int* a, const int* b, const int* c)
|
// TODO: these are the same as in RecastMesh.cpp, consider using the same.
|
||||||
|
|
||||||
|
inline int prev(int i, int n) { return i-1 >= 0 ? i-1 : n-1; }
|
||||||
|
inline int next(int i, int n) { return i+1 < n ? i+1 : 0; }
|
||||||
|
|
||||||
|
inline int area2(const int* a, const int* b, const int* c)
|
||||||
{
|
{
|
||||||
return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]) <= 0;
|
return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void getClosestIndices(const int* vertsa, const int nvertsa,
|
// Exclusive or: true iff exactly one argument is true.
|
||||||
const int* vertsb, const int nvertsb,
|
// The arguments are negated to ensure that they are 0/1
|
||||||
int& ia, int& ib)
|
// values. Then the bitwise Xor operator may apply.
|
||||||
|
// (This idea is due to Michael Baldwin.)
|
||||||
|
inline bool xorb(bool x, bool y)
|
||||||
{
|
{
|
||||||
int closestDist = 0xfffffff;
|
return !x ^ !y;
|
||||||
ia = -1, ib = -1;
|
}
|
||||||
for (int i = 0; i < nvertsa; ++i)
|
|
||||||
{
|
|
||||||
const int in = (i+1) % nvertsa;
|
|
||||||
const int ip = (i+nvertsa-1) % nvertsa;
|
|
||||||
const int* va = &vertsa[i*4];
|
|
||||||
const int* van = &vertsa[in*4];
|
|
||||||
const int* vap = &vertsa[ip*4];
|
|
||||||
|
|
||||||
for (int j = 0; j < nvertsb; ++j)
|
// Returns true iff c is strictly to the left of the directed
|
||||||
|
// line through a to b.
|
||||||
|
inline bool left(const int* a, const int* b, const int* c)
|
||||||
|
{
|
||||||
|
return area2(a, b, c) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool leftOn(const int* a, const int* b, const int* c)
|
||||||
|
{
|
||||||
|
return area2(a, b, c) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool collinear(const int* a, const int* b, const int* c)
|
||||||
|
{
|
||||||
|
return area2(a, b, c) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true iff ab properly intersects cd: they share
|
||||||
|
// a point interior to both segments. The properness of the
|
||||||
|
// intersection is ensured by using strict leftness.
|
||||||
|
static bool intersectProp(const int* a, const int* b, const int* c, const int* d)
|
||||||
|
{
|
||||||
|
// Eliminate improper cases.
|
||||||
|
if (collinear(a,b,c) || collinear(a,b,d) ||
|
||||||
|
collinear(c,d,a) || collinear(c,d,b))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return xorb(left(a,b,c), left(a,b,d)) && xorb(left(c,d,a), left(c,d,b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns T iff (a,b,c) are collinear and point c lies
|
||||||
|
// on the closed segement ab.
|
||||||
|
static bool between(const int* a, const int* b, const int* c)
|
||||||
|
{
|
||||||
|
if (!collinear(a, b, c))
|
||||||
|
return false;
|
||||||
|
// If ab not vertical, check betweenness on x; else on y.
|
||||||
|
if (a[0] != b[0])
|
||||||
|
return ((a[0] <= c[0]) && (c[0] <= b[0])) || ((a[0] >= c[0]) && (c[0] >= b[0]));
|
||||||
|
else
|
||||||
|
return ((a[2] <= c[2]) && (c[2] <= b[2])) || ((a[2] >= c[2]) && (c[2] >= b[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true iff segments ab and cd intersect, properly or improperly.
|
||||||
|
static bool intersect(const int* a, const int* b, const int* c, const int* d)
|
||||||
|
{
|
||||||
|
if (intersectProp(a, b, c, d))
|
||||||
|
return true;
|
||||||
|
else if (between(a, b, c) || between(a, b, d) ||
|
||||||
|
between(c, d, a) || between(c, d, b))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool vequal(const int* a, const int* b)
|
||||||
|
{
|
||||||
|
return a[0] == b[0] && a[2] == b[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool intersectSegCountour(const int* d0, const int* d1, int i, int n, const int* verts)
|
||||||
|
{
|
||||||
|
// For each edge (k,k+1) of P
|
||||||
|
for (int k = 0; k < n; k++)
|
||||||
{
|
{
|
||||||
const int* vb = &vertsb[j*4];
|
int k1 = next(k, n);
|
||||||
// vb must be "infront" of va.
|
// Skip edges incident to i.
|
||||||
if (ileft(vap,va,vb) && ileft(va,van,vb))
|
if (i == k || i == k1)
|
||||||
{
|
continue;
|
||||||
const int dx = vb[0] - va[0];
|
const int* p0 = &verts[k * 4];
|
||||||
const int dz = vb[2] - va[2];
|
const int* p1 = &verts[k1 * 4];
|
||||||
const int d = dx*dx + dz*dz;
|
if (vequal(d0, p0) || vequal(d1, p0) || vequal(d0, p1) || vequal(d1, p1))
|
||||||
if (d < closestDist)
|
continue;
|
||||||
{
|
|
||||||
ia = i;
|
if (intersect(d0, d1, p0, p1))
|
||||||
ib = j;
|
return true;
|
||||||
closestDist = d;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool inCone(int i, int n, const int* verts, const int* pj)
|
||||||
|
{
|
||||||
|
const int* pi = &verts[i * 4];
|
||||||
|
const int* pi1 = &verts[next(i, n) * 4];
|
||||||
|
const int* pin1 = &verts[prev(i, n) * 4];
|
||||||
|
|
||||||
|
// If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
|
||||||
|
if (leftOn(pin1, pi, pi1))
|
||||||
|
return left(pi, pj, pin1) && left(pj, pi, pi1);
|
||||||
|
// Assume (i-1,i,i+1) not collinear.
|
||||||
|
// else P[i] is reflex.
|
||||||
|
return !(leftOn(pi, pj, pi1) && leftOn(pj, pi, pin1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void removeDegenerateSegments(rcIntArray& simplified)
|
||||||
|
{
|
||||||
|
// Remove adjacent vertices which are equal on xz-plane,
|
||||||
|
// or else the triangulator will get confused.
|
||||||
|
int npts = simplified.size()/4;
|
||||||
|
for (int i = 0; i < npts; ++i)
|
||||||
|
{
|
||||||
|
int ni = next(i, npts);
|
||||||
|
|
||||||
|
if (vequal(&simplified[i*4], &simplified[ni*4]))
|
||||||
|
{
|
||||||
|
// Degenerate segment, remove.
|
||||||
|
for (int j = i; j < simplified.size()/4-1; ++j)
|
||||||
|
{
|
||||||
|
simplified[j*4+0] = simplified[(j+1)*4+0];
|
||||||
|
simplified[j*4+1] = simplified[(j+1)*4+1];
|
||||||
|
simplified[j*4+2] = simplified[(j+1)*4+2];
|
||||||
|
simplified[j*4+3] = simplified[(j+1)*4+3];
|
||||||
}
|
}
|
||||||
|
simplified.resize(simplified.size()-4);
|
||||||
|
npts--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib)
|
static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib)
|
||||||
{
|
{
|
||||||
const int maxVerts = ca.nverts + cb.nverts + 2;
|
const int maxVerts = ca.nverts + cb.nverts + 2;
|
||||||
|
|
@ -592,6 +647,180 @@ static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct rcContourHole
|
||||||
|
{
|
||||||
|
rcContour* contour;
|
||||||
|
int minx, minz, leftmost;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rcContourRegion
|
||||||
|
{
|
||||||
|
rcContour* outline;
|
||||||
|
rcContourHole* holes;
|
||||||
|
int nholes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rcPotentialDiagonal
|
||||||
|
{
|
||||||
|
int vert;
|
||||||
|
int dist;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Finds the lowest leftmost vertex of a contour.
|
||||||
|
static void findLeftMostVertex(rcContour* contour, int* minx, int* minz, int* leftmost)
|
||||||
|
{
|
||||||
|
*minx = contour->verts[0];
|
||||||
|
*minz = contour->verts[2];
|
||||||
|
*leftmost = 0;
|
||||||
|
for (int i = 1; i < contour->nverts; i++)
|
||||||
|
{
|
||||||
|
const int x = contour->verts[i*4+0];
|
||||||
|
const int z = contour->verts[i*4+2];
|
||||||
|
if (x < *minx || (x == *minx && z < *minz))
|
||||||
|
{
|
||||||
|
*minx = x;
|
||||||
|
*minz = z;
|
||||||
|
*leftmost = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compareHoles(const void* va, const void* vb)
|
||||||
|
{
|
||||||
|
const rcContourHole* a = (const rcContourHole*)va;
|
||||||
|
const rcContourHole* b = (const rcContourHole*)vb;
|
||||||
|
if (a->minx == b->minx)
|
||||||
|
{
|
||||||
|
if (a->minz < b->minz)
|
||||||
|
return -1;
|
||||||
|
if (a->minz > b->minz)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (a->minx < b->minx)
|
||||||
|
return -1;
|
||||||
|
if (a->minx > b->minx)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int compareDiagDist(const void* va, const void* vb)
|
||||||
|
{
|
||||||
|
const rcPotentialDiagonal* a = (const rcPotentialDiagonal*)va;
|
||||||
|
const rcPotentialDiagonal* b = (const rcPotentialDiagonal*)vb;
|
||||||
|
if (a->dist < b->dist)
|
||||||
|
return -1;
|
||||||
|
if (a->dist > b->dist)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void mergeRegionHoles(rcContext* ctx, rcContourRegion& region)
|
||||||
|
{
|
||||||
|
// Sort holes from left to right.
|
||||||
|
for (int i = 0; i < region.nholes; i++)
|
||||||
|
findLeftMostVertex(region.holes[i].contour, ®ion.holes[i].minx, ®ion.holes[i].minz, ®ion.holes[i].leftmost);
|
||||||
|
|
||||||
|
qsort(region.holes, region.nholes, sizeof(rcContourHole), compareHoles);
|
||||||
|
|
||||||
|
int maxVerts = region.outline->nverts;
|
||||||
|
for (int i = 0; i < region.nholes; i++)
|
||||||
|
maxVerts += region.holes[i].contour->nverts;
|
||||||
|
|
||||||
|
rcScopedDelete<rcPotentialDiagonal> diags = (rcPotentialDiagonal*)rcAlloc(sizeof(rcPotentialDiagonal)*maxVerts, RC_ALLOC_TEMP);
|
||||||
|
if (!diags)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_WARNING, "mergeRegionHoles: Failed to allocated diags %d.", maxVerts);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rcContour* outline = region.outline;
|
||||||
|
|
||||||
|
// Merge holes into the outline one by one.
|
||||||
|
for (int i = 0; i < region.nholes; i++)
|
||||||
|
{
|
||||||
|
rcContour* hole = region.holes[i].contour;
|
||||||
|
|
||||||
|
int index = -1;
|
||||||
|
int bestVertex = region.holes[i].leftmost;
|
||||||
|
for (int iter = 0; iter < hole->nverts; iter++)
|
||||||
|
{
|
||||||
|
// Find potential diagonals.
|
||||||
|
// The 'best' vertex must be in the cone described by 3 cosequtive vertices of the outline.
|
||||||
|
// ..o j-1
|
||||||
|
// |
|
||||||
|
// | * best
|
||||||
|
// |
|
||||||
|
// j o-----o j+1
|
||||||
|
// :
|
||||||
|
int ndiags = 0;
|
||||||
|
const int* corner = &hole->verts[bestVertex*4];
|
||||||
|
for (int j = 0; j < outline->nverts; j++)
|
||||||
|
{
|
||||||
|
if (inCone(j, outline->nverts, outline->verts, corner))
|
||||||
|
{
|
||||||
|
int dx = outline->verts[j*4+0] - corner[0];
|
||||||
|
int dz = outline->verts[j*4+2] - corner[2];
|
||||||
|
diags[ndiags].vert = j;
|
||||||
|
diags[ndiags].dist = dx*dx + dz*dz;
|
||||||
|
ndiags++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sort potential diagonals by distance, we want to make the connection as short as possible.
|
||||||
|
qsort(diags, ndiags, sizeof(rcPotentialDiagonal), compareDiagDist);
|
||||||
|
|
||||||
|
// Find a diagonal that is not intersecting the outline not the remaining holes.
|
||||||
|
index = -1;
|
||||||
|
for (int j = 0; j < ndiags; j++)
|
||||||
|
{
|
||||||
|
const int* pt = &outline->verts[diags[j].vert*4];
|
||||||
|
bool intersect = intersectSegCountour(pt, corner, diags[i].vert, outline->nverts, outline->verts);
|
||||||
|
for (int k = i; k < region.nholes && !intersect; k++)
|
||||||
|
intersect |= intersectSegCountour(pt, corner, -1, region.holes[k].contour->nverts, region.holes[k].contour->verts);
|
||||||
|
if (!intersect)
|
||||||
|
{
|
||||||
|
index = diags[j].vert;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If found non-intersecting diagonal, stop looking.
|
||||||
|
if (index != -1)
|
||||||
|
break;
|
||||||
|
// All the potential diagonals for the current vertex were intersecting, try next vertex.
|
||||||
|
bestVertex = (bestVertex + 1) % hole->nverts;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_WARNING, "mergeHoles: Failed to find merge points for %p and %p.", region.outline, hole);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!mergeContours(*region.outline, *hole, index, bestVertex))
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_WARNING, "mergeHoles: Failed to merge contours %p and %p.", region.outline, hole);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// The raw contours will match the region outlines exactly. The @p maxError and @p maxEdgeLen
|
||||||
|
/// parameters control how closely the simplified contours will match the raw contours.
|
||||||
|
///
|
||||||
|
/// Simplified contours are generated such that the vertices for portals between areas match up.
|
||||||
|
/// (They are considered mandatory vertices.)
|
||||||
|
///
|
||||||
|
/// Setting @p maxEdgeLength to zero will disabled the edge length feature.
|
||||||
|
///
|
||||||
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
|
///
|
||||||
|
/// @see rcAllocContourSet, rcCompactHeightfield, rcContourSet, rcConfig
|
||||||
bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
const float maxError, const int maxEdgeLen,
|
const float maxError, const int maxEdgeLen,
|
||||||
rcContourSet& cset, const int buildFlags)
|
rcContourSet& cset, const int buildFlags)
|
||||||
|
|
@ -600,13 +829,26 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
|
|
||||||
const int w = chf.width;
|
const int w = chf.width;
|
||||||
const int h = chf.height;
|
const int h = chf.height;
|
||||||
|
const int borderSize = chf.borderSize;
|
||||||
|
|
||||||
ctx->startTimer(RC_TIMER_BUILD_CONTOURS);
|
ctx->startTimer(RC_TIMER_BUILD_CONTOURS);
|
||||||
|
|
||||||
rcVcopy(cset.bmin, chf.bmin);
|
rcVcopy(cset.bmin, chf.bmin);
|
||||||
rcVcopy(cset.bmax, chf.bmax);
|
rcVcopy(cset.bmax, chf.bmax);
|
||||||
|
if (borderSize > 0)
|
||||||
|
{
|
||||||
|
// If the heightfield was build with bordersize, remove the offset.
|
||||||
|
const float pad = borderSize*chf.cs;
|
||||||
|
cset.bmin[0] += pad;
|
||||||
|
cset.bmin[2] += pad;
|
||||||
|
cset.bmax[0] -= pad;
|
||||||
|
cset.bmax[2] -= pad;
|
||||||
|
}
|
||||||
cset.cs = chf.cs;
|
cset.cs = chf.cs;
|
||||||
cset.ch = chf.ch;
|
cset.ch = chf.ch;
|
||||||
|
cset.width = chf.width - chf.borderSize*2;
|
||||||
|
cset.height = chf.height - chf.borderSize*2;
|
||||||
|
cset.borderSize = chf.borderSize;
|
||||||
|
|
||||||
int maxContours = rcMax((int)chf.maxRegions, 8);
|
int maxContours = rcMax((int)chf.maxRegions, 8);
|
||||||
cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM);
|
cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM);
|
||||||
|
|
@ -658,8 +900,6 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
|
|
||||||
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
|
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
|
||||||
|
|
||||||
ctx->startTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
|
|
||||||
|
|
||||||
rcIntArray verts(256);
|
rcIntArray verts(256);
|
||||||
rcIntArray simplified(64);
|
rcIntArray simplified(64);
|
||||||
|
|
||||||
|
|
@ -682,9 +922,16 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
|
|
||||||
verts.resize(0);
|
verts.resize(0);
|
||||||
simplified.resize(0);
|
simplified.resize(0);
|
||||||
|
|
||||||
|
ctx->startTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
|
||||||
walkContour(x, y, i, chf, flags, verts);
|
walkContour(x, y, i, chf, flags, verts);
|
||||||
|
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
|
||||||
|
|
||||||
|
ctx->startTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
|
||||||
simplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags);
|
simplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags);
|
||||||
removeDegenerateSegments(simplified);
|
removeDegenerateSegments(simplified);
|
||||||
|
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
|
||||||
|
|
||||||
|
|
||||||
// Store region->contour remap info.
|
// Store region->contour remap info.
|
||||||
// Create contour.
|
// Create contour.
|
||||||
|
|
@ -693,7 +940,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
if (cset.nconts >= maxContours)
|
if (cset.nconts >= maxContours)
|
||||||
{
|
{
|
||||||
// Allocate more contours.
|
// Allocate more contours.
|
||||||
// This can happen when there are tiny holes in the heightfield.
|
// This happens when a region has holes.
|
||||||
const int oldMax = maxContours;
|
const int oldMax = maxContours;
|
||||||
maxContours *= 2;
|
maxContours *= 2;
|
||||||
rcContour* newConts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM);
|
rcContour* newConts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM);
|
||||||
|
|
@ -720,6 +967,16 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memcpy(cont->verts, &simplified[0], sizeof(int)*cont->nverts*4);
|
memcpy(cont->verts, &simplified[0], sizeof(int)*cont->nverts*4);
|
||||||
|
if (borderSize > 0)
|
||||||
|
{
|
||||||
|
// If the heightfield was build with bordersize, remove the offset.
|
||||||
|
for (int j = 0; j < cont->nverts; ++j)
|
||||||
|
{
|
||||||
|
int* v = &cont->verts[j*4];
|
||||||
|
v[0] -= borderSize;
|
||||||
|
v[2] -= borderSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cont->nrverts = verts.size()/4;
|
cont->nrverts = verts.size()/4;
|
||||||
cont->rverts = (int*)rcAlloc(sizeof(int)*cont->nrverts*4, RC_ALLOC_PERM);
|
cont->rverts = (int*)rcAlloc(sizeof(int)*cont->nrverts*4, RC_ALLOC_PERM);
|
||||||
|
|
@ -729,17 +986,16 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memcpy(cont->rverts, &verts[0], sizeof(int)*cont->nrverts*4);
|
memcpy(cont->rverts, &verts[0], sizeof(int)*cont->nrverts*4);
|
||||||
|
if (borderSize > 0)
|
||||||
/* cont->cx = cont->cy = cont->cz = 0;
|
|
||||||
for (int i = 0; i < cont->nverts; ++i)
|
|
||||||
{
|
{
|
||||||
cont->cx += cont->verts[i*4+0];
|
// If the heightfield was build with bordersize, remove the offset.
|
||||||
cont->cy += cont->verts[i*4+1];
|
for (int j = 0; j < cont->nrverts; ++j)
|
||||||
cont->cz += cont->verts[i*4+2];
|
{
|
||||||
|
int* v = &cont->rverts[j*4];
|
||||||
|
v[0] -= borderSize;
|
||||||
|
v[2] -= borderSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cont->cx /= cont->nverts;
|
|
||||||
cont->cy /= cont->nverts;
|
|
||||||
cont->cz /= cont->nverts;*/
|
|
||||||
|
|
||||||
cont->reg = reg;
|
cont->reg = reg;
|
||||||
cont->area = area;
|
cont->area = area;
|
||||||
|
|
@ -748,55 +1004,101 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check and merge droppings.
|
// Merge holes if needed.
|
||||||
// Sometimes the previous algorithms can fail and create several contours
|
if (cset.nconts > 0)
|
||||||
// per area. This pass will try to merge the holes into the main region.
|
{
|
||||||
|
// Calculate winding of all polygons.
|
||||||
|
rcScopedDelete<char> winding = (char*)rcAlloc(sizeof(char)*cset.nconts, RC_ALLOC_TEMP);
|
||||||
|
if (!winding)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'hole' (%d).", cset.nconts);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int nholes = 0;
|
||||||
for (int i = 0; i < cset.nconts; ++i)
|
for (int i = 0; i < cset.nconts; ++i)
|
||||||
{
|
{
|
||||||
rcContour& cont = cset.conts[i];
|
rcContour& cont = cset.conts[i];
|
||||||
// Check if the contour is would backwards.
|
// If the contour is wound backwards, it is a hole.
|
||||||
if (calcAreaOfPolygon2D(cont.verts, cont.nverts) < 0)
|
winding[i] = calcAreaOfPolygon2D(cont.verts, cont.nverts) < 0 ? -1 : 1;
|
||||||
{
|
if (winding[i] < 0)
|
||||||
// Find another contour which has the same region ID.
|
nholes++;
|
||||||
int mergeIdx = -1;
|
|
||||||
for (int j = 0; j < cset.nconts; ++j)
|
|
||||||
{
|
|
||||||
if (i == j) continue;
|
|
||||||
if (cset.conts[j].nverts && cset.conts[j].reg == cont.reg)
|
|
||||||
{
|
|
||||||
// Make sure the polygon is correctly oriented.
|
|
||||||
if (calcAreaOfPolygon2D(cset.conts[j].verts, cset.conts[j].nverts))
|
|
||||||
{
|
|
||||||
mergeIdx = j;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
if (nholes > 0)
|
||||||
if (mergeIdx == -1)
|
|
||||||
{
|
{
|
||||||
ctx->log(RC_LOG_WARNING, "rcBuildContours: Could not find merge target for bad contour %d.", i);
|
// Collect outline contour and holes contours per region.
|
||||||
|
// We assume that there is one outline and multiple holes.
|
||||||
|
const int nregions = chf.maxRegions+1;
|
||||||
|
rcScopedDelete<rcContourRegion> regions = (rcContourRegion*)rcAlloc(sizeof(rcContourRegion)*nregions, RC_ALLOC_TEMP);
|
||||||
|
if (!regions)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'regions' (%d).", nregions);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(regions, 0, sizeof(rcContourRegion)*nregions);
|
||||||
|
|
||||||
|
rcScopedDelete<rcContourHole> holes = (rcContourHole*)rcAlloc(sizeof(rcContourHole)*cset.nconts, RC_ALLOC_TEMP);
|
||||||
|
if (!holes)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'holes' (%d).", cset.nconts);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(holes, 0, sizeof(rcContourHole)*cset.nconts);
|
||||||
|
|
||||||
|
for (int i = 0; i < cset.nconts; ++i)
|
||||||
|
{
|
||||||
|
rcContour& cont = cset.conts[i];
|
||||||
|
// Positively would contours are outlines, negative holes.
|
||||||
|
if (winding[i] > 0)
|
||||||
|
{
|
||||||
|
if (regions[cont.reg].outline)
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildContours: Multiple outlines for region %d.", cont.reg);
|
||||||
|
regions[cont.reg].outline = &cont;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rcContour& mcont = cset.conts[mergeIdx];
|
regions[cont.reg].nholes++;
|
||||||
// Merge by closest points.
|
|
||||||
int ia = 0, ib = 0;
|
|
||||||
getClosestIndices(mcont.verts, mcont.nverts, cont.verts, cont.nverts, ia, ib);
|
|
||||||
if (ia == -1 || ib == -1)
|
|
||||||
{
|
|
||||||
ctx->log(RC_LOG_WARNING, "rcBuildContours: Failed to find merge points for %d and %d.", i, mergeIdx);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (!mergeContours(mcont, cont, ia, ib))
|
|
||||||
{
|
|
||||||
ctx->log(RC_LOG_WARNING, "rcBuildContours: Failed to merge contours %d and %d.", i, mergeIdx);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 0; i < nregions; i++)
|
||||||
|
{
|
||||||
|
if (regions[i].nholes > 0)
|
||||||
|
{
|
||||||
|
regions[i].holes = &holes[index];
|
||||||
|
index += regions[i].nholes;
|
||||||
|
regions[i].nholes = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < cset.nconts; ++i)
|
||||||
|
{
|
||||||
|
rcContour& cont = cset.conts[i];
|
||||||
|
rcContourRegion& reg = regions[cont.reg];
|
||||||
|
if (winding[i] < 0)
|
||||||
|
reg.holes[reg.nholes++].contour = &cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally merge each regions holes into the outline.
|
||||||
|
for (int i = 0; i < nregions; i++)
|
||||||
|
{
|
||||||
|
rcContourRegion& reg = regions[i];
|
||||||
|
if (!reg.nholes) continue;
|
||||||
|
|
||||||
|
if (reg.outline)
|
||||||
|
{
|
||||||
|
mergeRegionHoles(ctx, reg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The region does not have an outline.
|
||||||
|
// This can happen if the contour becaomes selfoverlapping because of
|
||||||
|
// too aggressive simplification settings.
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildContours: Bad outline for region %d, contour simplification is likely too aggressive.", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
|
}
|
||||||
|
|
||||||
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS);
|
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,17 @@
|
||||||
#include "Recast.h"
|
#include "Recast.h"
|
||||||
#include "RecastAssert.h"
|
#include "RecastAssert.h"
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// Allows the formation of walkable regions that will flow over low lying
|
||||||
|
/// objects such as curbs, and up structures such as stairways.
|
||||||
|
///
|
||||||
|
/// Two neighboring spans are walkable if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) < waklableClimb</tt>
|
||||||
|
///
|
||||||
|
/// @warning Will override the effect of #rcFilterLedgeSpans. So if both filters are used, call
|
||||||
|
/// #rcFilterLedgeSpans after calling this filter.
|
||||||
|
///
|
||||||
|
/// @see rcHeightfield, rcConfig
|
||||||
void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb, rcHeightfield& solid)
|
void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb, rcHeightfield& solid)
|
||||||
{
|
{
|
||||||
rcAssert(ctx);
|
rcAssert(ctx);
|
||||||
|
|
@ -38,6 +48,7 @@ void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb
|
||||||
{
|
{
|
||||||
rcSpan* ps = 0;
|
rcSpan* ps = 0;
|
||||||
bool previousWalkable = false;
|
bool previousWalkable = false;
|
||||||
|
unsigned char previousArea = RC_NULL_AREA;
|
||||||
|
|
||||||
for (rcSpan* s = solid.spans[x + y*w]; s; ps = s, s = s->next)
|
for (rcSpan* s = solid.spans[x + y*w]; s; ps = s, s = s->next)
|
||||||
{
|
{
|
||||||
|
|
@ -47,11 +58,12 @@ void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb
|
||||||
if (!walkable && previousWalkable)
|
if (!walkable && previousWalkable)
|
||||||
{
|
{
|
||||||
if (rcAbs((int)s->smax - (int)ps->smax) <= walkableClimb)
|
if (rcAbs((int)s->smax - (int)ps->smax) <= walkableClimb)
|
||||||
s->area = RC_NULL_AREA;
|
s->area = previousArea;
|
||||||
}
|
}
|
||||||
// Copy walkable flag so that it cannot propagate
|
// Copy walkable flag so that it cannot propagate
|
||||||
// past multiple non-walkable objects.
|
// past multiple non-walkable objects.
|
||||||
previousWalkable = walkable;
|
previousWalkable = walkable;
|
||||||
|
previousArea = s->area;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +71,16 @@ void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb
|
||||||
ctx->stopTimer(RC_TIMER_FILTER_LOW_OBSTACLES);
|
ctx->stopTimer(RC_TIMER_FILTER_LOW_OBSTACLES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// A ledge is a span with one or more neighbors whose maximum is further away than @p walkableClimb
|
||||||
|
/// from the current span's maximum.
|
||||||
|
/// This method removes the impact of the overestimation of conservative voxelization
|
||||||
|
/// so the resulting mesh will not have regions hanging in the air over ledges.
|
||||||
|
///
|
||||||
|
/// A span is a ledge if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt>
|
||||||
|
///
|
||||||
|
/// @see rcHeightfield, rcConfig
|
||||||
void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walkableClimb,
|
void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walkableClimb,
|
||||||
rcHeightfield& solid)
|
rcHeightfield& solid)
|
||||||
{
|
{
|
||||||
|
|
@ -149,6 +171,12 @@ void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walk
|
||||||
ctx->stopTimer(RC_TIMER_FILTER_BORDER);
|
ctx->stopTimer(RC_TIMER_FILTER_BORDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// For this filter, the clearance above the span is the distance from the span's
|
||||||
|
/// maximum to the next higher span's minimum. (Same grid column.)
|
||||||
|
///
|
||||||
|
/// @see rcHeightfield, rcConfig
|
||||||
void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeightfield& solid)
|
void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeightfield& solid)
|
||||||
{
|
{
|
||||||
rcAssert(ctx);
|
rcAssert(ctx);
|
||||||
|
|
|
||||||
620
dep/recastnavigation/Recast/Source/RecastLayers.cpp
Normal file
620
dep/recastnavigation/Recast/Source/RecastLayers.cpp
Normal file
|
|
@ -0,0 +1,620 @@
|
||||||
|
//
|
||||||
|
// 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 <float.h>
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "Recast.h"
|
||||||
|
#include "RecastAlloc.h"
|
||||||
|
#include "RecastAssert.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const int RC_MAX_LAYERS = RC_NOT_CONNECTED;
|
||||||
|
static const int RC_MAX_NEIS = 16;
|
||||||
|
|
||||||
|
struct rcLayerRegion
|
||||||
|
{
|
||||||
|
unsigned char layers[RC_MAX_LAYERS];
|
||||||
|
unsigned char neis[RC_MAX_NEIS];
|
||||||
|
unsigned short ymin, ymax;
|
||||||
|
unsigned char layerId; // Layer ID
|
||||||
|
unsigned char nlayers; // Layer count
|
||||||
|
unsigned char nneis; // Neighbour count
|
||||||
|
unsigned char base; // Flag indicating if the region is the base of merged regions.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void addUnique(unsigned char* a, unsigned char& an, unsigned char v)
|
||||||
|
{
|
||||||
|
const int n = (int)an;
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
if (a[i] == v)
|
||||||
|
return;
|
||||||
|
a[an] = v;
|
||||||
|
an++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool contains(const unsigned char* a, const unsigned char an, const unsigned char v)
|
||||||
|
{
|
||||||
|
const int n = (int)an;
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
if (a[i] == v)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool overlapRange(const unsigned short amin, const unsigned short amax,
|
||||||
|
const unsigned short bmin, const unsigned short bmax)
|
||||||
|
{
|
||||||
|
return (amin > bmax || amax < bmin) ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct rcLayerSweepSpan
|
||||||
|
{
|
||||||
|
unsigned short ns; // number samples
|
||||||
|
unsigned char id; // region id
|
||||||
|
unsigned char nei; // neighbour id
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
|
///
|
||||||
|
/// @see rcAllocHeightfieldLayerSet, rcCompactHeightfield, rcHeightfieldLayerSet, rcConfig
|
||||||
|
bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
|
const int borderSize, const int walkableHeight,
|
||||||
|
rcHeightfieldLayerSet& lset)
|
||||||
|
{
|
||||||
|
rcAssert(ctx);
|
||||||
|
|
||||||
|
ctx->startTimer(RC_TIMER_BUILD_LAYERS);
|
||||||
|
|
||||||
|
const int w = chf.width;
|
||||||
|
const int h = chf.height;
|
||||||
|
|
||||||
|
rcScopedDelete<unsigned char> srcReg = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP);
|
||||||
|
if (!srcReg)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'srcReg' (%d).", chf.spanCount);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(srcReg,0xff,sizeof(unsigned char)*chf.spanCount);
|
||||||
|
|
||||||
|
const int nsweeps = chf.width;
|
||||||
|
rcScopedDelete<rcLayerSweepSpan> sweeps = (rcLayerSweepSpan*)rcAlloc(sizeof(rcLayerSweepSpan)*nsweeps, RC_ALLOC_TEMP);
|
||||||
|
if (!sweeps)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'sweeps' (%d).", nsweeps);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Partition walkable area into monotone regions.
|
||||||
|
int prevCount[256];
|
||||||
|
unsigned char regId = 0;
|
||||||
|
|
||||||
|
for (int y = borderSize; y < h-borderSize; ++y)
|
||||||
|
{
|
||||||
|
memset(prevCount,0,sizeof(int)*regId);
|
||||||
|
unsigned char sweepId = 0;
|
||||||
|
|
||||||
|
for (int x = borderSize; x < w-borderSize; ++x)
|
||||||
|
{
|
||||||
|
const rcCompactCell& c = chf.cells[x+y*w];
|
||||||
|
|
||||||
|
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||||
|
{
|
||||||
|
const rcCompactSpan& s = chf.spans[i];
|
||||||
|
if (chf.areas[i] == RC_NULL_AREA) continue;
|
||||||
|
|
||||||
|
unsigned char sid = 0xff;
|
||||||
|
|
||||||
|
// -x
|
||||||
|
if (rcGetCon(s, 0) != RC_NOT_CONNECTED)
|
||||||
|
{
|
||||||
|
const int ax = x + rcGetDirOffsetX(0);
|
||||||
|
const int ay = y + rcGetDirOffsetY(0);
|
||||||
|
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0);
|
||||||
|
if (chf.areas[ai] != RC_NULL_AREA && srcReg[ai] != 0xff)
|
||||||
|
sid = srcReg[ai];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sid == 0xff)
|
||||||
|
{
|
||||||
|
sid = sweepId++;
|
||||||
|
sweeps[sid].nei = 0xff;
|
||||||
|
sweeps[sid].ns = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -y
|
||||||
|
if (rcGetCon(s,3) != RC_NOT_CONNECTED)
|
||||||
|
{
|
||||||
|
const int ax = x + rcGetDirOffsetX(3);
|
||||||
|
const int ay = y + rcGetDirOffsetY(3);
|
||||||
|
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3);
|
||||||
|
const unsigned char nr = srcReg[ai];
|
||||||
|
if (nr != 0xff)
|
||||||
|
{
|
||||||
|
// Set neighbour when first valid neighbour is encoutered.
|
||||||
|
if (sweeps[sid].ns == 0)
|
||||||
|
sweeps[sid].nei = nr;
|
||||||
|
|
||||||
|
if (sweeps[sid].nei == nr)
|
||||||
|
{
|
||||||
|
// Update existing neighbour
|
||||||
|
sweeps[sid].ns++;
|
||||||
|
prevCount[nr]++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is hit if there is nore than one neighbour.
|
||||||
|
// Invalidate the neighbour.
|
||||||
|
sweeps[sid].nei = 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
srcReg[i] = sid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create unique ID.
|
||||||
|
for (int i = 0; i < sweepId; ++i)
|
||||||
|
{
|
||||||
|
// If the neighbour is set and there is only one continuous connection to it,
|
||||||
|
// the sweep will be merged with the previous one, else new region is created.
|
||||||
|
if (sweeps[i].nei != 0xff && prevCount[sweeps[i].nei] == (int)sweeps[i].ns)
|
||||||
|
{
|
||||||
|
sweeps[i].id = sweeps[i].nei;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (regId == 255)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Region ID overflow.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sweeps[i].id = regId++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remap local sweep ids to region ids.
|
||||||
|
for (int x = borderSize; x < w-borderSize; ++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 (srcReg[i] != 0xff)
|
||||||
|
srcReg[i] = sweeps[srcReg[i]].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate and init layer regions.
|
||||||
|
const int nregs = (int)regId;
|
||||||
|
rcScopedDelete<rcLayerRegion> regs = (rcLayerRegion*)rcAlloc(sizeof(rcLayerRegion)*nregs, RC_ALLOC_TEMP);
|
||||||
|
if (!regs)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'regs' (%d).", nregs);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(regs, 0, sizeof(rcLayerRegion)*nregs);
|
||||||
|
for (int i = 0; i < nregs; ++i)
|
||||||
|
{
|
||||||
|
regs[i].layerId = 0xff;
|
||||||
|
regs[i].ymin = 0xffff;
|
||||||
|
regs[i].ymax = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find region neighbours and overlapping regions.
|
||||||
|
for (int y = 0; y < h; ++y)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < w; ++x)
|
||||||
|
{
|
||||||
|
const rcCompactCell& c = chf.cells[x+y*w];
|
||||||
|
|
||||||
|
unsigned char lregs[RC_MAX_LAYERS];
|
||||||
|
int nlregs = 0;
|
||||||
|
|
||||||
|
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||||
|
{
|
||||||
|
const rcCompactSpan& s = chf.spans[i];
|
||||||
|
const unsigned char ri = srcReg[i];
|
||||||
|
if (ri == 0xff) continue;
|
||||||
|
|
||||||
|
regs[ri].ymin = rcMin(regs[ri].ymin, s.y);
|
||||||
|
regs[ri].ymax = rcMax(regs[ri].ymax, s.y);
|
||||||
|
|
||||||
|
// Collect all region layers.
|
||||||
|
if (nlregs < RC_MAX_LAYERS)
|
||||||
|
lregs[nlregs++] = ri;
|
||||||
|
|
||||||
|
// Update neighbours
|
||||||
|
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*w].index + rcGetCon(s, dir);
|
||||||
|
const unsigned char rai = srcReg[ai];
|
||||||
|
if (rai != 0xff && rai != ri)
|
||||||
|
addUnique(regs[ri].neis, regs[ri].nneis, rai);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update overlapping regions.
|
||||||
|
for (int i = 0; i < nlregs-1; ++i)
|
||||||
|
{
|
||||||
|
for (int j = i+1; j < nlregs; ++j)
|
||||||
|
{
|
||||||
|
if (lregs[i] != lregs[j])
|
||||||
|
{
|
||||||
|
rcLayerRegion& ri = regs[lregs[i]];
|
||||||
|
rcLayerRegion& rj = regs[lregs[j]];
|
||||||
|
addUnique(ri.layers, ri.nlayers, lregs[j]);
|
||||||
|
addUnique(rj.layers, rj.nlayers, lregs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create 2D layers from regions.
|
||||||
|
unsigned char layerId = 0;
|
||||||
|
|
||||||
|
static const int MAX_STACK = 64;
|
||||||
|
unsigned char stack[MAX_STACK];
|
||||||
|
int nstack = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < nregs; ++i)
|
||||||
|
{
|
||||||
|
rcLayerRegion& root = regs[i];
|
||||||
|
// Skip alreadu visited.
|
||||||
|
if (root.layerId != 0xff)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Start search.
|
||||||
|
root.layerId = layerId;
|
||||||
|
root.base = 1;
|
||||||
|
|
||||||
|
nstack = 0;
|
||||||
|
stack[nstack++] = (unsigned char)i;
|
||||||
|
|
||||||
|
while (nstack)
|
||||||
|
{
|
||||||
|
// Pop front
|
||||||
|
rcLayerRegion& reg = regs[stack[0]];
|
||||||
|
nstack--;
|
||||||
|
for (int j = 0; j < nstack; ++j)
|
||||||
|
stack[j] = stack[j+1];
|
||||||
|
|
||||||
|
const int nneis = (int)reg.nneis;
|
||||||
|
for (int j = 0; j < nneis; ++j)
|
||||||
|
{
|
||||||
|
const unsigned char nei = reg.neis[j];
|
||||||
|
rcLayerRegion& regn = regs[nei];
|
||||||
|
// Skip already visited.
|
||||||
|
if (regn.layerId != 0xff)
|
||||||
|
continue;
|
||||||
|
// Skip if the neighbour is overlapping root region.
|
||||||
|
if (contains(root.layers, root.nlayers, nei))
|
||||||
|
continue;
|
||||||
|
// Skip if the height range would become too large.
|
||||||
|
const int ymin = rcMin(root.ymin, regn.ymin);
|
||||||
|
const int ymax = rcMax(root.ymax, regn.ymax);
|
||||||
|
if ((ymax - ymin) >= 255)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nstack < MAX_STACK)
|
||||||
|
{
|
||||||
|
// Deepen
|
||||||
|
stack[nstack++] = (unsigned char)nei;
|
||||||
|
|
||||||
|
// Mark layer id
|
||||||
|
regn.layerId = layerId;
|
||||||
|
// Merge current layers to root.
|
||||||
|
for (int k = 0; k < regn.nlayers; ++k)
|
||||||
|
addUnique(root.layers, root.nlayers, regn.layers[k]);
|
||||||
|
root.ymin = rcMin(root.ymin, regn.ymin);
|
||||||
|
root.ymax = rcMax(root.ymax, regn.ymax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layerId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge non-overlapping regions that are close in height.
|
||||||
|
const unsigned short mergeHeight = (unsigned short)walkableHeight * 4;
|
||||||
|
|
||||||
|
for (int i = 0; i < nregs; ++i)
|
||||||
|
{
|
||||||
|
rcLayerRegion& ri = regs[i];
|
||||||
|
if (!ri.base) continue;
|
||||||
|
|
||||||
|
unsigned char newId = ri.layerId;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
unsigned char oldId = 0xff;
|
||||||
|
|
||||||
|
for (int j = 0; j < nregs; ++j)
|
||||||
|
{
|
||||||
|
if (i == j) continue;
|
||||||
|
rcLayerRegion& rj = regs[j];
|
||||||
|
if (!rj.base) continue;
|
||||||
|
|
||||||
|
// Skip if teh regions are not close to each other.
|
||||||
|
if (!overlapRange(ri.ymin,ri.ymax+mergeHeight, rj.ymin,rj.ymax+mergeHeight))
|
||||||
|
continue;
|
||||||
|
// Skip if the height range would become too large.
|
||||||
|
const int ymin = rcMin(ri.ymin, rj.ymin);
|
||||||
|
const int ymax = rcMax(ri.ymax, rj.ymax);
|
||||||
|
if ((ymax - ymin) >= 255)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Make sure that there is no overlap when mergin 'ri' and 'rj'.
|
||||||
|
bool overlap = false;
|
||||||
|
// Iterate over all regions which have the same layerId as 'rj'
|
||||||
|
for (int k = 0; k < nregs; ++k)
|
||||||
|
{
|
||||||
|
if (regs[k].layerId != rj.layerId)
|
||||||
|
continue;
|
||||||
|
// Check if region 'k' is overlapping region 'ri'
|
||||||
|
// Index to 'regs' is the same as region id.
|
||||||
|
if (contains(ri.layers,ri.nlayers, (unsigned char)k))
|
||||||
|
{
|
||||||
|
overlap = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Cannot merge of regions overlap.
|
||||||
|
if (overlap)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Can merge i and j.
|
||||||
|
oldId = rj.layerId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Could not find anything to merge with, stop.
|
||||||
|
if (oldId == 0xff)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Merge
|
||||||
|
for (int j = 0; j < nregs; ++j)
|
||||||
|
{
|
||||||
|
rcLayerRegion& rj = regs[j];
|
||||||
|
if (rj.layerId == oldId)
|
||||||
|
{
|
||||||
|
rj.base = 0;
|
||||||
|
// Remap layerIds.
|
||||||
|
rj.layerId = newId;
|
||||||
|
// Add overlaid layers from 'rj' to 'ri'.
|
||||||
|
for (int k = 0; k < rj.nlayers; ++k)
|
||||||
|
addUnique(ri.layers, ri.nlayers, rj.layers[k]);
|
||||||
|
// Update heigh bounds.
|
||||||
|
ri.ymin = rcMin(ri.ymin, rj.ymin);
|
||||||
|
ri.ymax = rcMax(ri.ymax, rj.ymax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compact layerIds
|
||||||
|
unsigned char remap[256];
|
||||||
|
memset(remap, 0, 256);
|
||||||
|
|
||||||
|
// Find number of unique layers.
|
||||||
|
layerId = 0;
|
||||||
|
for (int i = 0; i < nregs; ++i)
|
||||||
|
remap[regs[i].layerId] = 1;
|
||||||
|
for (int i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
if (remap[i])
|
||||||
|
remap[i] = layerId++;
|
||||||
|
else
|
||||||
|
remap[i] = 0xff;
|
||||||
|
}
|
||||||
|
// Remap ids.
|
||||||
|
for (int i = 0; i < nregs; ++i)
|
||||||
|
regs[i].layerId = remap[regs[i].layerId];
|
||||||
|
|
||||||
|
// No layers, return empty.
|
||||||
|
if (layerId == 0)
|
||||||
|
{
|
||||||
|
ctx->stopTimer(RC_TIMER_BUILD_LAYERS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create layers.
|
||||||
|
rcAssert(lset.layers == 0);
|
||||||
|
|
||||||
|
const int lw = w - borderSize*2;
|
||||||
|
const int lh = h - borderSize*2;
|
||||||
|
|
||||||
|
// Build contracted bbox for layers.
|
||||||
|
float bmin[3], bmax[3];
|
||||||
|
rcVcopy(bmin, chf.bmin);
|
||||||
|
rcVcopy(bmax, chf.bmax);
|
||||||
|
bmin[0] += borderSize*chf.cs;
|
||||||
|
bmin[2] += borderSize*chf.cs;
|
||||||
|
bmax[0] -= borderSize*chf.cs;
|
||||||
|
bmax[2] -= borderSize*chf.cs;
|
||||||
|
|
||||||
|
lset.nlayers = (int)layerId;
|
||||||
|
|
||||||
|
lset.layers = (rcHeightfieldLayer*)rcAlloc(sizeof(rcHeightfieldLayer)*lset.nlayers, RC_ALLOC_PERM);
|
||||||
|
if (!lset.layers)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'layers' (%d).", lset.nlayers);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(lset.layers, 0, sizeof(rcHeightfieldLayer)*lset.nlayers);
|
||||||
|
|
||||||
|
|
||||||
|
// Store layers.
|
||||||
|
for (int i = 0; i < lset.nlayers; ++i)
|
||||||
|
{
|
||||||
|
unsigned char curId = (unsigned char)i;
|
||||||
|
|
||||||
|
// Allocate memory for the current layer.
|
||||||
|
rcHeightfieldLayer* layer = &lset.layers[i];
|
||||||
|
memset(layer, 0, sizeof(rcHeightfieldLayer));
|
||||||
|
|
||||||
|
const int gridSize = sizeof(unsigned char)*lw*lh;
|
||||||
|
|
||||||
|
layer->heights = (unsigned char*)rcAlloc(gridSize, RC_ALLOC_PERM);
|
||||||
|
if (!layer->heights)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'heights' (%d).", gridSize);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(layer->heights, 0xff, gridSize);
|
||||||
|
|
||||||
|
layer->areas = (unsigned char*)rcAlloc(gridSize, RC_ALLOC_PERM);
|
||||||
|
if (!layer->areas)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'areas' (%d).", gridSize);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(layer->areas, 0, gridSize);
|
||||||
|
|
||||||
|
layer->cons = (unsigned char*)rcAlloc(gridSize, RC_ALLOC_PERM);
|
||||||
|
if (!layer->cons)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'cons' (%d).", gridSize);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(layer->cons, 0, gridSize);
|
||||||
|
|
||||||
|
// Find layer height bounds.
|
||||||
|
int hmin = 0, hmax = 0;
|
||||||
|
for (int j = 0; j < nregs; ++j)
|
||||||
|
{
|
||||||
|
if (regs[j].base && regs[j].layerId == curId)
|
||||||
|
{
|
||||||
|
hmin = (int)regs[j].ymin;
|
||||||
|
hmax = (int)regs[j].ymax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->width = lw;
|
||||||
|
layer->height = lh;
|
||||||
|
layer->cs = chf.cs;
|
||||||
|
layer->ch = chf.ch;
|
||||||
|
|
||||||
|
// Adjust the bbox to fit the heighfield.
|
||||||
|
rcVcopy(layer->bmin, bmin);
|
||||||
|
rcVcopy(layer->bmax, bmax);
|
||||||
|
layer->bmin[1] = bmin[1] + hmin*chf.ch;
|
||||||
|
layer->bmax[1] = bmin[1] + hmax*chf.ch;
|
||||||
|
layer->hmin = hmin;
|
||||||
|
layer->hmax = hmax;
|
||||||
|
|
||||||
|
// Update usable data region.
|
||||||
|
layer->minx = layer->width;
|
||||||
|
layer->maxx = 0;
|
||||||
|
layer->miny = layer->height;
|
||||||
|
layer->maxy = 0;
|
||||||
|
|
||||||
|
// Copy height and area from compact heighfield.
|
||||||
|
for (int y = 0; y < lh; ++y)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < lw; ++x)
|
||||||
|
{
|
||||||
|
const int cx = borderSize+x;
|
||||||
|
const int cy = borderSize+y;
|
||||||
|
const rcCompactCell& c = chf.cells[cx+cy*w];
|
||||||
|
for (int j = (int)c.index, nj = (int)(c.index+c.count); j < nj; ++j)
|
||||||
|
{
|
||||||
|
const rcCompactSpan& s = chf.spans[j];
|
||||||
|
// Skip unassigned regions.
|
||||||
|
if (srcReg[j] == 0xff)
|
||||||
|
continue;
|
||||||
|
// Skip of does nto belong to current layer.
|
||||||
|
unsigned char lid = regs[srcReg[j]].layerId;
|
||||||
|
if (lid != curId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Update data bounds.
|
||||||
|
layer->minx = rcMin(layer->minx, x);
|
||||||
|
layer->maxx = rcMax(layer->maxx, x);
|
||||||
|
layer->miny = rcMin(layer->miny, y);
|
||||||
|
layer->maxy = rcMax(layer->maxy, y);
|
||||||
|
|
||||||
|
// Store height and area type.
|
||||||
|
const int idx = x+y*lw;
|
||||||
|
layer->heights[idx] = (unsigned char)(s.y - hmin);
|
||||||
|
layer->areas[idx] = chf.areas[j];
|
||||||
|
|
||||||
|
// Check connection.
|
||||||
|
unsigned char portal = 0;
|
||||||
|
unsigned char con = 0;
|
||||||
|
for (int dir = 0; dir < 4; ++dir)
|
||||||
|
{
|
||||||
|
if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
|
||||||
|
{
|
||||||
|
const int ax = cx + rcGetDirOffsetX(dir);
|
||||||
|
const int ay = cy + rcGetDirOffsetY(dir);
|
||||||
|
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
|
||||||
|
unsigned char alid = srcReg[ai] != 0xff ? regs[srcReg[ai]].layerId : 0xff;
|
||||||
|
// Portal mask
|
||||||
|
if (chf.areas[ai] != RC_NULL_AREA && lid != alid)
|
||||||
|
{
|
||||||
|
portal |= (unsigned char)(1<<dir);
|
||||||
|
// Update height so that it matches on both sides of the portal.
|
||||||
|
const rcCompactSpan& as = chf.spans[ai];
|
||||||
|
if (as.y > hmin)
|
||||||
|
layer->heights[idx] = rcMax(layer->heights[idx], (unsigned char)(as.y - hmin));
|
||||||
|
}
|
||||||
|
// Valid connection mask
|
||||||
|
if (chf.areas[ai] != RC_NULL_AREA && lid == alid)
|
||||||
|
{
|
||||||
|
const int nx = ax - borderSize;
|
||||||
|
const int ny = ay - borderSize;
|
||||||
|
if (nx >= 0 && ny >= 0 && nx < lw && ny < lh)
|
||||||
|
con |= (unsigned char)(1<<dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->cons[idx] = (portal << 4) | con;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layer->minx > layer->maxx)
|
||||||
|
layer->minx = layer->maxx = 0;
|
||||||
|
if (layer->miny > layer->maxy)
|
||||||
|
layer->miny = layer->maxy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->stopTimer(RC_TIMER_BUILD_LAYERS);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
@ -59,6 +59,7 @@ static bool buildMeshAdjacency(unsigned short* polys, const int npolys,
|
||||||
unsigned short* t = &polys[i*vertsPerPoly*2];
|
unsigned short* t = &polys[i*vertsPerPoly*2];
|
||||||
for (int j = 0; j < vertsPerPoly; ++j)
|
for (int j = 0; j < vertsPerPoly; ++j)
|
||||||
{
|
{
|
||||||
|
if (t[j] == RC_MESH_NULL_IDX) break;
|
||||||
unsigned short v0 = t[j];
|
unsigned short v0 = t[j];
|
||||||
unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == RC_MESH_NULL_IDX) ? t[0] : t[j+1];
|
unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == RC_MESH_NULL_IDX) ? t[0] : t[j+1];
|
||||||
if (v0 < v1)
|
if (v0 < v1)
|
||||||
|
|
@ -83,6 +84,7 @@ static bool buildMeshAdjacency(unsigned short* polys, const int npolys,
|
||||||
unsigned short* t = &polys[i*vertsPerPoly*2];
|
unsigned short* t = &polys[i*vertsPerPoly*2];
|
||||||
for (int j = 0; j < vertsPerPoly; ++j)
|
for (int j = 0; j < vertsPerPoly; ++j)
|
||||||
{
|
{
|
||||||
|
if (t[j] == RC_MESH_NULL_IDX) break;
|
||||||
unsigned short v0 = t[j];
|
unsigned short v0 = t[j];
|
||||||
unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == RC_MESH_NULL_IDX) ? t[0] : t[j+1];
|
unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == RC_MESH_NULL_IDX) ? t[0] : t[j+1];
|
||||||
if (v0 > v1)
|
if (v0 > v1)
|
||||||
|
|
@ -195,7 +197,7 @@ inline bool collinear(const int* a, const int* b, const int* c)
|
||||||
// Returns true iff ab properly intersects cd: they share
|
// Returns true iff ab properly intersects cd: they share
|
||||||
// a point interior to both segments. The properness of the
|
// a point interior to both segments. The properness of the
|
||||||
// intersection is ensured by using strict leftness.
|
// intersection is ensured by using strict leftness.
|
||||||
bool intersectProp(const int* a, const int* b, const int* c, const int* d)
|
static bool intersectProp(const int* a, const int* b, const int* c, const int* d)
|
||||||
{
|
{
|
||||||
// Eliminate improper cases.
|
// Eliminate improper cases.
|
||||||
if (collinear(a,b,c) || collinear(a,b,d) ||
|
if (collinear(a,b,c) || collinear(a,b,d) ||
|
||||||
|
|
@ -286,6 +288,53 @@ static bool diagonal(int i, int j, int n, const int* verts, int* indices)
|
||||||
return inCone(i, j, n, verts, indices) && diagonalie(i, j, n, verts, indices);
|
return inCone(i, j, n, verts, indices) && diagonalie(i, j, n, verts, indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool diagonalieLoose(int i, int j, int n, const int* verts, int* indices)
|
||||||
|
{
|
||||||
|
const int* d0 = &verts[(indices[i] & 0x0fffffff) * 4];
|
||||||
|
const int* d1 = &verts[(indices[j] & 0x0fffffff) * 4];
|
||||||
|
|
||||||
|
// For each edge (k,k+1) of P
|
||||||
|
for (int k = 0; k < n; k++)
|
||||||
|
{
|
||||||
|
int k1 = next(k, n);
|
||||||
|
// Skip edges incident to i or j
|
||||||
|
if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
|
||||||
|
{
|
||||||
|
const int* p0 = &verts[(indices[k] & 0x0fffffff) * 4];
|
||||||
|
const int* p1 = &verts[(indices[k1] & 0x0fffffff) * 4];
|
||||||
|
|
||||||
|
if (vequal(d0, p0) || vequal(d1, p0) || vequal(d0, p1) || vequal(d1, p1))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (intersectProp(d0, d1, p0, p1))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool inConeLoose(int i, int j, int n, const int* verts, int* indices)
|
||||||
|
{
|
||||||
|
const int* pi = &verts[(indices[i] & 0x0fffffff) * 4];
|
||||||
|
const int* pj = &verts[(indices[j] & 0x0fffffff) * 4];
|
||||||
|
const int* pi1 = &verts[(indices[next(i, n)] & 0x0fffffff) * 4];
|
||||||
|
const int* pin1 = &verts[(indices[prev(i, n)] & 0x0fffffff) * 4];
|
||||||
|
|
||||||
|
// If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
|
||||||
|
if (leftOn(pin1, pi, pi1))
|
||||||
|
return leftOn(pi, pj, pin1) && leftOn(pj, pi, pi1);
|
||||||
|
// Assume (i-1,i,i+1) not collinear.
|
||||||
|
// else P[i] is reflex.
|
||||||
|
return !(leftOn(pi, pj, pi1) && leftOn(pj, pi, pin1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool diagonalLoose(int i, int j, int n, const int* verts, int* indices)
|
||||||
|
{
|
||||||
|
return inConeLoose(i, j, n, verts, indices) && diagonalieLoose(i, j, n, verts, indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int triangulate(int n, const int* verts, int* indices, int* tris)
|
static int triangulate(int n, const int* verts, int* indices, int* tris)
|
||||||
{
|
{
|
||||||
int ntris = 0;
|
int ntris = 0;
|
||||||
|
|
@ -326,15 +375,42 @@ static int triangulate(int n, const int* verts, int* indices, int* tris)
|
||||||
|
|
||||||
if (mini == -1)
|
if (mini == -1)
|
||||||
{
|
{
|
||||||
// Should not happen.
|
// We might get here because the contour has overlapping segments, like this:
|
||||||
/* printf("mini == -1 ntris=%d n=%d\n", ntris, n);
|
//
|
||||||
|
// A o-o=====o---o B
|
||||||
|
// / |C D| \
|
||||||
|
// o o o o
|
||||||
|
// : : : :
|
||||||
|
// We'll try to recover by loosing up the inCone test a bit so that a diagonal
|
||||||
|
// like A-B or C-D can be found and we can continue.
|
||||||
|
minLen = -1;
|
||||||
|
mini = -1;
|
||||||
for (int i = 0; i < n; i++)
|
for (int i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
printf("%d ", indices[i] & 0x0fffffff);
|
int i1 = next(i, n);
|
||||||
|
int i2 = next(i1, n);
|
||||||
|
if (diagonalLoose(i, i2, n, verts, indices))
|
||||||
|
{
|
||||||
|
const int* p0 = &verts[(indices[i] & 0x0fffffff) * 4];
|
||||||
|
const int* p2 = &verts[(indices[next(i2, n)] & 0x0fffffff) * 4];
|
||||||
|
int dx = p2[0] - p0[0];
|
||||||
|
int dy = p2[2] - p0[2];
|
||||||
|
int len = dx*dx + dy*dy;
|
||||||
|
|
||||||
|
if (minLen < 0 || len < minLen)
|
||||||
|
{
|
||||||
|
minLen = len;
|
||||||
|
mini = i;
|
||||||
}
|
}
|
||||||
printf("\n");*/
|
}
|
||||||
|
}
|
||||||
|
if (mini == -1)
|
||||||
|
{
|
||||||
|
// The contour is messed up. This sometimes happens
|
||||||
|
// if the contour simplification is too aggressive.
|
||||||
return -ntris;
|
return -ntris;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int i = mini;
|
int i = mini;
|
||||||
int i1 = next(i, n);
|
int i1 = next(i, n);
|
||||||
|
|
@ -470,6 +546,7 @@ static void mergePolys(unsigned short* pa, unsigned short* pb, int ea, int eb,
|
||||||
memcpy(pa, tmp, sizeof(unsigned short)*nvp);
|
memcpy(pa, tmp, sizeof(unsigned short)*nvp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void pushFront(int v, int* arr, int& an)
|
static void pushFront(int v, int* arr, int& an)
|
||||||
{
|
{
|
||||||
an++;
|
an++;
|
||||||
|
|
@ -547,9 +624,9 @@ static bool canRemoveVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned sho
|
||||||
|
|
||||||
// Check if the edge exists
|
// Check if the edge exists
|
||||||
bool exists = false;
|
bool exists = false;
|
||||||
for (int k = 0; k < nedges; ++k)
|
for (int m = 0; m < nedges; ++m)
|
||||||
{
|
{
|
||||||
int* e = &edges[k*3];
|
int* e = &edges[m*3];
|
||||||
if (e[1] == b)
|
if (e[1] == b)
|
||||||
{
|
{
|
||||||
// Exists, increment vertex share count.
|
// Exists, increment vertex share count.
|
||||||
|
|
@ -658,6 +735,7 @@ 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];
|
||||||
|
if (p != p2)
|
||||||
memcpy(p,p2,sizeof(unsigned short)*nvp);
|
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];
|
||||||
|
|
@ -858,7 +936,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--;
|
||||||
|
|
@ -892,8 +972,13 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& mesh)
|
///
|
||||||
|
/// @note If the mesh data is to be used to construct a Detour navigation mesh, then the upper
|
||||||
|
/// limit must be retricted to <= #DT_VERTS_PER_POLYGON.
|
||||||
|
///
|
||||||
|
/// @see rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig
|
||||||
|
bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMesh& mesh)
|
||||||
{
|
{
|
||||||
rcAssert(ctx);
|
rcAssert(ctx);
|
||||||
|
|
||||||
|
|
@ -903,6 +988,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& me
|
||||||
rcVcopy(mesh.bmax, cset.bmax);
|
rcVcopy(mesh.bmax, cset.bmax);
|
||||||
mesh.cs = cset.cs;
|
mesh.cs = cset.cs;
|
||||||
mesh.ch = cset.ch;
|
mesh.ch = cset.ch;
|
||||||
|
mesh.borderSize = cset.borderSize;
|
||||||
|
|
||||||
int maxVertices = 0;
|
int maxVertices = 0;
|
||||||
int maxTris = 0;
|
int maxTris = 0;
|
||||||
|
|
@ -925,7 +1011,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& me
|
||||||
rcScopedDelete<unsigned char> vflags = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxVertices, RC_ALLOC_TEMP);
|
rcScopedDelete<unsigned char> vflags = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxVertices, RC_ALLOC_TEMP);
|
||||||
if (!vflags)
|
if (!vflags)
|
||||||
{
|
{
|
||||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices);
|
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'vflags' (%d).", maxVertices);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memset(vflags, 0, maxVertices);
|
memset(vflags, 0, maxVertices);
|
||||||
|
|
@ -936,7 +1022,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& me
|
||||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices);
|
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris*nvp*2*2, RC_ALLOC_PERM);
|
mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris*nvp*2, RC_ALLOC_PERM);
|
||||||
if (!mesh.polys)
|
if (!mesh.polys)
|
||||||
{
|
{
|
||||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.polys' (%d).", maxTris*nvp*2);
|
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.polys' (%d).", maxTris*nvp*2);
|
||||||
|
|
@ -1096,7 +1182,9 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& me
|
||||||
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
|
||||||
|
|
@ -1141,6 +1229,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& me
|
||||||
}
|
}
|
||||||
// Remove vertex
|
// Remove vertex
|
||||||
// Note: mesh.nverts is already decremented inside removeVertex()!
|
// Note: mesh.nverts is already decremented inside removeVertex()!
|
||||||
|
// Fixup vertex flags
|
||||||
for (int j = i; j < mesh.nverts; ++j)
|
for (int j = i; j < mesh.nverts; ++j)
|
||||||
vflags[j] = vflags[j+1];
|
vflags[j] = vflags[j+1];
|
||||||
--i;
|
--i;
|
||||||
|
|
@ -1154,6 +1243,37 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& me
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find portal edges
|
||||||
|
if (mesh.borderSize > 0)
|
||||||
|
{
|
||||||
|
const int w = cset.width;
|
||||||
|
const int h = cset.height;
|
||||||
|
for (int i = 0; i < mesh.npolys; ++i)
|
||||||
|
{
|
||||||
|
unsigned short* p = &mesh.polys[i*2*nvp];
|
||||||
|
for (int j = 0; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == RC_MESH_NULL_IDX) break;
|
||||||
|
// Skip connected edges.
|
||||||
|
if (p[nvp+j] != RC_MESH_NULL_IDX)
|
||||||
|
continue;
|
||||||
|
int nj = j+1;
|
||||||
|
if (nj >= nvp || p[nj] == RC_MESH_NULL_IDX) nj = 0;
|
||||||
|
const unsigned short* va = &mesh.verts[p[j]*3];
|
||||||
|
const unsigned short* vb = &mesh.verts[p[nj]*3];
|
||||||
|
|
||||||
|
if ((int)va[0] == 0 && (int)vb[0] == 0)
|
||||||
|
p[nvp+j] = 0x8000 | 0;
|
||||||
|
else if ((int)va[2] == h && (int)vb[2] == h)
|
||||||
|
p[nvp+j] = 0x8000 | 1;
|
||||||
|
else if ((int)va[0] == w && (int)vb[0] == w)
|
||||||
|
p[nvp+j] = 0x8000 | 2;
|
||||||
|
else if ((int)va[2] == 0 && (int)vb[2] == 0)
|
||||||
|
p[nvp+j] = 0x8000 | 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Just allocate the mesh flags array. The user is resposible to fill it.
|
// Just allocate the mesh flags array. The user is resposible to fill it.
|
||||||
mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*mesh.npolys, RC_ALLOC_PERM);
|
mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*mesh.npolys, RC_ALLOC_PERM);
|
||||||
if (!mesh.flags)
|
if (!mesh.flags)
|
||||||
|
|
@ -1165,11 +1285,11 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& me
|
||||||
|
|
||||||
if (mesh.nverts > 0xffff)
|
if (mesh.nverts > 0xffff)
|
||||||
{
|
{
|
||||||
ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: The resulting mesh has too many vertices %d (max %d). Data can be corrupted.", mesh.nverts, 0xffff);
|
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: The resulting mesh has too many vertices %d (max %d). Data can be corrupted.", mesh.nverts, 0xffff);
|
||||||
}
|
}
|
||||||
if (mesh.npolys > 0xffff)
|
if (mesh.npolys > 0xffff)
|
||||||
{
|
{
|
||||||
ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff);
|
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->stopTimer(RC_TIMER_BUILD_POLYMESH);
|
ctx->stopTimer(RC_TIMER_BUILD_POLYMESH);
|
||||||
|
|
@ -1177,6 +1297,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& me
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @see rcAllocPolyMesh, rcPolyMesh
|
||||||
bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
|
bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
|
||||||
{
|
{
|
||||||
rcAssert(ctx);
|
rcAssert(ctx);
|
||||||
|
|
@ -1268,7 +1389,7 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
|
||||||
ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'vremap' (%d).", maxVertsPerMesh);
|
ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'vremap' (%d).", maxVertsPerMesh);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memset(nextVert, 0, sizeof(int)*maxVerts);
|
memset(vremap, 0, sizeof(unsigned short)*maxVertsPerMesh);
|
||||||
|
|
||||||
for (int i = 0; i < nmeshes; ++i)
|
for (int i = 0; i < nmeshes; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -1277,6 +1398,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];
|
||||||
|
|
@ -1297,6 +1424,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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1320,3 +1477,67 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rcCopyPolyMesh(rcContext* ctx, const rcPolyMesh& src, rcPolyMesh& dst)
|
||||||
|
{
|
||||||
|
rcAssert(ctx);
|
||||||
|
|
||||||
|
// Destination must be empty.
|
||||||
|
rcAssert(dst.verts == 0);
|
||||||
|
rcAssert(dst.polys == 0);
|
||||||
|
rcAssert(dst.regs == 0);
|
||||||
|
rcAssert(dst.areas == 0);
|
||||||
|
rcAssert(dst.flags == 0);
|
||||||
|
|
||||||
|
dst.nverts = src.nverts;
|
||||||
|
dst.npolys = src.npolys;
|
||||||
|
dst.maxpolys = src.npolys;
|
||||||
|
dst.nvp = src.nvp;
|
||||||
|
rcVcopy(dst.bmin, src.bmin);
|
||||||
|
rcVcopy(dst.bmax, src.bmax);
|
||||||
|
dst.cs = src.cs;
|
||||||
|
dst.ch = src.ch;
|
||||||
|
dst.borderSize = src.borderSize;
|
||||||
|
|
||||||
|
dst.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.nverts*3, RC_ALLOC_PERM);
|
||||||
|
if (!dst.verts)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.verts' (%d).", src.nverts*3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(dst.verts, src.verts, sizeof(unsigned short)*src.nverts*3);
|
||||||
|
|
||||||
|
dst.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys*2*src.nvp, RC_ALLOC_PERM);
|
||||||
|
if (!dst.polys)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.polys' (%d).", src.npolys*2*src.nvp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(dst.polys, src.polys, sizeof(unsigned short)*src.npolys*2*src.nvp);
|
||||||
|
|
||||||
|
dst.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys, RC_ALLOC_PERM);
|
||||||
|
if (!dst.regs)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.regs' (%d).", src.npolys);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(dst.regs, src.regs, sizeof(unsigned short)*src.npolys);
|
||||||
|
|
||||||
|
dst.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*src.npolys, RC_ALLOC_PERM);
|
||||||
|
if (!dst.areas)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.areas' (%d).", src.npolys);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(dst.areas, src.areas, sizeof(unsigned char)*src.npolys);
|
||||||
|
|
||||||
|
dst.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys, RC_ALLOC_PERM);
|
||||||
|
if (!dst.flags)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.flags' (%d).", src.npolys);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(dst.flags, src.flags, sizeof(unsigned short)*src.npolys);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,21 +68,27 @@ static bool circumCircle(const float* p1, const float* p2, const float* p3,
|
||||||
float* c, float& r)
|
float* c, float& r)
|
||||||
{
|
{
|
||||||
static const float EPS = 1e-6f;
|
static const float EPS = 1e-6f;
|
||||||
|
// Calculate the circle relative to p1, to avoid some precision issues.
|
||||||
|
const float v1[3] = {0,0,0};
|
||||||
|
float v2[3], v3[3];
|
||||||
|
rcVsub(v2, p2,p1);
|
||||||
|
rcVsub(v3, p3,p1);
|
||||||
|
|
||||||
const float cp = vcross2(p1, p2, p3);
|
const float cp = vcross2(v1, v2, v3);
|
||||||
if (fabsf(cp) > EPS)
|
if (fabsf(cp) > EPS)
|
||||||
{
|
{
|
||||||
const float p1Sq = vdot2(p1,p1);
|
const float v1Sq = vdot2(v1,v1);
|
||||||
const float p2Sq = vdot2(p2,p2);
|
const float v2Sq = vdot2(v2,v2);
|
||||||
const float p3Sq = vdot2(p3,p3);
|
const float v3Sq = vdot2(v3,v3);
|
||||||
c[0] = (p1Sq*(p2[2]-p3[2]) + p2Sq*(p3[2]-p1[2]) + p3Sq*(p1[2]-p2[2])) / (2*cp);
|
c[0] = (v1Sq*(v2[2]-v3[2]) + v2Sq*(v3[2]-v1[2]) + v3Sq*(v1[2]-v2[2])) / (2*cp);
|
||||||
c[2] = (p1Sq*(p3[0]-p2[0]) + p2Sq*(p1[0]-p3[0]) + p3Sq*(p2[0]-p1[0])) / (2*cp);
|
c[1] = 0;
|
||||||
r = vdist2(c, p1);
|
c[2] = (v1Sq*(v3[0]-v2[0]) + v2Sq*(v1[0]-v3[0]) + v3Sq*(v2[0]-v1[0])) / (2*cp);
|
||||||
|
r = vdist2(c, v1);
|
||||||
|
rcVadd(c, c, p1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
c[0] = p1[0];
|
rcVcopy(c, p1);
|
||||||
c[2] = p1[2];
|
|
||||||
r = 0;
|
r = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -200,8 +206,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);
|
ix = rcClamp(ix-hp.xmin, 0, hp.width - 1);
|
||||||
iz = rcClamp(iz-hp.ymin, 0, hp.height);
|
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)
|
||||||
{
|
{
|
||||||
|
|
@ -223,15 +229,6 @@ static unsigned short getHeight(const float fx, const float fy, const float fz,
|
||||||
h = nh;
|
h = nh;
|
||||||
dmin = d;
|
dmin = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* const float dx = (nx+0.5f)*cs - fx;
|
|
||||||
const float dz = (nz+0.5f)*cs - fz;
|
|
||||||
const float d = dx*dx+dz*dz;
|
|
||||||
if (d < dmin)
|
|
||||||
{
|
|
||||||
h = nh;
|
|
||||||
dmin = d;
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
|
|
@ -267,11 +264,11 @@ static int addEdge(rcContext* ctx, int* edges, int& nedges, const int maxEdges,
|
||||||
int e = findEdge(edges, nedges, s, t);
|
int e = findEdge(edges, nedges, s, t);
|
||||||
if (e == UNDEF)
|
if (e == UNDEF)
|
||||||
{
|
{
|
||||||
int* e = &edges[nedges*4];
|
int* edge = &edges[nedges*4];
|
||||||
e[0] = s;
|
edge[0] = s;
|
||||||
e[1] = t;
|
edge[1] = t;
|
||||||
e[2] = l;
|
edge[2] = l;
|
||||||
e[3] = r;
|
edge[3] = r;
|
||||||
return nedges++;
|
return nedges++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -489,6 +486,103 @@ static void delaunayHull(rcContext* ctx, const int npts, const float* pts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate minimum extend of the polygon.
|
||||||
|
static float polyMinExtent(const float* verts, const int nverts)
|
||||||
|
{
|
||||||
|
float minDist = FLT_MAX;
|
||||||
|
for (int i = 0; i < nverts; i++)
|
||||||
|
{
|
||||||
|
const int ni = (i+1) % nverts;
|
||||||
|
const float* p1 = &verts[i*3];
|
||||||
|
const float* p2 = &verts[ni*3];
|
||||||
|
float maxEdgeDist = 0;
|
||||||
|
for (int j = 0; j < nverts; j++)
|
||||||
|
{
|
||||||
|
if (j == i || j == ni) continue;
|
||||||
|
float d = distancePtSeg2d(&verts[j*3], p1,p2);
|
||||||
|
maxEdgeDist = rcMax(maxEdgeDist, d);
|
||||||
|
}
|
||||||
|
minDist = rcMin(minDist, maxEdgeDist);
|
||||||
|
}
|
||||||
|
return rcSqrt(minDist);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int next(int i, int n)
|
||||||
|
{
|
||||||
|
return (i+1) % n;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int prev(int i, int n)
|
||||||
|
{
|
||||||
|
return (i + n-1) % n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void triangulateHull(const int nverts, const float* verts, const int nhull, const int* hull, rcIntArray& tris)
|
||||||
|
{
|
||||||
|
int start = 0, left = 1, right = nhull-1;
|
||||||
|
|
||||||
|
// Start from an ear with shortest perimeter.
|
||||||
|
// This tends to favor well formed triangles as starting point.
|
||||||
|
float dmin = 0;
|
||||||
|
for (int i = 0; i < nhull; i++)
|
||||||
|
{
|
||||||
|
int pi = prev(i, nhull);
|
||||||
|
int ni = next(i, nhull);
|
||||||
|
const float* pv = &verts[hull[pi]*3];
|
||||||
|
const float* cv = &verts[hull[i]*3];
|
||||||
|
const float* nv = &verts[hull[ni]*3];
|
||||||
|
const float d = vdist2(pv,cv) + vdist2(cv,nv) + vdist2(nv,pv);
|
||||||
|
if (d < dmin)
|
||||||
|
{
|
||||||
|
start = i;
|
||||||
|
left = ni;
|
||||||
|
right = pi;
|
||||||
|
dmin = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add first triangle
|
||||||
|
tris.push(hull[start]);
|
||||||
|
tris.push(hull[left]);
|
||||||
|
tris.push(hull[right]);
|
||||||
|
tris.push(0);
|
||||||
|
|
||||||
|
// Triangulate the polygon by moving left or right,
|
||||||
|
// depending on which triangle has shorter perimeter.
|
||||||
|
// This heuristic was chose emprically, since it seems
|
||||||
|
// handle tesselated straight edges well.
|
||||||
|
while (next(left, nhull) != right)
|
||||||
|
{
|
||||||
|
// Check to see if se should advance left or right.
|
||||||
|
int nleft = next(left, nhull);
|
||||||
|
int nright = prev(right, nhull);
|
||||||
|
|
||||||
|
const float* cvleft = &verts[hull[left]*3];
|
||||||
|
const float* nvleft = &verts[hull[nleft]*3];
|
||||||
|
const float* cvright = &verts[hull[right]*3];
|
||||||
|
const float* nvright = &verts[hull[nright]*3];
|
||||||
|
const float dleft = vdist2(cvleft, nvleft) + vdist2(nvleft, cvright);
|
||||||
|
const float dright = vdist2(cvright, nvright) + vdist2(cvleft, nvright);
|
||||||
|
|
||||||
|
if (dleft < dright)
|
||||||
|
{
|
||||||
|
tris.push(hull[left]);
|
||||||
|
tris.push(hull[nleft]);
|
||||||
|
tris.push(hull[right]);
|
||||||
|
tris.push(0);
|
||||||
|
left = nleft;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tris.push(hull[left]);
|
||||||
|
tris.push(hull[nright]);
|
||||||
|
tris.push(hull[right]);
|
||||||
|
tris.push(0);
|
||||||
|
right = nright;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline float getJitterX(const int i)
|
inline float getJitterX(const int i)
|
||||||
{
|
{
|
||||||
|
|
@ -519,9 +613,15 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||||
rcVcopy(&verts[i*3], &in[i*3]);
|
rcVcopy(&verts[i*3], &in[i*3]);
|
||||||
nverts = nin;
|
nverts = nin;
|
||||||
|
|
||||||
|
edges.resize(0);
|
||||||
|
tris.resize(0);
|
||||||
|
|
||||||
const float cs = chf.cs;
|
const float cs = chf.cs;
|
||||||
const float ics = 1.0f/cs;
|
const float ics = 1.0f/cs;
|
||||||
|
|
||||||
|
// Calculate minimum extents of the polygon based on input data.
|
||||||
|
float minExtent = polyMinExtent(verts, nverts);
|
||||||
|
|
||||||
// Tessellate outlines.
|
// Tessellate outlines.
|
||||||
// This is done in separate pass in order to ensure
|
// This is done in separate pass in order to ensure
|
||||||
// seamless height values across the ply boundaries.
|
// seamless height values across the ply boundaries.
|
||||||
|
|
@ -583,10 +683,10 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||||
int maxi = -1;
|
int maxi = -1;
|
||||||
for (int m = a+1; m < b; ++m)
|
for (int m = a+1; m < b; ++m)
|
||||||
{
|
{
|
||||||
float d = distancePtSeg(&edge[m*3],va,vb);
|
float dev = distancePtSeg(&edge[m*3],va,vb);
|
||||||
if (d > maxd)
|
if (dev > maxd)
|
||||||
{
|
{
|
||||||
maxd = d;
|
maxd = dev;
|
||||||
maxi = m;
|
maxi = m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -628,24 +728,23 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the polygon minimum extent is small (sliver or small triangle), do not try to add internal points.
|
||||||
|
if (minExtent < sampleDist*2)
|
||||||
|
{
|
||||||
|
triangulateHull(nverts, verts, nhull, hull, tris);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Tessellate the base mesh.
|
// Tessellate the base mesh.
|
||||||
edges.resize(0);
|
// We're using the triangulateHull instead of delaunayHull as it tends to
|
||||||
tris.resize(0);
|
// create a bit better triangulation for long thing triangles when there
|
||||||
|
// are no internal points.
|
||||||
delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges);
|
triangulateHull(nverts, verts, nhull, hull, tris);
|
||||||
|
|
||||||
if (tris.size() == 0)
|
if (tris.size() == 0)
|
||||||
{
|
{
|
||||||
// Could not triangulate the poly, make sure there is some valid data there.
|
// Could not triangulate the poly, make sure there is some valid data there.
|
||||||
ctx->log(RC_LOG_WARNING, "buildPolyDetail: Could not triangulate polygon, adding default data.");
|
ctx->log(RC_LOG_WARNING, "buildPolyDetail: Could not triangulate polygon (%d verts).", nverts);
|
||||||
for (int i = 2; i < nverts; ++i)
|
|
||||||
{
|
|
||||||
tris.push(0);
|
|
||||||
tris.push(i-1);
|
|
||||||
tris.push(i);
|
|
||||||
tris.push(0);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -741,14 +840,18 @@ 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 unsigned short* verts, const int bs,
|
||||||
rcHeightPatch& hp, rcIntArray& stack)
|
rcHeightPatch& hp, rcIntArray& stack)
|
||||||
{
|
{
|
||||||
// Floodfill the heightfield to get 2D height data,
|
// Floodfill the heightfield to get 2D height data,
|
||||||
// starting at vertex locations as seeds.
|
// starting at vertex locations as seeds.
|
||||||
|
|
||||||
|
// Note: Reads to the compact heightfield are offset by border size (bs)
|
||||||
|
// since border size offset is already removed from the polymesh vertices.
|
||||||
|
|
||||||
memset(hp.data, 0, sizeof(unsigned short)*hp.width*hp.height);
|
memset(hp.data, 0, sizeof(unsigned short)*hp.width*hp.height);
|
||||||
|
|
||||||
stack.resize(0);
|
stack.resize(0);
|
||||||
|
|
@ -772,7 +875,7 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
||||||
az < hp.ymin || az >= hp.ymin+hp.height)
|
az < hp.ymin || az >= hp.ymin+hp.height)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const rcCompactCell& c = chf.cells[ax+az*chf.width];
|
const rcCompactCell& c = chf.cells[(ax+bs)+(az+bs)*chf.width];
|
||||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||||
{
|
{
|
||||||
const rcCompactSpan& s = chf.spans[i];
|
const rcCompactSpan& s = chf.spans[i];
|
||||||
|
|
@ -844,7 +947,7 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
||||||
if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != 0)
|
if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(cs, dir);
|
const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir);
|
||||||
|
|
||||||
int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width;
|
int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width;
|
||||||
hp.data[idx] = 1;
|
hp.data[idx] = 1;
|
||||||
|
|
@ -866,8 +969,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;
|
||||||
|
|
||||||
|
|
@ -892,26 +1070,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) ||
|
if (hx < 0 || hx >= hp.width || hy < 0 || hy >= hp.height)
|
||||||
ay < hp.ymin || ay >= (hp.ymin+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+ay*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,
|
||||||
|
|
@ -938,8 +1115,11 @@ static unsigned char getTriFlags(const float* va, const float* vb, const float*
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
|
///
|
||||||
|
/// @see rcAllocPolyMeshDetail, rcPolyMesh, rcCompactHeightfield, rcPolyMeshDetail, rcConfig
|
||||||
bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf,
|
bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf,
|
||||||
const float sampleDist, const float sampleMaxError,
|
const float sampleDist, const float sampleMaxError,
|
||||||
rcPolyMeshDetail& dmesh)
|
rcPolyMeshDetail& dmesh)
|
||||||
|
|
@ -955,6 +1135,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||||
const float cs = mesh.cs;
|
const float cs = mesh.cs;
|
||||||
const float ch = mesh.ch;
|
const float ch = mesh.ch;
|
||||||
const float* orig = mesh.bmin;
|
const float* orig = mesh.bmin;
|
||||||
|
const int borderSize = mesh.borderSize;
|
||||||
|
|
||||||
rcIntArray edges(64);
|
rcIntArray edges(64);
|
||||||
rcIntArray tris(512);
|
rcIntArray tris(512);
|
||||||
|
|
@ -1037,7 +1218,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dmesh.ntris = 0;
|
dmesh.ntris = 0;
|
||||||
dmesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char*)*tcap*4, RC_ALLOC_PERM);
|
dmesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char)*tcap*4, RC_ALLOC_PERM);
|
||||||
if (!dmesh.tris)
|
if (!dmesh.tris)
|
||||||
{
|
{
|
||||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", tcap*4);
|
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", tcap*4);
|
||||||
|
|
@ -1065,7 +1246,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, 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;
|
||||||
|
|
@ -1157,6 +1338,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @see rcAllocPolyMeshDetail, rcPolyMeshDetail
|
||||||
bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh)
|
bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh)
|
||||||
{
|
{
|
||||||
rcAssert(ctx);
|
rcAssert(ctx);
|
||||||
|
|
@ -1234,4 +1416,3 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -154,6 +154,13 @@ static void addSpan(rcHeightfield& hf, const int x, const int y,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// The span addition can be set to favor flags. If the span is merged to
|
||||||
|
/// another span and the new @p smax is within @p flagMergeThr units
|
||||||
|
/// from the existing span, the span flags are merged.
|
||||||
|
///
|
||||||
|
/// @see rcHeightfield, rcSpan.
|
||||||
void rcAddSpan(rcContext* /*ctx*/, rcHeightfield& hf, const int x, const int y,
|
void rcAddSpan(rcContext* /*ctx*/, rcHeightfield& hf, const int x, const int y,
|
||||||
const unsigned short smin, const unsigned short smax,
|
const unsigned short smin, const unsigned short smax,
|
||||||
const unsigned char area, const int flagMergeThr)
|
const unsigned char area, const int flagMergeThr)
|
||||||
|
|
@ -162,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)
|
for (int i = 0; i < nin; ++i)
|
||||||
d[i] = pnx*in[i*3+0] + pnz*in[i*3+2] + pd;
|
d[i] = x - in[i*3+axis];
|
||||||
|
|
||||||
int m = 0;
|
int m = 0, n = 0;
|
||||||
for (int i = 0, j = n-1; i < n; j=i, ++i)
|
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;
|
out1[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;
|
out1[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+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
|
||||||
|
rcVcopy(out2 + n*3, out1 + m*3);
|
||||||
m++;
|
m++;
|
||||||
}
|
n++;
|
||||||
if (inb)
|
// 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)
|
||||||
{
|
{
|
||||||
out[m*3+0] = in[i*3+0];
|
rcVcopy(out1 + m*3, in + i*3);
|
||||||
out[m*3+1] = in[i*3+1];
|
|
||||||
out[m*3+2] = in[i*3+2];
|
|
||||||
m++;
|
m++;
|
||||||
}
|
}
|
||||||
|
else if (d[i] < 0)
|
||||||
|
{
|
||||||
|
rcVcopy(out2 + n*3, in + i*3);
|
||||||
|
n++;
|
||||||
}
|
}
|
||||||
return m;
|
}
|
||||||
|
else // same side
|
||||||
|
{
|
||||||
|
// 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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*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,
|
||||||
|
|
@ -215,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.
|
// Calculate the footprint of the triangle on the grid's y-axis
|
||||||
int x0 = (int)((tmin[0] - bmin[0])*ics);
|
|
||||||
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;
|
||||||
|
|
||||||
for (int y = y0; y <= y1; ++y)
|
|
||||||
{
|
|
||||||
// Clip polygon to row.
|
|
||||||
rcVcopy(&in[0], v0);
|
rcVcopy(&in[0], v0);
|
||||||
rcVcopy(&in[1*3], v1);
|
rcVcopy(&in[1*3], v1);
|
||||||
rcVcopy(&in[2*3], v2);
|
rcVcopy(&in[2*3], v2);
|
||||||
int nvrow = 3;
|
int nvrow, nvIn = 3;
|
||||||
|
|
||||||
|
for (int y = y0; y <= y1; ++y)
|
||||||
|
{
|
||||||
|
// 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);
|
dividePoly(in, nvIn, inrow, &nvrow, p1, &nvIn, cz+cs, 2);
|
||||||
if (nvrow < 3) continue;
|
rcSwap(in, p1);
|
||||||
nvrow = clipPoly(out, nvrow, inrow, 0, -1, cz+cs);
|
|
||||||
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.
|
// Clip polygon to column. store the remaining polygon as well
|
||||||
int nv = nvrow;
|
|
||||||
const float cx = bmin[0] + x*cs;
|
const float cx = bmin[0] + x*cs;
|
||||||
nv = clipPoly(inrow, nv, out, 1, 0, -cx);
|
dividePoly(inrow, nv2, p1, &nv, p2, &nv2, cx+cs, 0);
|
||||||
if (nv < 3) continue;
|
rcSwap(inrow, p2);
|
||||||
nv = clipPoly(out, nv, in, -1, 0, cx+cs);
|
|
||||||
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]);
|
smin = rcMin(smin, p1[i*3+1]);
|
||||||
smax = rcMax(smax, in[i*3+1]);
|
smax = rcMax(smax, p1[i*3+1]);
|
||||||
}
|
}
|
||||||
smin -= bmin[1];
|
smin -= bmin[1];
|
||||||
smax -= bmin[1];
|
smax -= bmin[1];
|
||||||
|
|
@ -276,6 +320,11 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// No spans will be added if the triangle does not overlap the heightfield grid.
|
||||||
|
///
|
||||||
|
/// @see rcHeightfield
|
||||||
void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
|
void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
|
||||||
const unsigned char area, rcHeightfield& solid,
|
const unsigned char area, rcHeightfield& solid,
|
||||||
const int flagMergeThr)
|
const int flagMergeThr)
|
||||||
|
|
@ -291,6 +340,11 @@ void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const
|
||||||
ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// Spans will only be added for triangles that overlap the heightfield grid.
|
||||||
|
///
|
||||||
|
/// @see rcHeightfield
|
||||||
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
||||||
const int* tris, const unsigned char* areas, const int nt,
|
const int* tris, const unsigned char* areas, const int nt,
|
||||||
rcHeightfield& solid, const int flagMergeThr)
|
rcHeightfield& solid, const int flagMergeThr)
|
||||||
|
|
@ -314,6 +368,11 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
||||||
ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// Spans will only be added for triangles that overlap the heightfield grid.
|
||||||
|
///
|
||||||
|
/// @see rcHeightfield
|
||||||
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
||||||
const unsigned short* tris, const unsigned char* areas, const int nt,
|
const unsigned short* tris, const unsigned char* areas, const int nt,
|
||||||
rcHeightfield& solid, const int flagMergeThr)
|
rcHeightfield& solid, const int flagMergeThr)
|
||||||
|
|
@ -337,6 +396,11 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
||||||
ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// Spans will only be added for triangles that overlap the heightfield grid.
|
||||||
|
///
|
||||||
|
/// @see rcHeightfield
|
||||||
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
|
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
|
||||||
rcHeightfield& solid, const int flagMergeThr)
|
rcHeightfield& solid, const int flagMergeThr)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -283,8 +283,13 @@ static bool floodRegion(int x, int y, int i,
|
||||||
if (chf.areas[ai] != area)
|
if (chf.areas[ai] != area)
|
||||||
continue;
|
continue;
|
||||||
unsigned short nr = srcReg[ai];
|
unsigned short nr = srcReg[ai];
|
||||||
|
if (nr & RC_BORDER_REG) // Do not take borders into account.
|
||||||
|
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];
|
||||||
|
|
||||||
|
|
@ -296,9 +301,12 @@ static bool floodRegion(int x, int y, int i,
|
||||||
const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2);
|
const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2);
|
||||||
if (chf.areas[ai2] != area)
|
if (chf.areas[ai2] != area)
|
||||||
continue;
|
continue;
|
||||||
unsigned short nr = srcReg[ai2];
|
unsigned short nr2 = srcReg[ai2];
|
||||||
if (nr != 0 && nr != r)
|
if (nr2 != 0 && nr2 != r)
|
||||||
ar = nr;
|
{
|
||||||
|
ar = nr2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -307,6 +315,7 @@ static bool floodRegion(int x, int y, int i,
|
||||||
srcReg[ci] = 0;
|
srcReg[ci] = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
// Expand neighbours.
|
// Expand neighbours.
|
||||||
|
|
@ -319,9 +328,7 @@ static bool floodRegion(int x, int y, int i,
|
||||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir);
|
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir);
|
||||||
if (chf.areas[ai] != area)
|
if (chf.areas[ai] != area)
|
||||||
continue;
|
continue;
|
||||||
if (chf.dist[ai] >= lev)
|
if (chf.dist[ai] >= lev && srcReg[ai] == 0)
|
||||||
{
|
|
||||||
if (srcReg[ai] == 0)
|
|
||||||
{
|
{
|
||||||
srcReg[ai] = r;
|
srcReg[ai] = r;
|
||||||
srcDist[ai] = 0;
|
srcDist[ai] = 0;
|
||||||
|
|
@ -332,7 +339,6 @@ static bool floodRegion(int x, int y, int i,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return count > 0;
|
return count > 0;
|
||||||
}
|
}
|
||||||
|
|
@ -341,11 +347,14 @@ 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;
|
||||||
|
|
||||||
|
if (fillStack)
|
||||||
|
{
|
||||||
// Find cells revealed by the raised level.
|
// Find cells revealed by the raised level.
|
||||||
stack.resize(0);
|
stack.resize(0);
|
||||||
for (int y = 0; y < h; ++y)
|
for (int y = 0; y < h; ++y)
|
||||||
|
|
@ -364,6 +373,17 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
|
@ -435,6 +455,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) :
|
||||||
|
|
@ -442,7 +517,11 @@ struct rcRegion
|
||||||
id(i),
|
id(i),
|
||||||
areaType(0),
|
areaType(0),
|
||||||
remap(false),
|
remap(false),
|
||||||
visited(false)
|
visited(false),
|
||||||
|
overlap(false),
|
||||||
|
connectsToBorder(false),
|
||||||
|
ymin(0xffff),
|
||||||
|
ymax(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
int spanCount; // Number of spans belonging to this region
|
int spanCount; // Number of spans belonging to this region
|
||||||
|
|
@ -450,6 +529,9 @@ struct rcRegion
|
||||||
unsigned char areaType; // Are type.
|
unsigned char areaType; // Are type.
|
||||||
bool remap;
|
bool remap;
|
||||||
bool visited;
|
bool visited;
|
||||||
|
bool overlap;
|
||||||
|
bool connectsToBorder;
|
||||||
|
unsigned short ymin, ymax;
|
||||||
rcIntArray connections;
|
rcIntArray connections;
|
||||||
rcIntArray floors;
|
rcIntArray floors;
|
||||||
};
|
};
|
||||||
|
|
@ -679,25 +761,26 @@ static void walkContour(int x, int y, int i, int dir,
|
||||||
// Remove adjacent duplicates.
|
// Remove adjacent duplicates.
|
||||||
if (cont.size() > 1)
|
if (cont.size() > 1)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < cont.size(); )
|
for (int j = 0; j < cont.size(); )
|
||||||
{
|
{
|
||||||
int ni = (i+1) % cont.size();
|
int nj = (j+1) % cont.size();
|
||||||
if (cont[i] == cont[ni])
|
if (cont[j] == cont[nj])
|
||||||
{
|
{
|
||||||
for (int j = i; j < cont.size()-1; ++j)
|
for (int k = j; k < cont.size()-1; ++k)
|
||||||
cont[j] = cont[j+1];
|
cont[k] = cont[k+1];
|
||||||
cont.pop();
|
cont.pop();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
++i;
|
++j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegionSize,
|
|
||||||
|
static bool mergeAndFilterRegions(rcContext* ctx, int minRegionArea, int mergeRegionSize,
|
||||||
unsigned short& maxRegionId,
|
unsigned short& maxRegionId,
|
||||||
rcCompactHeightfield& chf,
|
rcCompactHeightfield& chf,
|
||||||
unsigned short* srcReg)
|
unsigned short* srcReg, rcIntArray& overlaps)
|
||||||
{
|
{
|
||||||
const int w = chf.width;
|
const int w = chf.width;
|
||||||
const int h = chf.height;
|
const int h = chf.height;
|
||||||
|
|
@ -706,7 +789,7 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
|
||||||
rcRegion* regions = (rcRegion*)rcAlloc(sizeof(rcRegion)*nreg, RC_ALLOC_TEMP);
|
rcRegion* regions = (rcRegion*)rcAlloc(sizeof(rcRegion)*nreg, RC_ALLOC_TEMP);
|
||||||
if (!regions)
|
if (!regions)
|
||||||
{
|
{
|
||||||
ctx->log(RC_LOG_ERROR, "filterSmallRegions: Out of memory 'regions' (%d).", nreg);
|
ctx->log(RC_LOG_ERROR, "mergeAndFilterRegions: Out of memory 'regions' (%d).", nreg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -729,7 +812,6 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
|
||||||
rcRegion& reg = regions[r];
|
rcRegion& reg = regions[r];
|
||||||
reg.spanCount++;
|
reg.spanCount++;
|
||||||
|
|
||||||
|
|
||||||
// Update floors.
|
// Update floors.
|
||||||
for (int j = (int)c.index; j < ni; ++j)
|
for (int j = (int)c.index; j < ni; ++j)
|
||||||
{
|
{
|
||||||
|
|
@ -737,6 +819,8 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
|
||||||
unsigned short floorId = srcReg[j];
|
unsigned short floorId = srcReg[j];
|
||||||
if (floorId == 0 || floorId >= nreg)
|
if (floorId == 0 || floorId >= nreg)
|
||||||
continue;
|
continue;
|
||||||
|
if (floorId == r)
|
||||||
|
reg.overlap = true;
|
||||||
addUniqueFloorRegion(reg, floorId);
|
addUniqueFloorRegion(reg, floorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -807,14 +891,14 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
|
||||||
connectsToBorder = true;
|
connectsToBorder = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
rcRegion& nreg = regions[creg.connections[j]];
|
rcRegion& neireg = regions[creg.connections[j]];
|
||||||
if (nreg.visited)
|
if (neireg.visited)
|
||||||
continue;
|
continue;
|
||||||
if (nreg.id == 0 || (nreg.id & RC_BORDER_REG))
|
if (neireg.id == 0 || (neireg.id & RC_BORDER_REG))
|
||||||
continue;
|
continue;
|
||||||
// Visit
|
// Visit
|
||||||
stack.push(nreg.id);
|
stack.push(neireg.id);
|
||||||
nreg.visited = true;
|
neireg.visited = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -843,6 +927,8 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
|
||||||
rcRegion& reg = regions[i];
|
rcRegion& reg = regions[i];
|
||||||
if (reg.id == 0 || (reg.id & RC_BORDER_REG))
|
if (reg.id == 0 || (reg.id & RC_BORDER_REG))
|
||||||
continue;
|
continue;
|
||||||
|
if (reg.overlap)
|
||||||
|
continue;
|
||||||
if (reg.spanCount == 0)
|
if (reg.spanCount == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -859,7 +945,7 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
|
||||||
{
|
{
|
||||||
if (reg.connections[j] & RC_BORDER_REG) continue;
|
if (reg.connections[j] & RC_BORDER_REG) continue;
|
||||||
rcRegion& mreg = regions[reg.connections[j]];
|
rcRegion& mreg = regions[reg.connections[j]];
|
||||||
if (mreg.id == 0 || (mreg.id & RC_BORDER_REG)) continue;
|
if (mreg.id == 0 || (mreg.id & RC_BORDER_REG) || mreg.overlap) continue;
|
||||||
if (mreg.spanCount < smallest &&
|
if (mreg.spanCount < smallest &&
|
||||||
canMergeWithRegion(reg, mreg) &&
|
canMergeWithRegion(reg, mreg) &&
|
||||||
canMergeWithRegion(mreg, reg))
|
canMergeWithRegion(mreg, reg))
|
||||||
|
|
@ -930,6 +1016,224 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
|
||||||
srcReg[i] = regions[srcReg[i]].id;
|
srcReg[i] = regions[srcReg[i]].id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return regions that we found to be overlapping.
|
||||||
|
for (int i = 0; i < nreg; ++i)
|
||||||
|
if (regions[i].overlap)
|
||||||
|
overlaps.push(regions[i].id);
|
||||||
|
|
||||||
|
for (int i = 0; i < nreg; ++i)
|
||||||
|
regions[i].~rcRegion();
|
||||||
|
rcFree(regions);
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void addUniqueConnection(rcRegion& reg, int n)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < reg.connections.size(); ++i)
|
||||||
|
if (reg.connections[i] == n)
|
||||||
|
return;
|
||||||
|
reg.connections.push(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mergeAndFilterLayerRegions(rcContext* ctx, int minRegionArea,
|
||||||
|
unsigned short& maxRegionId,
|
||||||
|
rcCompactHeightfield& chf,
|
||||||
|
unsigned short* srcReg, rcIntArray& overlaps)
|
||||||
|
{
|
||||||
|
const int w = chf.width;
|
||||||
|
const int h = chf.height;
|
||||||
|
|
||||||
|
const int nreg = maxRegionId+1;
|
||||||
|
rcRegion* regions = (rcRegion*)rcAlloc(sizeof(rcRegion)*nreg, RC_ALLOC_TEMP);
|
||||||
|
if (!regions)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "mergeAndFilterLayerRegions: Out of memory 'regions' (%d).", nreg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct regions
|
||||||
|
for (int i = 0; i < nreg; ++i)
|
||||||
|
new(®ions[i]) rcRegion((unsigned short)i);
|
||||||
|
|
||||||
|
// Find region neighbours and overlapping regions.
|
||||||
|
rcIntArray lregs(32);
|
||||||
|
for (int y = 0; y < h; ++y)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < w; ++x)
|
||||||
|
{
|
||||||
|
const rcCompactCell& c = chf.cells[x+y*w];
|
||||||
|
|
||||||
|
lregs.resize(0);
|
||||||
|
|
||||||
|
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||||
|
{
|
||||||
|
const rcCompactSpan& s = chf.spans[i];
|
||||||
|
const unsigned short ri = srcReg[i];
|
||||||
|
if (ri == 0 || ri >= nreg) continue;
|
||||||
|
rcRegion& reg = regions[ri];
|
||||||
|
|
||||||
|
reg.spanCount++;
|
||||||
|
|
||||||
|
reg.ymin = rcMin(reg.ymin, s.y);
|
||||||
|
reg.ymax = rcMax(reg.ymax, s.y);
|
||||||
|
|
||||||
|
// Collect all region layers.
|
||||||
|
lregs.push(ri);
|
||||||
|
|
||||||
|
// Update neighbours
|
||||||
|
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*w].index + rcGetCon(s, dir);
|
||||||
|
const unsigned short rai = srcReg[ai];
|
||||||
|
if (rai > 0 && rai < nreg && rai != ri)
|
||||||
|
addUniqueConnection(reg, rai);
|
||||||
|
if (rai & RC_BORDER_REG)
|
||||||
|
reg.connectsToBorder = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update overlapping regions.
|
||||||
|
for (int i = 0; i < lregs.size()-1; ++i)
|
||||||
|
{
|
||||||
|
for (int j = i+1; j < lregs.size(); ++j)
|
||||||
|
{
|
||||||
|
if (lregs[i] != lregs[j])
|
||||||
|
{
|
||||||
|
rcRegion& ri = regions[lregs[i]];
|
||||||
|
rcRegion& rj = regions[lregs[j]];
|
||||||
|
addUniqueFloorRegion(ri, lregs[j]);
|
||||||
|
addUniqueFloorRegion(rj, lregs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create 2D layers from regions.
|
||||||
|
unsigned short layerId = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < nreg; ++i)
|
||||||
|
regions[i].id = 0;
|
||||||
|
|
||||||
|
// Merge montone regions to create non-overlapping areas.
|
||||||
|
rcIntArray stack(32);
|
||||||
|
for (int i = 1; i < nreg; ++i)
|
||||||
|
{
|
||||||
|
rcRegion& root = regions[i];
|
||||||
|
// Skip already visited.
|
||||||
|
if (root.id != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Start search.
|
||||||
|
root.id = layerId;
|
||||||
|
|
||||||
|
stack.resize(0);
|
||||||
|
stack.push(i);
|
||||||
|
|
||||||
|
while (stack.size() > 0)
|
||||||
|
{
|
||||||
|
// Pop front
|
||||||
|
rcRegion& reg = regions[stack[0]];
|
||||||
|
for (int j = 0; j < stack.size()-1; ++j)
|
||||||
|
stack[j] = stack[j+1];
|
||||||
|
stack.resize(stack.size()-1);
|
||||||
|
|
||||||
|
const int ncons = (int)reg.connections.size();
|
||||||
|
for (int j = 0; j < ncons; ++j)
|
||||||
|
{
|
||||||
|
const int nei = reg.connections[j];
|
||||||
|
rcRegion& regn = regions[nei];
|
||||||
|
// Skip already visited.
|
||||||
|
if (regn.id != 0)
|
||||||
|
continue;
|
||||||
|
// Skip if the neighbour is overlapping root region.
|
||||||
|
bool overlap = false;
|
||||||
|
for (int k = 0; k < root.floors.size(); k++)
|
||||||
|
{
|
||||||
|
if (root.floors[k] == nei)
|
||||||
|
{
|
||||||
|
overlap = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (overlap)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Deepen
|
||||||
|
stack.push(nei);
|
||||||
|
|
||||||
|
// Mark layer id
|
||||||
|
regn.id = layerId;
|
||||||
|
// Merge current layers to root.
|
||||||
|
for (int k = 0; k < regn.floors.size(); ++k)
|
||||||
|
addUniqueFloorRegion(root, regn.floors[k]);
|
||||||
|
root.ymin = rcMin(root.ymin, regn.ymin);
|
||||||
|
root.ymax = rcMax(root.ymax, regn.ymax);
|
||||||
|
root.spanCount += regn.spanCount;
|
||||||
|
regn.spanCount = 0;
|
||||||
|
root.connectsToBorder = root.connectsToBorder || regn.connectsToBorder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layerId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove small regions
|
||||||
|
for (int i = 0; i < nreg; ++i)
|
||||||
|
{
|
||||||
|
if (regions[i].spanCount > 0 && regions[i].spanCount < minRegionArea && !regions[i].connectsToBorder)
|
||||||
|
{
|
||||||
|
unsigned short reg = regions[i].id;
|
||||||
|
for (int j = 0; j < nreg; ++j)
|
||||||
|
if (regions[j].id == reg)
|
||||||
|
regions[j].id = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compress region Ids.
|
||||||
|
for (int i = 0; i < nreg; ++i)
|
||||||
|
{
|
||||||
|
regions[i].remap = false;
|
||||||
|
if (regions[i].id == 0) continue; // Skip nil regions.
|
||||||
|
if (regions[i].id & RC_BORDER_REG) continue; // Skip external regions.
|
||||||
|
regions[i].remap = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short regIdGen = 0;
|
||||||
|
for (int i = 0; i < nreg; ++i)
|
||||||
|
{
|
||||||
|
if (!regions[i].remap)
|
||||||
|
continue;
|
||||||
|
unsigned short oldId = regions[i].id;
|
||||||
|
unsigned short newId = ++regIdGen;
|
||||||
|
for (int j = i; j < nreg; ++j)
|
||||||
|
{
|
||||||
|
if (regions[j].id == oldId)
|
||||||
|
{
|
||||||
|
regions[j].id = newId;
|
||||||
|
regions[j].remap = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maxRegionId = regIdGen;
|
||||||
|
|
||||||
|
// Remap regions.
|
||||||
|
for (int i = 0; i < chf.spanCount; ++i)
|
||||||
|
{
|
||||||
|
if ((srcReg[i] & RC_BORDER_REG) == 0)
|
||||||
|
srcReg[i] = regions[srcReg[i]].id;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < nreg; ++i)
|
for (int i = 0; i < nreg; ++i)
|
||||||
regions[i].~rcRegion();
|
regions[i].~rcRegion();
|
||||||
rcFree(regions);
|
rcFree(regions);
|
||||||
|
|
@ -938,6 +1242,17 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// This is usually the second to the last step in creating a fully built
|
||||||
|
/// compact heightfield. This step is required before regions are built
|
||||||
|
/// using #rcBuildRegions or #rcBuildRegionsMonotone.
|
||||||
|
///
|
||||||
|
/// After this step, the distance data is available via the rcCompactHeightfield::maxDistance
|
||||||
|
/// and rcCompactHeightfield::dist fields.
|
||||||
|
///
|
||||||
|
/// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone
|
||||||
bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf)
|
bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf)
|
||||||
{
|
{
|
||||||
rcAssert(ctx);
|
rcAssert(ctx);
|
||||||
|
|
@ -1020,6 +1335,25 @@ struct rcSweepSpan
|
||||||
unsigned short nei; // neighbour id
|
unsigned short nei; // neighbour id
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour.
|
||||||
|
/// Contours will form simple polygons.
|
||||||
|
///
|
||||||
|
/// If multiple regions form an area that is smaller than @p minRegionArea, then all spans will be
|
||||||
|
/// re-assigned to the zero (null) region.
|
||||||
|
///
|
||||||
|
/// Partitioning can result in smaller than necessary regions. @p mergeRegionArea helps
|
||||||
|
/// reduce unecessarily small regions.
|
||||||
|
///
|
||||||
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
|
///
|
||||||
|
/// The region data will be available via the rcCompactHeightfield::maxRegions
|
||||||
|
/// and rcCompactSpan::reg fields.
|
||||||
|
///
|
||||||
|
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
||||||
|
///
|
||||||
|
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
|
||||||
bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
|
bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
const int borderSize, const int minRegionArea, const int mergeRegionArea)
|
const int borderSize, const int minRegionArea, const int mergeRegionArea)
|
||||||
{
|
{
|
||||||
|
|
@ -1059,6 +1393,8 @@ bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
|
paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
|
||||||
paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++;
|
paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++;
|
||||||
paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++;
|
paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++;
|
||||||
|
|
||||||
|
chf.borderSize = borderSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcIntArray prev(256);
|
rcIntArray prev(256);
|
||||||
|
|
@ -1152,13 +1488,17 @@ bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
||||||
|
|
||||||
// Filter out small regions.
|
// Merge regions and filter out small regions.
|
||||||
|
rcIntArray overlaps;
|
||||||
chf.maxRegions = id;
|
chf.maxRegions = id;
|
||||||
if (!filterSmallRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg))
|
if (!mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg, overlaps))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Monotone partitioning does not generate overlapping regions.
|
||||||
|
|
||||||
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
||||||
|
|
||||||
// Store the result out.
|
// Store the result out.
|
||||||
|
|
@ -1170,6 +1510,25 @@ bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour.
|
||||||
|
/// Contours will form simple polygons.
|
||||||
|
///
|
||||||
|
/// If multiple regions form an area that is smaller than @p minRegionArea, then all spans will be
|
||||||
|
/// re-assigned to the zero (null) region.
|
||||||
|
///
|
||||||
|
/// Watershed partitioning can result in smaller than necessary regions, especially in diagonal corridors.
|
||||||
|
/// @p mergeRegionArea helps reduce unecessarily small regions.
|
||||||
|
///
|
||||||
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
|
///
|
||||||
|
/// The region data will be available via the rcCompactHeightfield::maxRegions
|
||||||
|
/// and rcCompactSpan::reg fields.
|
||||||
|
///
|
||||||
|
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
||||||
|
///
|
||||||
|
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
|
||||||
bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
const int borderSize, const int minRegionArea, const int mergeRegionArea)
|
const int borderSize, const int minRegionArea, const int mergeRegionArea)
|
||||||
{
|
{
|
||||||
|
|
@ -1189,6 +1548,12 @@ 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);
|
||||||
|
|
||||||
|
|
@ -1209,20 +1574,39 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
// const int expandIters = 4 + walkableRadius * 2;
|
// const int expandIters = 4 + walkableRadius * 2;
|
||||||
const int expandIters = 8;
|
const int expandIters = 8;
|
||||||
|
|
||||||
// Mark border regions.
|
if (borderSize > 0)
|
||||||
paintRectRegion(0, borderSize, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
{
|
||||||
paintRectRegion(w-borderSize, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
// Make sure border will not overflow.
|
||||||
paintRectRegion(0, w, 0, borderSize, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
const int bw = rcMin(w, borderSize);
|
||||||
paintRectRegion(0, w, h-borderSize, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
const int bh = rcMin(h, borderSize);
|
||||||
|
// Paint regions
|
||||||
|
paintRectRegion(0, bw, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
||||||
|
paintRectRegion(w-bw, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
||||||
|
paintRectRegion(0, w, 0, bh, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
||||||
|
paintRectRegion(0, w, h-bh, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
@ -1233,28 +1617,23 @@ 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))
|
if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
|
||||||
regionId++;
|
regionId++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FLOOD);
|
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FLOOD);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
@ -1264,11 +1643,18 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
|
|
||||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
||||||
|
|
||||||
// Filter out small regions.
|
// Merge regions and filter out smalle regions.
|
||||||
|
rcIntArray overlaps;
|
||||||
chf.maxRegions = regionId;
|
chf.maxRegions = regionId;
|
||||||
if (!filterSmallRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg))
|
if (!mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg, overlaps))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// If overlapping regions were found during merging, split those regions.
|
||||||
|
if (overlaps.size() > 0)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildRegions: %d overlapping regions.", overlaps.size());
|
||||||
|
}
|
||||||
|
|
||||||
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
||||||
|
|
||||||
// Write the result out.
|
// Write the result out.
|
||||||
|
|
@ -1281,3 +1667,157 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool rcBuildLayerRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||||
|
const int borderSize, const int minRegionArea)
|
||||||
|
{
|
||||||
|
rcAssert(ctx);
|
||||||
|
|
||||||
|
ctx->startTimer(RC_TIMER_BUILD_REGIONS);
|
||||||
|
|
||||||
|
const int w = chf.width;
|
||||||
|
const int h = chf.height;
|
||||||
|
unsigned short id = 1;
|
||||||
|
|
||||||
|
rcScopedDelete<unsigned short> srcReg = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
|
||||||
|
if (!srcReg)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(srcReg,0,sizeof(unsigned short)*chf.spanCount);
|
||||||
|
|
||||||
|
const int nsweeps = rcMax(chf.width,chf.height);
|
||||||
|
rcScopedDelete<rcSweepSpan> sweeps = (rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP);
|
||||||
|
if (!sweeps)
|
||||||
|
{
|
||||||
|
ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Mark border regions.
|
||||||
|
if (borderSize > 0)
|
||||||
|
{
|
||||||
|
// Make sure border will not overflow.
|
||||||
|
const int bw = rcMin(w, borderSize);
|
||||||
|
const int bh = rcMin(h, borderSize);
|
||||||
|
// Paint regions
|
||||||
|
paintRectRegion(0, bw, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
|
||||||
|
paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
|
||||||
|
paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++;
|
||||||
|
paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++;
|
||||||
|
|
||||||
|
chf.borderSize = borderSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
rcIntArray prev(256);
|
||||||
|
|
||||||
|
// Sweep one line at a time.
|
||||||
|
for (int y = borderSize; y < h-borderSize; ++y)
|
||||||
|
{
|
||||||
|
// Collect spans from this row.
|
||||||
|
prev.resize(id+1);
|
||||||
|
memset(&prev[0],0,sizeof(int)*id);
|
||||||
|
unsigned short rid = 1;
|
||||||
|
|
||||||
|
for (int x = borderSize; x < w-borderSize; ++x)
|
||||||
|
{
|
||||||
|
const rcCompactCell& c = chf.cells[x+y*w];
|
||||||
|
|
||||||
|
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||||
|
{
|
||||||
|
const rcCompactSpan& s = chf.spans[i];
|
||||||
|
if (chf.areas[i] == RC_NULL_AREA) continue;
|
||||||
|
|
||||||
|
// -x
|
||||||
|
unsigned short previd = 0;
|
||||||
|
if (rcGetCon(s, 0) != RC_NOT_CONNECTED)
|
||||||
|
{
|
||||||
|
const int ax = x + rcGetDirOffsetX(0);
|
||||||
|
const int ay = y + rcGetDirOffsetY(0);
|
||||||
|
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0);
|
||||||
|
if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
|
||||||
|
previd = srcReg[ai];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!previd)
|
||||||
|
{
|
||||||
|
previd = rid++;
|
||||||
|
sweeps[previd].rid = previd;
|
||||||
|
sweeps[previd].ns = 0;
|
||||||
|
sweeps[previd].nei = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -y
|
||||||
|
if (rcGetCon(s,3) != RC_NOT_CONNECTED)
|
||||||
|
{
|
||||||
|
const int ax = x + rcGetDirOffsetX(3);
|
||||||
|
const int ay = y + rcGetDirOffsetY(3);
|
||||||
|
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3);
|
||||||
|
if (srcReg[ai] && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
|
||||||
|
{
|
||||||
|
unsigned short nr = srcReg[ai];
|
||||||
|
if (!sweeps[previd].nei || sweeps[previd].nei == nr)
|
||||||
|
{
|
||||||
|
sweeps[previd].nei = nr;
|
||||||
|
sweeps[previd].ns++;
|
||||||
|
prev[nr]++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sweeps[previd].nei = RC_NULL_NEI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
srcReg[i] = previd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create unique ID.
|
||||||
|
for (int i = 1; i < rid; ++i)
|
||||||
|
{
|
||||||
|
if (sweeps[i].nei != RC_NULL_NEI && sweeps[i].nei != 0 &&
|
||||||
|
prev[sweeps[i].nei] == (int)sweeps[i].ns)
|
||||||
|
{
|
||||||
|
sweeps[i].id = sweeps[i].nei;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sweeps[i].id = id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remap IDs
|
||||||
|
for (int x = borderSize; x < w-borderSize; ++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 (srcReg[i] > 0 && srcReg[i] < rid)
|
||||||
|
srcReg[i] = sweeps[srcReg[i]].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
||||||
|
|
||||||
|
// Merge monotone regions to layers and remove small regions.
|
||||||
|
rcIntArray overlaps;
|
||||||
|
chf.maxRegions = id;
|
||||||
|
if (!mergeAndFilterLayerRegions(ctx, minRegionArea, chf.maxRegions, chf, srcReg, overlaps))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
||||||
|
|
||||||
|
|
||||||
|
// Store the result out.
|
||||||
|
for (int i = 0; i < chf.spanCount; ++i)
|
||||||
|
chf.spans[i].reg = srcReg[i];
|
||||||
|
|
||||||
|
ctx->stopTimer(RC_TIMER_BUILD_REGIONS);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,19 @@ EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Win32 = Debug|Win32
|
Debug|Win32 = Debug|Win32
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
Release|Win32 = Release|Win32
|
Release|Win32 = Release|Win32
|
||||||
|
Release|x64 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|Win32.ActiveCfg = Debug|Win32
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|Win32.Build.0 = Debug|Win32
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|x64.Build.0 = Debug|x64
|
||||||
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|Win32.ActiveCfg = Release|Win32
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|Win32.Build.0 = Release|Win32
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,19 @@ EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Win32 = Debug|Win32
|
Debug|Win32 = Debug|Win32
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
Release|Win32 = Release|Win32
|
Release|Win32 = Release|Win32
|
||||||
|
Release|x64 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|Win32.ActiveCfg = Debug|Win32
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|Win32.Build.0 = Debug|Win32
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|x64.Build.0 = Debug|x64
|
||||||
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|Win32.ActiveCfg = Release|Win32
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|Win32.Build.0 = Release|Win32
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,26 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 2012
|
# Visual Studio 2013
|
||||||
|
VisualStudioVersion = 12.0.21005.1
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Recast", "VC120\Recast.vcxproj", "{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Recast", "VC120\Recast.vcxproj", "{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Win32 = Debug|Win32
|
Debug|Win32 = Debug|Win32
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
Release|Win32 = Release|Win32
|
Release|Win32 = Release|Win32
|
||||||
|
Release|x64 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|Win32.ActiveCfg = Debug|Win32
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|Win32.Build.0 = Debug|Win32
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Debug|x64.Build.0 = Debug|x64
|
||||||
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|Win32.ActiveCfg = Release|Win32
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|Win32.Build.0 = Release|Win32
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,18 @@
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Release|Win32">
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}</ProjectGuid>
|
<ProjectGuid>{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}</ProjectGuid>
|
||||||
|
|
@ -20,38 +28,76 @@
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
<ImportGroup Label="ExtensionSettings">
|
<ImportGroup Label="ExtensionSettings">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
||||||
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
||||||
|
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
|
@ -64,7 +110,23 @@
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,22 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Release|Win32">
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}</ProjectGuid>
|
<ProjectGuid>{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}</ProjectGuid>
|
||||||
|
|
@ -19,14 +27,27 @@
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
<PlatformToolset>v120</PlatformToolset>
|
<PlatformToolset>v110</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v110</PlatformToolset>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
<PlatformToolset>v120</PlatformToolset>
|
<PlatformToolset>v110</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v110</PlatformToolset>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
<ImportGroup Label="ExtensionSettings">
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
|
@ -34,26 +55,53 @@
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
||||||
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
||||||
|
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
|
@ -66,7 +114,23 @@
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,18 @@
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Release|Win32">
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}</ProjectGuid>
|
<ProjectGuid>{00B9DC66-96A6-465D-A6C1-5DFF94E48A64}</ProjectGuid>
|
||||||
|
|
@ -21,6 +29,12 @@
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
<PlatformToolset>v120</PlatformToolset>
|
<PlatformToolset>v120</PlatformToolset>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v120</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
|
@ -28,32 +42,66 @@
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
<PlatformToolset>v120</PlatformToolset>
|
<PlatformToolset>v120</PlatformToolset>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v120</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
<ImportGroup Label="ExtensionSettings">
|
<ImportGroup Label="ExtensionSettings">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
||||||
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<OutDir>$(ProjectDir)\..\..\..\..\lib\$(Platform)_$(Configuration)\</OutDir>
|
||||||
|
<IntDir>.\$(ProjectName)__$(Platform)_$(Configuration)\</IntDir>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;DEBUG;_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
|
@ -66,7 +114,23 @@
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_MBCS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
|
|
||||||
!.gitignore
|
|
||||||
*
|
|
||||||
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,28 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>English</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>Recast</string>
|
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string>Icon.icns</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>com.yourcompany.Recast</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>Recast</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
<key>NSMainNibFile</key>
|
|
||||||
<string>MainMenu</string>
|
|
||||||
<key>NSPrincipalClass</key>
|
|
||||||
<string>NSApplication</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
Binary file not shown.
|
|
@ -1 +0,0 @@
|
||||||
APPL????
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,15 +0,0 @@
|
||||||
s Solo Mesh Simple
|
|
||||||
f movement.obj
|
|
||||||
pf -100.539185 -1.000000 54.028996 62.582016 15.757828 52.842243 0x3 0x0
|
|
||||||
pf -100.539185 -1.000000 54.028996 -1.259964 -1.000000 50.116970 0x3 0x0
|
|
||||||
pf -100.539185 -1.000000 54.028996 1.598934 -1.000000 23.528656 0x3 0x0
|
|
||||||
pf -100.539185 -1.000000 54.028996 3.652847 -1.000000 -5.022881 0x3 0x0
|
|
||||||
pf -100.539185 -1.000000 54.028996 -39.182816 8.999985 -24.697731 0x3 0x0
|
|
||||||
pf -100.539185 -1.000000 54.028996 -66.847992 -1.000000 -28.908646 0x3 0x0
|
|
||||||
pf -100.539185 -1.000000 54.028996 -90.966019 -1.000000 -3.219864 0x3 0x0
|
|
||||||
pf -43.394421 -1.000000 13.312424 -90.966019 -1.000000 -3.219864 0x3 0x0
|
|
||||||
pf -43.394421 -1.000000 13.312424 -36.447182 3.999992 -25.008087 0x3 0x0
|
|
||||||
pf -43.394421 -1.000000 13.312424 26.394167 15.757812 -13.491264 0x3 0x0
|
|
||||||
pf -43.394421 -1.000000 13.312424 -4.140746 6.944923 4.888435 0x3 0x0
|
|
||||||
pf -43.394421 -1.000000 13.312424 -73.532791 -1.062469 23.137051 0x3 0x0
|
|
||||||
pf -43.394421 -1.000000 13.312424 -72.902054 7.996834 15.076473 0x3 0x0
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
s Solo Mesh Simple
|
|
||||||
f nav_test.obj
|
|
||||||
pf 18.138550 -2.370003 -21.319118 -19.206181 -2.369133 24.802742 0x3 0x0
|
|
||||||
pf 18.252758 -2.368240 -7.000238 -19.206181 -2.369133 24.802742 0x3 0x0
|
|
||||||
pf 18.252758 -2.368240 -7.000238 -22.759071 -2.369453 2.003946 0x3 0x0
|
|
||||||
pf 18.252758 -2.368240 -7.000238 -24.483898 -2.369728 -6.778278 0x3 0x0
|
|
||||||
pf 18.252758 -2.368240 -7.000238 -24.068850 -2.370285 -18.879251 0x3 0x0
|
|
||||||
pf 18.252758 -2.368240 -7.000238 12.124170 -2.369637 -21.222471 0x3 0x0
|
|
||||||
pf 10.830146 -2.366791 19.002508 12.124170 -2.369637 -21.222471 0x3 0x0
|
|
||||||
pf 10.830146 -2.366791 19.002508 -7.146484 -2.368736 -16.031403 0x3 0x0
|
|
||||||
pf 10.830146 -2.366791 19.002508 -21.615391 -2.368706 -3.264029 0x3 0x0
|
|
||||||
pf 10.830146 -2.366791 19.002508 -22.651268 -2.369354 1.053217 0x3 0x0
|
|
||||||
pf 10.830146 -2.366791 19.002508 19.181122 -2.368134 3.011776 0x3 0x0
|
|
||||||
pf 10.830146 -2.366791 19.002508 19.041592 -2.368713 -7.404587 0x3 0x0
|
|
||||||
pf 6.054083 -2.365402 3.330421 19.041592 -2.368713 -7.404587 0x3 0x0
|
|
||||||
pf 6.054083 -2.365402 3.330421 21.846087 -2.368568 17.918859 0x3 0x0
|
|
||||||
pf 6.054083 -2.365402 3.330421 0.967449 -2.368439 25.767756 0x3 0x0
|
|
||||||
pf 6.054083 -2.365402 3.330421 -17.518076 -2.368477 26.569633 0x3 0x0
|
|
||||||
pf 6.054083 -2.365402 3.330421 -22.141787 -2.369209 2.440046 0x3 0x0
|
|
||||||
pf 6.054083 -2.365402 3.330421 -23.296972 -2.369797 -17.411043 0x3 0x0
|
|
||||||
pf 6.054083 -2.365402 3.330421 -1.564062 -2.369926 -20.452827 0x3 0x0
|
|
||||||
pf 6.054083 -2.365402 3.330421 16.905643 -2.370193 -21.811655 0x3 0x0
|
|
||||||
pf 6.054083 -2.365402 3.330421 19.289761 -2.368813 -6.954918 0x3 0x0
|
|
||||||
Binary file not shown.
|
|
@ -1,7 +0,0 @@
|
||||||
OBJECTS = $(patsubst $(NAME)/Source/%.cpp,$(OBJ)/%.o,$(wildcard $(NAME)/Source/*.cpp))
|
|
||||||
CPPFLAGS += -I$(NAME)/Include
|
|
||||||
|
|
||||||
$(OBJ)/%.o: $(NAME)/Source/%.cpp
|
|
||||||
c++ $(CPPFLAGS) -c -o $@ $<
|
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
NAME = DebugUtils
|
|
||||||
|
|
||||||
SOURCES = \
|
|
||||||
DebugDraw.cpp \
|
|
||||||
DetourDebugDraw.cpp \
|
|
||||||
RecastDebugDraw.cpp \
|
|
||||||
RecastDump.cpp
|
|
||||||
|
|
||||||
HEADERS = \
|
|
||||||
DebugDraw.h \
|
|
||||||
DetourDebugDraw.h \
|
|
||||||
RecastDebugDraw.h \
|
|
||||||
RecastDump.h
|
|
||||||
|
|
||||||
CPPFLAGS = \
|
|
||||||
-I Detour/Include \
|
|
||||||
-I Recast/Include
|
|
||||||
|
|
||||||
include $(BUILD)/HelperLibrary.mk
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
NAME = Detour
|
|
||||||
|
|
||||||
SOURCES = \
|
|
||||||
DetourAlloc.cpp \
|
|
||||||
DetourCommon.cpp \
|
|
||||||
DetourNavMesh.cpp \
|
|
||||||
DetourNavMeshBuilder.cpp \
|
|
||||||
DetourNavMeshQuery.cpp \
|
|
||||||
DetourNode.cpp \
|
|
||||||
DetourObstacleAvoidance.cpp
|
|
||||||
|
|
||||||
HEADERS = \
|
|
||||||
DetourAlloc.h \
|
|
||||||
DetourAssert.h \
|
|
||||||
DetourCommon.h \
|
|
||||||
DetourNavMesh.h \
|
|
||||||
DetourNavMeshBuilder.h \
|
|
||||||
DetourNavMeshQuery.h \
|
|
||||||
DetourNode.h \
|
|
||||||
DetourObstacleAvoidance.h
|
|
||||||
|
|
||||||
include $(BUILD)/Library.mk
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
include $(BUILD)/Common.mk
|
|
||||||
|
|
||||||
$(BIN)/$(NAME).a: $(OBJECTS)
|
|
||||||
ar -q $@ $(OBJECTS)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(BIN)/$(NAME).a $(OBJECTS)
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
include $(BUILD)/Common.mk
|
|
||||||
|
|
||||||
CPPFLAGS += -fPIC
|
|
||||||
LDFLAGS += -shared
|
|
||||||
|
|
||||||
$(BIN)/lib$(NAME).so: $(OBJECTS)
|
|
||||||
c++ $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(BIN)/lib$(NAME).so $(OBJECTS)
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
include $(BUILD)/Common.mk
|
|
||||||
|
|
||||||
$(BIN)/$(NAME): $(OBJECTS)
|
|
||||||
c++ $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(BIN)/$(NAME).a $(OBJECTS)
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue