Merge branch 'master' of https://github.com/memononen/recastnavigation
This commit is contained in:
commit
3cb87f2432
8
.gitignore
vendored
8
.gitignore
vendored
@ -14,6 +14,9 @@ RecastDemo/Bin/RecastDemo
|
||||
# Build directory
|
||||
RecastDemo/Build
|
||||
|
||||
# Ignore some meshes based on name
|
||||
RecastDemo/Bin/Meshes/_*
|
||||
|
||||
## Logs and databases #
|
||||
*.log
|
||||
*.sql
|
||||
@ -27,9 +30,14 @@ RecastDemo/Build
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
## xcode specific
|
||||
*xcuserdata*
|
||||
|
||||
## SDL contrib
|
||||
RecastDemo/Contrib/SDL/*
|
||||
|
||||
## Generated doc files
|
||||
Docs/html
|
||||
|
@ -32,6 +32,11 @@ 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
|
||||
|
@ -22,16 +22,39 @@
|
||||
#include "DetourAlloc.h"
|
||||
#include "DetourStatus.h"
|
||||
|
||||
// Undefine (or define in a build cofnig) the following line to use 64bit polyref.
|
||||
// Generally not needed, useful for very large worlds.
|
||||
// Note: tiles build using 32bit refs are not compatible with 64bit refs!
|
||||
//#define DT_POLYREF64 1
|
||||
|
||||
#ifdef DT_POLYREF64
|
||||
// TODO: figure out a multiplatform version of uint64_t
|
||||
// - maybe: https://code.google.com/p/msinttypes/
|
||||
// - or: http://www.azillionmonkeys.com/qed/pstdint.h
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
// Note: If you want to use 64-bit refs, change the types of both dtPolyRef & dtTileRef.
|
||||
// It is also recommended that you change dtHashRef() to a proper 64-bit hash.
|
||||
|
||||
/// A handle to a polygon within a navigation mesh tile.
|
||||
/// @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
|
||||
|
||||
/// A handle to a tile within a navigation mesh.
|
||||
/// @ingroup detour
|
||||
#ifdef DT_POLYREF64
|
||||
typedef uint64_t dtTileRef;
|
||||
#else
|
||||
typedef unsigned int dtTileRef;
|
||||
#endif
|
||||
|
||||
/// The maximum number of vertices per navigation polygon.
|
||||
/// @ingroup detour
|
||||
@ -469,7 +492,11 @@ public:
|
||||
/// @param[in] ip The index of the polygon within the tile.
|
||||
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;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Decodes a standard polygon reference.
|
||||
@ -481,12 +508,21 @@ public:
|
||||
/// @see #encodePolyId
|
||||
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 tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
||||
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
||||
salt = (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
||||
it = (unsigned int)((ref >> m_polyBits) & tileMask);
|
||||
ip = (unsigned int)(ref & polyMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Extracts a tile's salt value from the specified polygon reference.
|
||||
@ -495,8 +531,13 @@ public:
|
||||
/// @see #encodePolyId
|
||||
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;
|
||||
return (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Extracts the tile's index from the specified polygon reference.
|
||||
@ -505,8 +546,13 @@ public:
|
||||
/// @see #encodePolyId
|
||||
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;
|
||||
return (unsigned int)((ref >> m_polyBits) & tileMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Extracts the polygon's index (within its tile) from the specified polygon reference.
|
||||
@ -515,8 +561,13 @@ public:
|
||||
/// @see #encodePolyId
|
||||
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;
|
||||
return (unsigned int)(ref & polyMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @}
|
||||
@ -562,8 +613,7 @@ private:
|
||||
dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center,
|
||||
const float* extents, float* nearestPt) const;
|
||||
/// Returns closest point on polygon.
|
||||
void closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip,
|
||||
const float* pos, float* closest) const;
|
||||
void closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
|
||||
|
||||
dtNavMeshParams m_params; ///< Current initialization params. TODO: do not store this info twice.
|
||||
float m_orig[3]; ///< Origin of the tile (0,0)
|
||||
@ -576,9 +626,11 @@ private:
|
||||
dtMeshTile* m_nextFree; ///< Freelist of tiles.
|
||||
dtMeshTile* m_tiles; ///< List of tiles.
|
||||
|
||||
#ifndef DT_POLYREF64
|
||||
unsigned int m_saltBits; ///< Number of salt bits in the tile ID.
|
||||
unsigned int m_tileBits; ///< Number of tile bits in the tile ID.
|
||||
unsigned int m_polyBits; ///< Number of poly bits in the tile ID.
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Allocates a navigation mesh object using the Detour allocator.
|
||||
|
@ -200,8 +200,8 @@ public:
|
||||
|
||||
/// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest
|
||||
/// polygon on the existing path that was visited during the search.
|
||||
/// @param[out] existing An array of polygon references for the existing path.
|
||||
/// @param[out] existingSize The number of polygon in the @p existing array.
|
||||
/// @param[in] existing An array of polygon references for the existing path.
|
||||
/// @param[in] existingSize The number of polygon in the @p existing array.
|
||||
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||
/// [(polyRef) * @p pathCount]
|
||||
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||
@ -378,8 +378,9 @@ public:
|
||||
/// @param[in] ref The reference id of the polygon.
|
||||
/// @param[in] 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) const;
|
||||
dtStatus closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
|
||||
|
||||
/// Returns a point on the boundary closest to the source point if the source point is outside the
|
||||
/// polygon's xz-bounds.
|
||||
@ -428,11 +429,6 @@ private:
|
||||
/// Queries polygons within a tile.
|
||||
int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax, const dtQueryFilter* filter,
|
||||
dtPolyRef* polys, const int maxPolys) const;
|
||||
/// Find nearest polygon within a tile.
|
||||
dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center, const float* extents,
|
||||
const dtQueryFilter* filter, float* nearestPt) const;
|
||||
/// Returns closest point on polygon.
|
||||
void closestPointOnPolyInTile(const dtMeshTile* tile, const dtPoly* poly, const float* pos, float* closest) const;
|
||||
|
||||
/// Returns portal points between two polygons.
|
||||
dtStatus getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right,
|
||||
|
@ -193,11 +193,13 @@ dtNavMesh::dtNavMesh() :
|
||||
m_tileLutMask(0),
|
||||
m_posLookup(0),
|
||||
m_nextFree(0),
|
||||
m_tiles(0),
|
||||
m_saltBits(0),
|
||||
m_tileBits(0),
|
||||
m_polyBits(0)
|
||||
m_tiles(0)
|
||||
{
|
||||
#ifndef DT_POLYREF64
|
||||
m_saltBits = 0;
|
||||
m_tileBits = 0;
|
||||
m_polyBits = 0;
|
||||
#endif
|
||||
memset(&m_params, 0, sizeof(dtNavMeshParams));
|
||||
m_orig[0] = 0;
|
||||
m_orig[1] = 0;
|
||||
@ -249,12 +251,15 @@ dtStatus dtNavMesh::init(const dtNavMeshParams* params)
|
||||
}
|
||||
|
||||
// Init ID generator values.
|
||||
#ifndef DT_POLYREF64
|
||||
m_tileBits = dtIlog2(dtNextPow2((unsigned int)params->maxTiles));
|
||||
m_polyBits = dtIlog2(dtNextPow2((unsigned int)params->maxPolys));
|
||||
// Only allow 31 salt bits, since the salt mask is calculated using 32bit uint and it will overflow.
|
||||
m_saltBits = dtMin((unsigned int)31, 32 - m_tileBits - m_polyBits);
|
||||
|
||||
if (m_saltBits < 10)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
#endif
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
@ -612,10 +617,12 @@ void dtNavMesh::baseOffMeshLinks(dtMeshTile* tile)
|
||||
}
|
||||
}
|
||||
|
||||
void dtNavMesh::closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip,
|
||||
const float* pos, float* closest) const
|
||||
void dtNavMesh::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const
|
||||
{
|
||||
const dtPoly* poly = &tile->polys[ip];
|
||||
const dtMeshTile* tile = 0;
|
||||
const dtPoly* poly = 0;
|
||||
getTileAndPolyByRefUnsafe(ref, &tile, &poly);
|
||||
|
||||
// Off-mesh connections don't have detail polygons.
|
||||
if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||
{
|
||||
@ -625,9 +632,12 @@ void dtNavMesh::closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip
|
||||
const float d1 = dtVdist(pos, v1);
|
||||
const float u = d0 / (d0+d1);
|
||||
dtVlerp(closest, v0, v1, u);
|
||||
if (posOverPoly)
|
||||
*posOverPoly = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned int ip = (unsigned int)(poly - tile->polys);
|
||||
const dtPolyDetail* pd = &tile->detailMeshes[ip];
|
||||
|
||||
// Clamp point to be inside the polygon.
|
||||
@ -655,6 +665,14 @@ void dtNavMesh::closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip
|
||||
const float* va = &verts[imin*3];
|
||||
const float* vb = &verts[((imin+1)%nv)*3];
|
||||
dtVlerp(closest, va, vb, edget[imin]);
|
||||
|
||||
if (posOverPoly)
|
||||
*posOverPoly = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (posOverPoly)
|
||||
*posOverPoly = true;
|
||||
}
|
||||
|
||||
// Find height at the location.
|
||||
@ -697,12 +715,27 @@ dtPolyRef dtNavMesh::findNearestPolyInTile(const dtMeshTile* tile,
|
||||
{
|
||||
dtPolyRef ref = polys[i];
|
||||
float closestPtPoly[3];
|
||||
closestPointOnPolyInTile(tile, decodePolyIdPoly(ref), center, closestPtPoly);
|
||||
float d = dtVdistSqr(center, closestPtPoly);
|
||||
float diff[3];
|
||||
bool posOverPoly = false;
|
||||
float d = 0;
|
||||
closestPointOnPoly(ref, center, closestPtPoly, &posOverPoly);
|
||||
|
||||
// If a point is directly over a polygon and closer than
|
||||
// climb height, favor that instead of straight line nearest point.
|
||||
dtVsub(diff, center, closestPtPoly);
|
||||
if (posOverPoly)
|
||||
{
|
||||
d = dtAbs(diff[1]) - tile->header->walkableClimb;
|
||||
d = d > 0 ? d*d : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
d = dtVlenSqr(diff);
|
||||
}
|
||||
|
||||
if (d < nearestDistanceSqr)
|
||||
{
|
||||
if (nearestPt)
|
||||
dtVcopy(nearestPt, closestPtPoly);
|
||||
dtVcopy(nearestPt, closestPtPoly);
|
||||
nearestDistanceSqr = d;
|
||||
nearest = ref;
|
||||
}
|
||||
@ -1209,7 +1242,11 @@ dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSiz
|
||||
tile->offMeshCons = 0;
|
||||
|
||||
// Update salt, salt should never be zero.
|
||||
#ifdef DT_POLYREF64
|
||||
tile->salt = (tile->salt+1) & ((1<<DT_SALT_BITS)-1);
|
||||
#else
|
||||
tile->salt = (tile->salt+1) & ((1<<m_saltBits)-1);
|
||||
#endif
|
||||
if (tile->salt == 0)
|
||||
tile->salt++;
|
||||
|
||||
|
@ -501,7 +501,7 @@ dtStatus dtNavMeshQuery::findRandomPointAroundCircle(dtPolyRef startRef, const f
|
||||
///
|
||||
/// See closestPointOnPolyBoundary() for a limited but faster option.
|
||||
///
|
||||
dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest) const
|
||||
dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const
|
||||
{
|
||||
dtAssert(m_nav);
|
||||
const dtMeshTile* tile = 0;
|
||||
@ -511,14 +511,6 @@ dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, flo
|
||||
if (!tile)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
|
||||
closestPointOnPolyInTile(tile, poly, pos, closest);
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
void dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPoly* poly,
|
||||
const float* pos, float* closest) const
|
||||
{
|
||||
// Off-mesh connections don't have detail polygons.
|
||||
if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||
{
|
||||
@ -528,7 +520,9 @@ void dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPo
|
||||
const float d1 = dtVdist(pos, v1);
|
||||
const float u = d0 / (d0+d1);
|
||||
dtVlerp(closest, v0, v1, u);
|
||||
return;
|
||||
if (posOverPoly)
|
||||
*posOverPoly = false;
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
const unsigned int ip = (unsigned int)(poly - tile->polys);
|
||||
@ -559,6 +553,14 @@ void dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPo
|
||||
const float* va = &verts[imin*3];
|
||||
const float* vb = &verts[((imin+1)%nv)*3];
|
||||
dtVlerp(closest, va, vb, edget[imin]);
|
||||
|
||||
if (posOverPoly)
|
||||
*posOverPoly = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (posOverPoly)
|
||||
*posOverPoly = true;
|
||||
}
|
||||
|
||||
// Find height at the location.
|
||||
@ -581,29 +583,7 @@ void dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPo
|
||||
}
|
||||
}
|
||||
|
||||
/* float closestDistSqr = FLT_MAX;
|
||||
for (int j = 0; j < pd->triCount; ++j)
|
||||
{
|
||||
const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4];
|
||||
const float* v[3];
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
if (t[k] < poly->vertCount)
|
||||
v[k] = &tile->verts[poly->verts[t[k]]*3];
|
||||
else
|
||||
v[k] = &tile->detailVerts[(pd->vertBase+(t[k]-poly->vertCount))*3];
|
||||
}
|
||||
|
||||
float pt[3];
|
||||
dtClosestPtPointTriangle(pt, pos, v[0], v[1], v[2]);
|
||||
float d = dtVdistSqr(pos, pt);
|
||||
|
||||
if (d < closestDistSqr)
|
||||
{
|
||||
dtVcopy(closest, pt);
|
||||
closestDistSqr = d;
|
||||
}
|
||||
}*/
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
/// @par
|
||||
@ -682,8 +662,8 @@ dtStatus dtNavMeshQuery::getPolyHeight(dtPolyRef ref, const float* pos, float* h
|
||||
{
|
||||
const float* v0 = &tile->verts[poly->verts[0]*3];
|
||||
const float* v1 = &tile->verts[poly->verts[1]*3];
|
||||
const float d0 = dtVdist(pos, v0);
|
||||
const float d1 = dtVdist(pos, v1);
|
||||
const float d0 = dtVdist2D(pos, v0);
|
||||
const float d1 = dtVdist2D(pos, v1);
|
||||
const float u = d0 / (d0+d1);
|
||||
if (height)
|
||||
*height = v0[1] + (v1[1] - v0[1]) * u;
|
||||
@ -747,8 +727,27 @@ dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* exten
|
||||
{
|
||||
dtPolyRef ref = polys[i];
|
||||
float closestPtPoly[3];
|
||||
closestPointOnPoly(ref, center, closestPtPoly);
|
||||
float d = dtVdistSqr(center, closestPtPoly);
|
||||
float diff[3];
|
||||
bool posOverPoly = false;
|
||||
float d = 0;
|
||||
closestPointOnPoly(ref, center, closestPtPoly, &posOverPoly);
|
||||
|
||||
// If a point is directly over a polygon and closer than
|
||||
// climb height, favor that instead of straight line nearest point.
|
||||
dtVsub(diff, center, closestPtPoly);
|
||||
if (posOverPoly)
|
||||
{
|
||||
const dtMeshTile* tile = 0;
|
||||
const dtPoly* poly = 0;
|
||||
m_nav->getTileAndPolyByRefUnsafe(polys[i], &tile, &poly);
|
||||
d = dtAbs(diff[1]) - tile->header->walkableClimb;
|
||||
d = d > 0 ? d*d : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
d = dtVlenSqr(diff);
|
||||
}
|
||||
|
||||
if (d < nearestDistanceSqr)
|
||||
{
|
||||
if (nearestPt)
|
||||
@ -764,42 +763,6 @@ dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* exten
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtPolyRef dtNavMeshQuery::findNearestPolyInTile(const dtMeshTile* tile, const float* center, const float* extents,
|
||||
const dtQueryFilter* filter, float* nearestPt) const
|
||||
{
|
||||
dtAssert(m_nav);
|
||||
|
||||
float bmin[3], bmax[3];
|
||||
dtVsub(bmin, center, extents);
|
||||
dtVadd(bmax, center, extents);
|
||||
|
||||
// Get nearby polygons from proximity grid.
|
||||
dtPolyRef polys[128];
|
||||
int polyCount = queryPolygonsInTile(tile, bmin, bmax, filter, polys, 128);
|
||||
|
||||
// Find nearest polygon amongst the nearby polygons.
|
||||
dtPolyRef nearest = 0;
|
||||
float nearestDistanceSqr = FLT_MAX;
|
||||
for (int i = 0; i < polyCount; ++i)
|
||||
{
|
||||
dtPolyRef ref = polys[i];
|
||||
const dtPoly* poly = &tile->polys[m_nav->decodePolyIdPoly(ref)];
|
||||
float closestPtPoly[3];
|
||||
closestPointOnPolyInTile(tile, poly, center, closestPtPoly);
|
||||
|
||||
float d = dtVdistSqr(center, closestPtPoly);
|
||||
if (d < nearestDistanceSqr)
|
||||
{
|
||||
if (nearestPt)
|
||||
dtVcopy(nearestPt, closestPtPoly);
|
||||
nearestDistanceSqr = d;
|
||||
nearest = ref;
|
||||
}
|
||||
}
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
||||
int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
||||
const dtQueryFilter* filter,
|
||||
dtPolyRef* polys, const int maxPolys) const
|
||||
|
@ -22,6 +22,19 @@
|
||||
#include "DetourCommon.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef DT_POLYREF64
|
||||
// From Thomas Wang, https://gist.github.com/badboy/6267743
|
||||
inline unsigned int dtHashRef(dtPolyRef a)
|
||||
{
|
||||
a = (~a) + (a << 18); // a = (a << 18) - a - 1;
|
||||
a = a ^ (a >> 31);
|
||||
a = a * 21; // a = (a + (a << 2)) + (a << 4);
|
||||
a = a ^ (a >> 11);
|
||||
a = a + (a << 6);
|
||||
a = a ^ (a >> 22);
|
||||
return (unsigned int)a;
|
||||
}
|
||||
#else
|
||||
inline unsigned int dtHashRef(dtPolyRef a)
|
||||
{
|
||||
a += ~(a<<15);
|
||||
@ -32,6 +45,7 @@ inline unsigned int dtHashRef(dtPolyRef a)
|
||||
a ^= (a>>16);
|
||||
return (unsigned int)a;
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
dtNodePool::dtNodePool(int maxNodes, int hashSize) :
|
||||
|
@ -45,6 +45,12 @@ static const int DT_CROWDAGENT_MAX_CORNERS = 4;
|
||||
/// 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
|
||||
@ -87,6 +93,9 @@ struct dtCrowdAgentParams
|
||||
/// [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;
|
||||
};
|
||||
@ -106,12 +115,15 @@ enum MoveRequestState
|
||||
/// @ingroup crowd
|
||||
struct dtCrowdAgent
|
||||
{
|
||||
/// 1 if the agent is active, or 0 if the agent is in an unused slot in the agent pool.
|
||||
unsigned char active;
|
||||
/// 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;
|
||||
|
||||
@ -161,7 +173,7 @@ struct dtCrowdAgent
|
||||
|
||||
struct dtCrowdAgentAnimation
|
||||
{
|
||||
unsigned char active;
|
||||
bool active;
|
||||
float initPos[3], startPos[3], endPos[3];
|
||||
dtPolyRef polyRef;
|
||||
float t, tmax;
|
||||
@ -206,7 +218,8 @@ class dtCrowd
|
||||
int m_maxPathResult;
|
||||
|
||||
float m_ext[3];
|
||||
dtQueryFilter m_filter;
|
||||
|
||||
dtQueryFilter m_filters[DT_CROWD_MAX_QUERY_FILTER_TYPE];
|
||||
|
||||
float m_maxAgentRadius;
|
||||
|
||||
@ -251,6 +264,11 @@ public:
|
||||
/// @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;
|
||||
@ -301,11 +319,11 @@ public:
|
||||
|
||||
/// Gets the filter used by the crowd.
|
||||
/// @return The filter used by the crowd.
|
||||
const dtQueryFilter* getFilter() const { return &m_filter; }
|
||||
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.
|
||||
dtQueryFilter* getEditableFilter() { return &m_filter; }
|
||||
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)]
|
||||
|
@ -441,14 +441,14 @@ bool dtCrowd::init(const int maxAgents, const float maxAgentRadius, dtNavMesh* n
|
||||
for (int i = 0; i < m_maxAgents; ++i)
|
||||
{
|
||||
new(&m_agents[i]) dtCrowdAgent();
|
||||
m_agents[i].active = 0;
|
||||
m_agents[i].active = false;
|
||||
if (!m_agents[i].corridor.init(m_maxPathResult))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_maxAgents; ++i)
|
||||
{
|
||||
m_agentAnims[i].active = 0;
|
||||
m_agentAnims[i].active = false;
|
||||
}
|
||||
|
||||
// The navquery is mostly used for local searches, no need for large node pool.
|
||||
@ -484,6 +484,17 @@ int dtCrowd::getAgentCount() const
|
||||
/// Agents in the pool may not be in use. Check #dtCrowdAgent.active before using the returned object.
|
||||
const dtCrowdAgent* dtCrowd::getAgent(const int idx)
|
||||
{
|
||||
if (idx < 0 || idx >= m_maxAgents)
|
||||
return 0;
|
||||
return &m_agents[idx];
|
||||
}
|
||||
|
||||
///
|
||||
/// Agents in the pool may not be in use. Check #dtCrowdAgent.active before using the returned object.
|
||||
dtCrowdAgent* dtCrowd::getEditableAgent(const int idx)
|
||||
{
|
||||
if (idx < 0 || idx >= m_maxAgents)
|
||||
return 0;
|
||||
return &m_agents[idx];
|
||||
}
|
||||
|
||||
@ -514,11 +525,13 @@ int dtCrowd::addAgent(const float* pos, const dtCrowdAgentParams* params)
|
||||
|
||||
dtCrowdAgent* ag = &m_agents[idx];
|
||||
|
||||
updateAgentParameters(idx, params);
|
||||
|
||||
// Find nearest position on navmesh and place the agent there.
|
||||
float nearest[3];
|
||||
dtPolyRef ref = 0;
|
||||
dtVcopy(nearest, pos);
|
||||
dtStatus status = m_navquery->findNearestPoly(pos, m_ext, &m_filter, &ref, nearest);
|
||||
dtStatus status = m_navquery->findNearestPoly(pos, m_ext, &m_filters[ag->params.queryFilterType], &ref, nearest);
|
||||
if (dtStatusFailed(status))
|
||||
{
|
||||
dtVcopy(nearest, pos);
|
||||
@ -527,8 +540,7 @@ int dtCrowd::addAgent(const float* pos, const dtCrowdAgentParams* params)
|
||||
|
||||
ag->corridor.reset(ref, nearest);
|
||||
ag->boundary.reset();
|
||||
|
||||
updateAgentParameters(idx, params);
|
||||
ag->partial = false;
|
||||
|
||||
ag->topologyOptTime = 0;
|
||||
ag->targetReplanTime = 0;
|
||||
@ -548,7 +560,7 @@ int dtCrowd::addAgent(const float* pos, const dtCrowdAgentParams* params)
|
||||
|
||||
ag->targetState = DT_CROWDAGENT_TARGET_NONE;
|
||||
|
||||
ag->active = 1;
|
||||
ag->active = true;
|
||||
|
||||
return idx;
|
||||
}
|
||||
@ -561,7 +573,7 @@ void dtCrowd::removeAgent(const int idx)
|
||||
{
|
||||
if (idx >= 0 && idx < m_maxAgents)
|
||||
{
|
||||
m_agents[idx].active = 0;
|
||||
m_agents[idx].active = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -691,7 +703,7 @@ void dtCrowd::updateMoveRequest(const float /*dt*/)
|
||||
|
||||
// Quick seach towards the goal.
|
||||
static const int MAX_ITER = 20;
|
||||
m_navquery->initSlicedFindPath(path[0], ag->targetRef, ag->npos, ag->targetPos, &m_filter);
|
||||
m_navquery->initSlicedFindPath(path[0], ag->targetRef, ag->npos, ag->targetPos, &m_filters[ag->params.queryFilterType]);
|
||||
m_navquery->updateSlicedFindPath(MAX_ITER, 0);
|
||||
dtStatus status = 0;
|
||||
if (ag->targetReplan) // && npath > 10)
|
||||
@ -711,7 +723,7 @@ void dtCrowd::updateMoveRequest(const float /*dt*/)
|
||||
if (reqPath[reqPathCount-1] != ag->targetRef)
|
||||
{
|
||||
// Partial path, constrain target position inside the last polygon.
|
||||
status = m_navquery->closestPointOnPoly(reqPath[reqPathCount-1], ag->targetPos, reqPos);
|
||||
status = m_navquery->closestPointOnPoly(reqPath[reqPathCount-1], ag->targetPos, reqPos, 0);
|
||||
if (dtStatusFailed(status))
|
||||
reqPathCount = 0;
|
||||
}
|
||||
@ -735,6 +747,7 @@ void dtCrowd::updateMoveRequest(const float /*dt*/)
|
||||
|
||||
ag->corridor.setCorridor(reqPos, reqPath, reqPathCount);
|
||||
ag->boundary.reset();
|
||||
ag->partial = false;
|
||||
|
||||
if (reqPath[reqPathCount-1] == ag->targetRef)
|
||||
{
|
||||
@ -758,7 +771,7 @@ void dtCrowd::updateMoveRequest(const float /*dt*/)
|
||||
{
|
||||
dtCrowdAgent* ag = queue[i];
|
||||
ag->targetPathqRef = m_pathq.request(ag->corridor.getLastPoly(), ag->targetRef,
|
||||
ag->corridor.getTarget(), ag->targetPos, &m_filter);
|
||||
ag->corridor.getTarget(), ag->targetPos, &m_filters[ag->params.queryFilterType]);
|
||||
if (ag->targetPathqRef != DT_PATHQ_INVALID)
|
||||
ag->targetState = DT_CROWDAGENT_TARGET_WAITING_FOR_PATH;
|
||||
}
|
||||
@ -809,6 +822,11 @@ void dtCrowd::updateMoveRequest(const float /*dt*/)
|
||||
if (dtStatusFailed(status) || !nres)
|
||||
valid = false;
|
||||
|
||||
if (dtStatusDetail(status, DT_PARTIAL_RESULT))
|
||||
ag->partial = true;
|
||||
else
|
||||
ag->partial = false;
|
||||
|
||||
// Merge result and existing path.
|
||||
// The agent might have moved whilst the request is
|
||||
// being processed, so the path may have changed.
|
||||
@ -855,7 +873,7 @@ void dtCrowd::updateMoveRequest(const float /*dt*/)
|
||||
{
|
||||
// Partial path, constrain target position inside the last polygon.
|
||||
float nearest[3];
|
||||
status = m_navquery->closestPointOnPoly(res[nres-1], targetPos, nearest);
|
||||
status = m_navquery->closestPointOnPoly(res[nres-1], targetPos, nearest, 0);
|
||||
if (dtStatusSucceed(status))
|
||||
dtVcopy(targetPos, nearest);
|
||||
else
|
||||
@ -912,7 +930,7 @@ void dtCrowd::updateTopologyOptimization(dtCrowdAgent** agents, const int nagent
|
||||
for (int i = 0; i < nqueue; ++i)
|
||||
{
|
||||
dtCrowdAgent* ag = queue[i];
|
||||
ag->corridor.optimizePathTopology(m_navquery, &m_filter);
|
||||
ag->corridor.optimizePathTopology(m_navquery, &m_filters[ag->params.queryFilterType]);
|
||||
ag->topologyOptTime = 0;
|
||||
}
|
||||
|
||||
@ -930,9 +948,6 @@ void dtCrowd::checkPathValidity(dtCrowdAgent** agents, const int nagents, const
|
||||
if (ag->state != DT_CROWDAGENT_STATE_WALKING)
|
||||
continue;
|
||||
|
||||
if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
|
||||
continue;
|
||||
|
||||
ag->targetReplanTime += dt;
|
||||
|
||||
bool replan = false;
|
||||
@ -942,20 +957,21 @@ void dtCrowd::checkPathValidity(dtCrowdAgent** agents, const int nagents, const
|
||||
float agentPos[3];
|
||||
dtPolyRef agentRef = ag->corridor.getFirstPoly();
|
||||
dtVcopy(agentPos, ag->npos);
|
||||
if (!m_navquery->isValidPolyRef(agentRef, &m_filter))
|
||||
if (!m_navquery->isValidPolyRef(agentRef, &m_filters[ag->params.queryFilterType]))
|
||||
{
|
||||
// Current location is not valid, try to reposition.
|
||||
// TODO: this can snap agents, how to handle that?
|
||||
float nearest[3];
|
||||
dtVcopy(nearest, agentPos);
|
||||
agentRef = 0;
|
||||
dtStatus status = m_navquery->findNearestPoly(ag->npos, m_ext, &m_filter, &agentRef, nearest);
|
||||
m_navquery->findNearestPoly(ag->npos, m_ext, &m_filters[ag->params.queryFilterType], &agentRef, nearest);
|
||||
dtVcopy(agentPos, nearest);
|
||||
|
||||
if (!agentRef)
|
||||
{
|
||||
// Could not find location in navmesh, set state to invalid.
|
||||
ag->corridor.reset(0, agentPos);
|
||||
ag->partial = false;
|
||||
ag->boundary.reset();
|
||||
ag->state = DT_CROWDAGENT_STATE_INVALID;
|
||||
continue;
|
||||
@ -971,16 +987,20 @@ void dtCrowd::checkPathValidity(dtCrowdAgent** agents, const int nagents, const
|
||||
replan = true;
|
||||
}
|
||||
|
||||
// If the agent does not have move target or is controlled by velocity, no need to recover the target nor replan.
|
||||
if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
|
||||
continue;
|
||||
|
||||
// Try to recover move request position.
|
||||
if (ag->targetState != DT_CROWDAGENT_TARGET_NONE && ag->targetState != DT_CROWDAGENT_TARGET_FAILED)
|
||||
{
|
||||
if (!m_navquery->isValidPolyRef(ag->targetRef, &m_filter))
|
||||
if (!m_navquery->isValidPolyRef(ag->targetRef, &m_filters[ag->params.queryFilterType]))
|
||||
{
|
||||
// Current target is not valid, try to reposition.
|
||||
float nearest[3];
|
||||
dtVcopy(nearest, ag->targetPos);
|
||||
ag->targetRef = 0;
|
||||
m_navquery->findNearestPoly(ag->targetPos, m_ext, &m_filter, &ag->targetRef, nearest);
|
||||
m_navquery->findNearestPoly(ag->targetPos, m_ext, &m_filters[ag->params.queryFilterType], &ag->targetRef, nearest);
|
||||
dtVcopy(ag->targetPos, nearest);
|
||||
replan = true;
|
||||
}
|
||||
@ -988,12 +1008,13 @@ void dtCrowd::checkPathValidity(dtCrowdAgent** agents, const int nagents, const
|
||||
{
|
||||
// Failed to reposition target, fail moverequest.
|
||||
ag->corridor.reset(agentRef, agentPos);
|
||||
ag->partial = false;
|
||||
ag->targetState = DT_CROWDAGENT_TARGET_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// If nearby corridor is not valid, replan.
|
||||
if (!ag->corridor.isValid(CHECK_LOOKAHEAD, m_navquery, &m_filter))
|
||||
if (!ag->corridor.isValid(CHECK_LOOKAHEAD, m_navquery, &m_filters[ag->params.queryFilterType]))
|
||||
{
|
||||
// Fix current path.
|
||||
// ag->corridor.trimInvalidPath(agentRef, agentPos, m_navquery, &m_filter);
|
||||
@ -1060,10 +1081,10 @@ void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug)
|
||||
// if it has become invalid.
|
||||
const float updateThr = ag->params.collisionQueryRange*0.25f;
|
||||
if (dtVdist2DSqr(ag->npos, ag->boundary.getCenter()) > dtSqr(updateThr) ||
|
||||
!ag->boundary.isValid(m_navquery, &m_filter))
|
||||
!ag->boundary.isValid(m_navquery, &m_filters[ag->params.queryFilterType]))
|
||||
{
|
||||
ag->boundary.update(ag->corridor.getFirstPoly(), ag->npos, ag->params.collisionQueryRange,
|
||||
m_navquery, &m_filter);
|
||||
m_navquery, &m_filters[ag->params.queryFilterType]);
|
||||
}
|
||||
// Query neighbour agents
|
||||
ag->nneis = getNeighbours(ag->npos, ag->params.height, ag->params.collisionQueryRange,
|
||||
@ -1085,14 +1106,14 @@ void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug)
|
||||
|
||||
// Find corners for steering
|
||||
ag->ncorners = ag->corridor.findCorners(ag->cornerVerts, ag->cornerFlags, ag->cornerPolys,
|
||||
DT_CROWDAGENT_MAX_CORNERS, m_navquery, &m_filter);
|
||||
DT_CROWDAGENT_MAX_CORNERS, m_navquery, &m_filters[ag->params.queryFilterType]);
|
||||
|
||||
// Check to see if the corner after the next corner is directly visible,
|
||||
// and short cut to there.
|
||||
if ((ag->params.updateFlags & DT_CROWD_OPTIMIZE_VIS) && ag->ncorners > 0)
|
||||
{
|
||||
const float* target = &ag->cornerVerts[dtMin(1,ag->ncorners-1)*3];
|
||||
ag->corridor.optimizePathVisibility(target, ag->params.pathOptimizationRange, m_navquery, &m_filter);
|
||||
ag->corridor.optimizePathVisibility(target, ag->params.pathOptimizationRange, m_navquery, &m_filters[ag->params.queryFilterType]);
|
||||
|
||||
// Copy data for debug purposes.
|
||||
if (debugIdx == i)
|
||||
@ -1137,7 +1158,7 @@ void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug)
|
||||
{
|
||||
dtVcopy(anim->initPos, ag->npos);
|
||||
anim->polyRef = refs[1];
|
||||
anim->active = 1;
|
||||
anim->active = true;
|
||||
anim->t = 0.0f;
|
||||
anim->tmax = (dtVdist2D(anim->startPos, anim->endPos) / ag->params.maxSpeed) * 0.5f;
|
||||
|
||||
@ -1372,7 +1393,7 @@ void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug)
|
||||
continue;
|
||||
|
||||
// Move along navmesh.
|
||||
ag->corridor.movePosition(ag->npos, m_navquery, &m_filter);
|
||||
ag->corridor.movePosition(ag->npos, m_navquery, &m_filters[ag->params.queryFilterType]);
|
||||
// Get valid constrained position back.
|
||||
dtVcopy(ag->npos, ag->corridor.getPos());
|
||||
|
||||
@ -1380,6 +1401,7 @@ void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug)
|
||||
if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
|
||||
{
|
||||
ag->corridor.reset(ag->corridor.getFirstPoly(), ag->npos);
|
||||
ag->partial = false;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1396,7 +1418,7 @@ void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug)
|
||||
if (anim->t > anim->tmax)
|
||||
{
|
||||
// Reset animation
|
||||
anim->active = 0;
|
||||
anim->active = false;
|
||||
// Prepare agent for walking.
|
||||
ag->state = DT_CROWDAGENT_STATE_WALKING;
|
||||
continue;
|
||||
@ -1422,5 +1444,3 @@ void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -185,6 +185,7 @@ dtStatus dtPathQueue::getPathResult(dtPathQueueRef ref, dtPolyRef* path, int* pa
|
||||
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;
|
||||
@ -192,7 +193,7 @@ dtStatus dtPathQueue::getPathResult(dtPathQueueRef ref, dtPolyRef* path, int* pa
|
||||
int n = dtMin(q.npath, maxPath);
|
||||
memcpy(path, q.path, sizeof(dtPolyRef)*n);
|
||||
*pathSize = n;
|
||||
return DT_SUCCESS;
|
||||
return details | DT_SUCCESS;
|
||||
}
|
||||
}
|
||||
return DT_FAILURE;
|
||||
|
@ -2116,6 +2116,7 @@ dtStatus dtDecompressTileCacheLayer(dtTileCacheAlloc* alloc, dtTileCacheCompress
|
||||
|
||||
bool dtTileCacheHeaderSwapEndian(unsigned char* data, const int dataSize)
|
||||
{
|
||||
dtIgnoreUnused(dataSize);
|
||||
dtTileCacheLayerHeader* header = (dtTileCacheLayerHeader*)data;
|
||||
|
||||
int swappedMagic = DT_TILECACHE_MAGIC;
|
||||
|
@ -1,34 +1,27 @@
|
||||
/// @mainpage Recast Navigation
|
||||
///
|
||||
/// @note A documentation effort is currently underway.
|
||||
/// This documentation is in a draft state until the effort is complete.
|
||||
///
|
||||
/// @section intro_recast Recast
|
||||
///
|
||||
/// Recast is state of the art navigation mesh construction toolset for
|
||||
/// games.
|
||||
///
|
||||
/// - It is <b>automatic</b>, which means that you can throw any level
|
||||
/// geometry at it and you will get robust mesh out.
|
||||
/// - It is <b>fast</b> which means swift turnaround times for level
|
||||
/// designers.
|
||||
/// - It is <b>open source</b> so it comes with full source and you can
|
||||
/// customize it to your hearts content.
|
||||
///
|
||||
/// The Library is free for commercial use and open source under the
|
||||
/// ZLib License.
|
||||
///
|
||||
/// <b>Please use the latest version from the
|
||||
/// <a href="http://code.google.com/p/recastnavigation/">SVN</a>.</b>
|
||||
///
|
||||
/// @image html recast_intro.png
|
||||
///
|
||||
/// The Recast process starts with constructing a voxel mold from a level
|
||||
/// <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, peeling off the regions as simple polygons.
|
||||
/// mold into simple regions, and peeling off the regions as simple polygons.
|
||||
///
|
||||
/// -# The voxel mold is build from the input triangle mesh by
|
||||
/// -# 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.
|
||||
@ -41,20 +34,62 @@
|
||||
/// polygons are finally converted to convex polygons which makes them
|
||||
/// perfect for pathfinding and spatial reasoning about the level.
|
||||
///
|
||||
/// @section intro_detour Detour
|
||||
/// <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.
|
||||
/// _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
|
||||
/// _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.
|
||||
///
|
||||
/// You can discuss and give feedback for Recast and Detour in the
|
||||
/// <a href="http://groups.google.com/group/recastnavigation">
|
||||
/// discussion group</a>.
|
||||
/// <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.
|
||||
///
|
@ -1,24 +1,24 @@
|
||||
<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="namespaces" visible="yes" title="" intro=""/>
|
||||
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||
<tab type="namespacemembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="classes" visible="yes" title="">
|
||||
<tab type="classes" visible="no" title="" intro=""/>
|
||||
<tab type="classindex" visible="no" title=""/>
|
||||
<tab type="hierarchy" visible="no" title="" intro=""/>
|
||||
<tab type="classmembers" visible="no" title="" intro=""/>
|
||||
<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="no" title="">
|
||||
<tab type="files" visible="no" title="" intro=""/>
|
||||
<tab type="globals" visible="no" title="" intro=""/>
|
||||
<tab type="files" visible="yes" title="">
|
||||
<tab type="filelist" visible="yes" title="" intro=""/>
|
||||
<tab type="globals" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="dirs" visible="no" title="" intro=""/>
|
||||
<tab type="examples" visible="yes" title="" intro=""/>
|
||||
</navindex>
|
||||
|
||||
@ -28,10 +28,11 @@
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
|
||||
<allmemberslink visible="yes"/>
|
||||
<memberdecl>
|
||||
<nestedclasses visible="no" title=""/> <!-- If set to 'yes', the private nested classes will be visible. -->
|
||||
<nestedclasses visible="yes" title=""/>
|
||||
<publictypes title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<publicslots title=""/>
|
||||
<signals title=""/>
|
||||
<publicmethods title=""/>
|
||||
@ -61,10 +62,13 @@
|
||||
<related title="" subtitle=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<detaileddescription title="Description"/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<constructors title=""/>
|
||||
<functions title=""/>
|
||||
<related title=""/>
|
||||
@ -72,6 +76,7 @@
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
</memberdef>
|
||||
<allmemberslink visible="yes"/>
|
||||
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||
<authorsection visible="yes"/>
|
||||
</class>
|
||||
@ -81,6 +86,7 @@
|
||||
<briefdescription visible="yes"/>
|
||||
<memberdecl>
|
||||
<nestednamespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
@ -88,8 +94,9 @@
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<detaileddescription title="Description"/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
@ -100,7 +107,8 @@
|
||||
|
||||
<!-- Layout definition for a file page -->
|
||||
<file>
|
||||
<briefdescription visible="yes"/>
|
||||
<briefdescription visible="Description"/>
|
||||
<detaileddescription title=""/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<includegraph visible="$INCLUDE_GRAPH"/>
|
||||
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
|
||||
@ -108,6 +116,7 @@
|
||||
<memberdecl>
|
||||
<classes visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
@ -115,8 +124,8 @@
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
@ -128,15 +137,14 @@
|
||||
|
||||
<!-- Layout definition for a group page -->
|
||||
<group>
|
||||
<briefdescription visible="no"/>
|
||||
<detaileddescription title="Description"/>
|
||||
<briefdescription visible="yes"/>
|
||||
<groupgraph visible="$GROUP_GRAPHS"/>
|
||||
<memberdecl>
|
||||
<classes visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<dirs visible="yes" title=""/>
|
||||
<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=""/>
|
||||
@ -152,6 +160,7 @@
|
||||
<friends title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title="Description"/>
|
||||
<memberdef>
|
||||
<pagedocs/>
|
||||
<inlineclasses title=""/>
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 370 KiB |
@ -23,6 +23,10 @@ Directory Layout
|
||||
|
||||
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
|
||||
@ -39,4 +43,22 @@ is placed as follows:
|
||||
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)"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,847 +0,0 @@
|
||||
/* The standard CSS for doxygen */
|
||||
|
||||
body, table, div, p, dl {
|
||||
font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* @group Heading Levels */
|
||||
|
||||
h1 {
|
||||
font-size: 150%;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 150%;
|
||||
font-weight: bold;
|
||||
margin: 10px 2px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
div.textblock h2 {
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-color: #336699;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.multicol {
|
||||
-moz-column-gap: 1em;
|
||||
-webkit-column-gap: 1em;
|
||||
-moz-column-count: 3;
|
||||
-webkit-column-count: 3;
|
||||
}
|
||||
|
||||
p.startli, p.startdd, p.starttd {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
p.endli {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
p.enddd {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
p.endtd {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
caption {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span.legend {
|
||||
font-size: 70%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h3.version {
|
||||
font-size: 90%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.qindex, div.navtab{
|
||||
background-color: #EBEFF6;
|
||||
border: 1px solid #A3B4D7;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
div.qindex, div.navpath {
|
||||
width: 100%;
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
div.navtab {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
/* @group Link Styling */
|
||||
|
||||
a {
|
||||
color: #3D578C;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.contents a:visited {
|
||||
color: #4665A2;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.qindex {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a.qindexHL {
|
||||
font-weight: bold;
|
||||
background-color: #9CAFD4;
|
||||
color: #ffffff;
|
||||
border: 1px double #869DCA;
|
||||
}
|
||||
|
||||
.contents a.qindexHL:visited {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
a.el {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a.elRef {
|
||||
}
|
||||
|
||||
a.code {
|
||||
color: #4665A2;
|
||||
}
|
||||
|
||||
a.codeRef {
|
||||
color: #4665A2;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
dl.el {
|
||||
margin-left: -1cm;
|
||||
}
|
||||
|
||||
.fragment {
|
||||
font-family: monospace, fixed;
|
||||
font-size: 105%;
|
||||
}
|
||||
|
||||
pre.fragment {
|
||||
border: 1px solid #C4CFE5;
|
||||
background-color: #FBFCFD;
|
||||
padding: 4px 6px;
|
||||
margin: 4px 8px 4px 2px;
|
||||
overflow: auto;
|
||||
word-wrap: break-word;
|
||||
font-size: 9pt;
|
||||
line-height: 125%;
|
||||
}
|
||||
|
||||
div.ah {
|
||||
background-color: black;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
margin-bottom: 3px;
|
||||
margin-top: 3px;
|
||||
padding: 0.2em;
|
||||
border: solid thin #333;
|
||||
border-radius: 0.5em;
|
||||
-webkit-border-radius: .5em;
|
||||
-moz-border-radius: .5em;
|
||||
box-shadow: 2px 2px 3px #999;
|
||||
-webkit-box-shadow: 2px 2px 3px #999;
|
||||
-moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
|
||||
background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
|
||||
}
|
||||
|
||||
div.groupHeader {
|
||||
margin-left: 16px;
|
||||
margin-top: 12px;
|
||||
font-weight: bold;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
div.groupText {
|
||||
margin-left: 16px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
body {
|
||||
background: white;
|
||||
color: black;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.contents {
|
||||
margin-top: 10px;
|
||||
margin-left: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
td.indexkey {
|
||||
background-color: #EBEFF6;
|
||||
font-weight: bold;
|
||||
border: 1px solid #C4CFE5;
|
||||
margin: 2px 0px 2px 0;
|
||||
padding: 2px 10px;
|
||||
}
|
||||
|
||||
td.indexvalue {
|
||||
background-color: #EBEFF6;
|
||||
border: 1px solid #C4CFE5;
|
||||
padding: 2px 10px;
|
||||
margin: 2px 0px;
|
||||
}
|
||||
|
||||
tr.memlist {
|
||||
background-color: #EEF1F7;
|
||||
}
|
||||
|
||||
p.formulaDsp {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
img.formulaDsp {
|
||||
|
||||
}
|
||||
|
||||
img.formulaInl {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.center {
|
||||
text-align: center;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
div.center img {
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
address.footer {
|
||||
text-align: right;
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
img.footer {
|
||||
border: 0px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* @group Code Colorization */
|
||||
|
||||
span.keyword {
|
||||
color: #008000
|
||||
}
|
||||
|
||||
span.keywordtype {
|
||||
color: #604020
|
||||
}
|
||||
|
||||
span.keywordflow {
|
||||
color: #e08000
|
||||
}
|
||||
|
||||
span.comment {
|
||||
color: #800000
|
||||
}
|
||||
|
||||
span.preprocessor {
|
||||
color: #806020
|
||||
}
|
||||
|
||||
span.stringliteral {
|
||||
color: #002080
|
||||
}
|
||||
|
||||
span.charliteral {
|
||||
color: #008080
|
||||
}
|
||||
|
||||
span.vhdldigit {
|
||||
color: #ff00ff
|
||||
}
|
||||
|
||||
span.vhdlchar {
|
||||
color: #000000
|
||||
}
|
||||
|
||||
span.vhdlkeyword {
|
||||
color: #700070
|
||||
}
|
||||
|
||||
span.vhdllogic {
|
||||
color: #ff0000
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/*
|
||||
.search {
|
||||
color: #003399;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
form.search {
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
input.search {
|
||||
font-size: 75%;
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
background-color: #e8eef2;
|
||||
}
|
||||
*/
|
||||
|
||||
td.tiny {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
.dirtab {
|
||||
padding: 4px;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #A3B4D7;
|
||||
}
|
||||
|
||||
th.dirtab {
|
||||
background: #EBEFF6;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 0px;
|
||||
border: none;
|
||||
border-top: 1px solid #4A6AAA;
|
||||
}
|
||||
|
||||
hr.footer {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
/* @group Member Descriptions */
|
||||
|
||||
table.memberdecls {
|
||||
border-spacing: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.mdescLeft, .mdescRight,
|
||||
.memItemLeft, .memItemRight,
|
||||
.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
|
||||
background-color: #F9FAFC;
|
||||
border: none;
|
||||
margin: 4px;
|
||||
padding: 8px 0 8px 8px;
|
||||
}
|
||||
|
||||
.mdescLeft {
|
||||
padding: 0px 8px 4px 8px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.mdescRight {
|
||||
padding: 4px 8px 8px 24px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.memItemLeft, .memItemRight, .memTemplParams {
|
||||
border-top: 1px solid #C4CFE5;
|
||||
}
|
||||
|
||||
.memItemLeft, .memTemplItemLeft {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.memItemRight {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.memTemplParams {
|
||||
color: #4665A2;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Member Details */
|
||||
|
||||
/* Styles for detailed member documentation */
|
||||
|
||||
.memtemplate {
|
||||
font-size: 80%;
|
||||
color: #4665A2;
|
||||
font-weight: normal;
|
||||
margin-left: 9px;
|
||||
}
|
||||
|
||||
.memnav {
|
||||
background-color: #EBEFF6;
|
||||
border: 1px solid #A3B4D7;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
margin-right: 15px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.mempage {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.memitem {
|
||||
padding: 0;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.memname {
|
||||
white-space: nowrap;
|
||||
font-weight: bold;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.memproto {
|
||||
border-top: 1px solid #A8B8D9;
|
||||
border-left: 1px solid #A8B8D9;
|
||||
border-right: 1px solid #A8B8D9;
|
||||
padding: 6px 0px 6px 0px;
|
||||
color: #253555;
|
||||
font-weight: bold;
|
||||
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
|
||||
/* opera specific markup */
|
||||
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
|
||||
border-top-right-radius: 8px;
|
||||
border-top-left-radius: 8px;
|
||||
/* firefox specific markup */
|
||||
-moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
|
||||
-moz-border-radius-topright: 8px;
|
||||
-moz-border-radius-topleft: 8px;
|
||||
/* webkit specific markup */
|
||||
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
|
||||
-webkit-border-top-right-radius: 8px;
|
||||
-webkit-border-top-left-radius: 8px;
|
||||
background-image:url('nav_f.png');
|
||||
background-repeat:repeat-x;
|
||||
background-color: #E2E8F2;
|
||||
|
||||
}
|
||||
|
||||
.memdoc {
|
||||
border-bottom: 1px solid #A8B8D9;
|
||||
border-left: 1px solid #A8B8D9;
|
||||
border-right: 1px solid #A8B8D9;
|
||||
padding: 2px 5px;
|
||||
background-color: #FBFCFD;
|
||||
border-top-width: 0;
|
||||
/* opera specific markup */
|
||||
border-bottom-left-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
|
||||
/* firefox specific markup */
|
||||
-moz-border-radius-bottomleft: 8px;
|
||||
-moz-border-radius-bottomright: 8px;
|
||||
-moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
|
||||
background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7);
|
||||
/* webkit specific markup */
|
||||
-webkit-border-bottom-left-radius: 8px;
|
||||
-webkit-border-bottom-right-radius: 8px;
|
||||
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
|
||||
background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7));
|
||||
}
|
||||
|
||||
.paramkey {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.paramtype {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.paramname {
|
||||
color: #602020;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.paramname em {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.params, .retval, .exception, .tparams {
|
||||
border-spacing: 6px 2px;
|
||||
}
|
||||
|
||||
.params .paramname, .retval .paramname {
|
||||
font-weight: bold;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.params .paramtype {
|
||||
font-style: italic;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.params .paramdir {
|
||||
font-family: "courier new",courier,monospace;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Directory (tree) */
|
||||
|
||||
/* for the tree view */
|
||||
|
||||
.ftvtree {
|
||||
font-family: sans-serif;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
/* these are for tree view when used as main index */
|
||||
|
||||
.directory {
|
||||
font-size: 9pt;
|
||||
font-weight: bold;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.directory h3 {
|
||||
margin: 0px;
|
||||
margin-top: 1em;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
/*
|
||||
The following two styles can be used to replace the root node title
|
||||
with an image of your choice. Simply uncomment the next two styles,
|
||||
specify the name of your image and be sure to set 'height' to the
|
||||
proper pixel height of your image.
|
||||
*/
|
||||
|
||||
/*
|
||||
.directory h3.swap {
|
||||
height: 61px;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url("yourimage.gif");
|
||||
}
|
||||
.directory h3.swap span {
|
||||
display: none;
|
||||
}
|
||||
*/
|
||||
|
||||
.directory > h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.directory p {
|
||||
margin: 0px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.directory div {
|
||||
display: none;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.directory img {
|
||||
vertical-align: -30%;
|
||||
}
|
||||
|
||||
/* these are for tree view when not used as main index */
|
||||
|
||||
.directory-alt {
|
||||
font-size: 100%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.directory-alt h3 {
|
||||
margin: 0px;
|
||||
margin-top: 1em;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
.directory-alt > h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.directory-alt p {
|
||||
margin: 0px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.directory-alt div {
|
||||
display: none;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.directory-alt img {
|
||||
vertical-align: -30%;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
div.dynheader {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
address {
|
||||
font-style: normal;
|
||||
color: #2A3D61;
|
||||
}
|
||||
|
||||
table.doxtable {
|
||||
border-collapse:collapse;
|
||||
}
|
||||
|
||||
table.doxtable td, table.doxtable th {
|
||||
border: 1px solid #2D4068;
|
||||
padding: 3px 7px 2px;
|
||||
}
|
||||
|
||||
table.doxtable th {
|
||||
background-color: #374F7F;
|
||||
color: #FFFFFF;
|
||||
font-size: 110%;
|
||||
padding-bottom: 4px;
|
||||
padding-top: 5px;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
.tabsearch {
|
||||
top: 0px;
|
||||
left: 10px;
|
||||
height: 36px;
|
||||
background-image: url('tab_b.png');
|
||||
z-index: 101;
|
||||
overflow: hidden;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.navpath ul
|
||||
{
|
||||
font-size: 11px;
|
||||
background-image:url('tab_b.png');
|
||||
background-repeat:repeat-x;
|
||||
height:30px;
|
||||
line-height:30px;
|
||||
color:#8AA0CC;
|
||||
border:solid 1px #C2CDE4;
|
||||
overflow:hidden;
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
}
|
||||
|
||||
.navpath li
|
||||
{
|
||||
list-style-type:none;
|
||||
float:left;
|
||||
padding-left:10px;
|
||||
padding-right:15px;
|
||||
background-image:url('bc_s.png');
|
||||
background-repeat:no-repeat;
|
||||
background-position:right;
|
||||
color:#364D7C;
|
||||
}
|
||||
|
||||
.navpath li.navelem a
|
||||
{
|
||||
height:32px;
|
||||
display:block;
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.navpath li.navelem a:hover
|
||||
{
|
||||
color:#6884BD;
|
||||
}
|
||||
|
||||
.navpath li.footer
|
||||
{
|
||||
list-style-type:none;
|
||||
float:right;
|
||||
padding-left:10px;
|
||||
padding-right:15px;
|
||||
background-image:none;
|
||||
background-repeat:no-repeat;
|
||||
background-position:right;
|
||||
color:#364D7C;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
|
||||
div.summary
|
||||
{
|
||||
float: right;
|
||||
font-size: 8pt;
|
||||
padding-right: 5px;
|
||||
width: 50%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.summary a
|
||||
{
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
div.ingroups
|
||||
{
|
||||
font-size: 8pt;
|
||||
padding-left: 5px;
|
||||
width: 50%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.ingroups a
|
||||
{
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
div.header
|
||||
{
|
||||
background-image:url('nav_h.png');
|
||||
background-repeat:repeat-x;
|
||||
background-color: #F9FAFC;
|
||||
margin: 0px;
|
||||
border-bottom: 1px solid #C4CFE5;
|
||||
}
|
||||
|
||||
div.headertitle
|
||||
{
|
||||
padding: 5px 5px 5px 10px;
|
||||
}
|
||||
|
||||
dl
|
||||
{
|
||||
padding: 0 0 0 10px;
|
||||
}
|
||||
|
||||
dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug
|
||||
{
|
||||
border-left:4px solid;
|
||||
padding: 0 0 0 6px;
|
||||
}
|
||||
|
||||
dl.note
|
||||
{
|
||||
border-color: #D0C000;
|
||||
}
|
||||
|
||||
dl.warning, dl.attention
|
||||
{
|
||||
border-color: #FF0000;
|
||||
}
|
||||
|
||||
dl.pre, dl.post, dl.invariant
|
||||
{
|
||||
border-color: #00D000;
|
||||
}
|
||||
|
||||
dl.deprecated
|
||||
{
|
||||
border-color: #505050;
|
||||
}
|
||||
|
||||
dl.todo
|
||||
{
|
||||
border-color: #00C0E0;
|
||||
}
|
||||
|
||||
dl.test
|
||||
{
|
||||
border-color: #3030E0;
|
||||
}
|
||||
|
||||
dl.bug
|
||||
{
|
||||
border-color: #C08050;
|
||||
}
|
||||
|
||||
#projectlogo
|
||||
{
|
||||
text-align: center;
|
||||
vertical-align: bottom;
|
||||
border-collapse: separate;
|
||||
}
|
||||
|
||||
#projectlogo img
|
||||
{
|
||||
border: 0px none;
|
||||
}
|
||||
|
||||
#projectname
|
||||
{
|
||||
font: 300% Tahoma, Arial,sans-serif;
|
||||
margin: 0px;
|
||||
padding: 2px 0px;
|
||||
}
|
||||
|
||||
#projectbrief
|
||||
{
|
||||
font: 120% Tahoma, Arial,sans-serif;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#projectnumber
|
||||
{
|
||||
font: 50% Tahoma, Arial,sans-serif;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#titlearea
|
||||
{
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #5373B4;
|
||||
}
|
||||
|
||||
.image
|
||||
{
|
||||
text-align: left
|
||||
}
|
||||
|
||||
.dotgraph
|
||||
{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mscgraph
|
||||
{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.caption
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
<!-- HTML footer for doxygen 1.8.6-->
|
||||
<!-- start footer part -->
|
||||
<!--BEGIN GENERATE_TREEVIEW-->
|
||||
<li class="footer">
|
||||
<a href="http://code.google.com/p/recastnavigation/">Project Home</a>
|
||||
| <a href="./License.html"> Licence</a>
|
||||
| Copyright (c) 2009-2011 Mikko Mononen
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<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="http://code.google.com/p/recastnavigation/">Project Home</a>
|
||||
| <a href="./License.html">Licence</a>
|
||||
| Copyright (c) 2009-2011 Mikko Mononen
|
||||
<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>
|
||||
|
@ -1,23 +1,31 @@
|
||||
<!-- 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"/>
|
||||
<title>$title</title>
|
||||
<link href="$relpath$tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="$relpath$customdoxygen.css" rel="stylesheet" type="text/css" />
|
||||
<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! -->
|
||||
<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>
|
||||
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
|
||||
<!--END PROJECT_LOGO-->
|
||||
<!--BEGIN PROJECT_NAME-->
|
||||
<td style="padding-left: 0.5em;">
|
||||
@ -44,3 +52,4 @@ $mathjax
|
||||
</table>
|
||||
</div>
|
||||
<!--END TITLEAREA-->
|
||||
<!-- end header part -->
|
||||
|
@ -12,7 +12,7 @@ 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 hearts content.
|
||||
* 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,
|
||||
@ -28,7 +28,7 @@ the regions as simple polygons.
|
||||
|
||||
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 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.
|
||||
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
|
||||
@ -54,7 +54,7 @@ It is recommended to add the source directories `DebugUtils`, `Detour`, `DetourC
|
||||
## Discuss
|
||||
|
||||
- Discuss Recast & Detour: http://groups.google.com/group/recastnavigation
|
||||
- Develoment blog: http://digestingduck.blogspot.com/
|
||||
- Development blog: http://digestingduck.blogspot.com/
|
||||
|
||||
|
||||
## License
|
||||
|
@ -219,7 +219,7 @@ struct rcConfig
|
||||
int maxEdgeLen;
|
||||
|
||||
/// The maximum distance a simplfied contour's border edges should deviate
|
||||
/// the original raw contour. [Limit: >=0] [Units: wu]
|
||||
/// the original raw contour. [Limit: >=0] [Units: vx]
|
||||
float maxSimplificationError;
|
||||
|
||||
/// The minimum number of cells allowed to form isolated island areas. [Limit: >=0] [Units: vx]
|
||||
@ -549,6 +549,11 @@ static const int RC_NOT_CONNECTED = 0x3f;
|
||||
/// @name General helper functions
|
||||
/// @{
|
||||
|
||||
/// Used to ignore a function parameter. VS complains about unused parameters
|
||||
/// and this silences the warning.
|
||||
/// @param [in] _ Unused parameter
|
||||
template<class T> void rcIgnoreUnused(const T&) { }
|
||||
|
||||
/// Swaps the values of the two parameters.
|
||||
/// @param[in,out] a Value A
|
||||
/// @param[in,out] b Value B
|
||||
|
@ -208,12 +208,11 @@ void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int*
|
||||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||
///
|
||||
/// @see rcAllocHeightfield, rcHeightfield
|
||||
bool rcCreateHeightfield(rcContext* /*ctx*/, rcHeightfield& hf, int width, int height,
|
||||
bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height,
|
||||
const float* bmin, const float* bmax,
|
||||
float cs, float ch)
|
||||
{
|
||||
// TODO: VC complains about unref formal variable, figure out a way to handle this better.
|
||||
// rcAssert(ctx);
|
||||
rcIgnoreUnused(ctx);
|
||||
|
||||
hf.width = width;
|
||||
hf.height = height;
|
||||
@ -245,13 +244,12 @@ static void calcTriNormal(const float* v0, const float* v1, const float* v2, flo
|
||||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||
///
|
||||
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
|
||||
void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
|
||||
void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
|
||||
const float* verts, int /*nv*/,
|
||||
const int* tris, int nt,
|
||||
unsigned char* areas)
|
||||
{
|
||||
// TODO: VC complains about unref formal variable, figure out a way to handle this better.
|
||||
// rcAssert(ctx);
|
||||
rcIgnoreUnused(ctx);
|
||||
|
||||
const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
|
||||
|
||||
@ -275,13 +273,12 @@ void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
|
||||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||
///
|
||||
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
|
||||
void rcClearUnwalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
|
||||
void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
|
||||
const float* verts, int /*nv*/,
|
||||
const int* tris, int nt,
|
||||
unsigned char* areas)
|
||||
{
|
||||
// TODO: VC complains about unref formal variable, figure out a way to handle this better.
|
||||
// rcAssert(ctx);
|
||||
rcIgnoreUnused(ctx);
|
||||
|
||||
const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
|
||||
|
||||
@ -297,10 +294,9 @@ void rcClearUnwalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAng
|
||||
}
|
||||
}
|
||||
|
||||
int rcGetHeightFieldSpanCount(rcContext* /*ctx*/, rcHeightfield& hf)
|
||||
int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf)
|
||||
{
|
||||
// TODO: VC complains about unref formal variable, figure out a way to handle this better.
|
||||
// rcAssert(ctx);
|
||||
rcIgnoreUnused(ctx);
|
||||
|
||||
const int w = hf.width;
|
||||
const int h = hf.height;
|
||||
|
@ -735,7 +735,8 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
|
||||
}
|
||||
// Remove the polygon.
|
||||
unsigned short* p2 = &mesh.polys[(mesh.npolys-1)*nvp*2];
|
||||
memcpy(p,p2,sizeof(unsigned short)*nvp);
|
||||
if (p != p2)
|
||||
memcpy(p,p2,sizeof(unsigned short)*nvp);
|
||||
memset(p+nvp,0xff,sizeof(unsigned short)*nvp);
|
||||
mesh.regs[i] = mesh.regs[mesh.npolys-1];
|
||||
mesh.areas[i] = mesh.areas[mesh.npolys-1];
|
||||
@ -935,7 +936,9 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
|
||||
unsigned short* pa = &polys[bestPa*nvp];
|
||||
unsigned short* pb = &polys[bestPb*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];
|
||||
pareas[bestPb] = pareas[npolys-1];
|
||||
npolys--;
|
||||
@ -1395,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 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)
|
||||
{
|
||||
unsigned short* v = &pmesh->verts[j*3];
|
||||
@ -1415,6 +1424,36 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
|
||||
if (src[k] == RC_MESH_NULL_IDX) break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -839,7 +839,8 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void getHeightData(const rcCompactHeightfield& chf,
|
||||
|
||||
static void getHeightDataSeedsFromVertices(const rcCompactHeightfield& chf,
|
||||
const unsigned short* poly, const int npoly,
|
||||
const unsigned short* verts, const int bs,
|
||||
rcHeightPatch& hp, rcIntArray& stack)
|
||||
@ -967,8 +968,83 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
||||
int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width;
|
||||
const rcCompactSpan& cs = chf.spans[ci];
|
||||
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;
|
||||
int head = 0;
|
||||
|
||||
@ -993,26 +1069,25 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
||||
|
||||
const int ax = cx + rcGetDirOffsetX(dir);
|
||||
const int ay = cy + rcGetDirOffsetY(dir);
|
||||
const int hx = ax - hp.xmin - bs;
|
||||
const int hy = ay - hp.ymin - bs;
|
||||
|
||||
if (ax < hp.xmin || ax >= (hp.xmin+hp.width) ||
|
||||
ay < hp.ymin || ay >= (hp.ymin+hp.height))
|
||||
if (hx < 0 || hx >= hp.width || hy < 0 || hy >= hp.height)
|
||||
continue;
|
||||
|
||||
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;
|
||||
|
||||
const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir);
|
||||
|
||||
const int ai = (int)chf.cells[ax + ay*chf.width].index + rcGetCon(cs, dir);
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
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(ay);
|
||||
stack.push(ai);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static unsigned char getEdgeFlags(const float* va, const float* vb,
|
||||
@ -1170,7 +1245,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||
hp.ymin = bounds[i*4+2];
|
||||
hp.width = bounds[i*4+1]-bounds[i*4+0];
|
||||
hp.height = bounds[i*4+3]-bounds[i*4+2];
|
||||
getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack);
|
||||
getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack, mesh.regs[i]);
|
||||
|
||||
// Build detail mesh.
|
||||
int nverts = 0;
|
||||
@ -1340,4 +1415,3 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ static void addSpan(rcHeightfield& hf, const int x, const int y,
|
||||
s->area = area;
|
||||
s->next = 0;
|
||||
|
||||
// Empty cell, add he first span.
|
||||
// Empty cell, add the first span.
|
||||
if (!hf.spans[idx])
|
||||
{
|
||||
hf.spans[idx] = s;
|
||||
@ -169,36 +169,64 @@ void rcAddSpan(rcContext* /*ctx*/, rcHeightfield& hf, const int x, const int y,
|
||||
addSpan(hf, x,y, smin, smax, area, flagMergeThr);
|
||||
}
|
||||
|
||||
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];
|
||||
for (int i = 0; i < n; ++i)
|
||||
d[i] = pnx*in[i*3+0] + pnz*in[i*3+2] + pd;
|
||||
for (int i = 0; i < nin; ++i)
|
||||
d[i] = x - in[i*3+axis];
|
||||
|
||||
int m = 0;
|
||||
for (int i = 0, j = n-1; i < n; j=i, ++i)
|
||||
int m = 0, n = 0;
|
||||
for (int i = 0, j = nin-1; i < nin; j=i, ++i)
|
||||
{
|
||||
bool ina = d[j] >= 0;
|
||||
bool inb = d[i] >= 0;
|
||||
if (ina != inb)
|
||||
{
|
||||
float s = d[j] / (d[j] - d[i]);
|
||||
out[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
|
||||
out[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
|
||||
out[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
|
||||
out1[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
|
||||
out1[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
|
||||
out1[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
|
||||
rcVcopy(out2 + n*3, out1 + m*3);
|
||||
m++;
|
||||
n++;
|
||||
// add the i'th point to the right polygon. Do NOT add points that are on the dividing line
|
||||
// since these were already added above
|
||||
if (d[i] > 0)
|
||||
{
|
||||
rcVcopy(out1 + m*3, in + i*3);
|
||||
m++;
|
||||
}
|
||||
else if (d[i] < 0)
|
||||
{
|
||||
rcVcopy(out2 + n*3, in + i*3);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (inb)
|
||||
else // same side
|
||||
{
|
||||
out[m*3+0] = in[i*3+0];
|
||||
out[m*3+1] = in[i*3+1];
|
||||
out[m*3+2] = in[i*3+2];
|
||||
m++;
|
||||
// add the i'th point to the right polygon. Addition is done even for points on the dividing line
|
||||
if (d[i] >= 0)
|
||||
{
|
||||
rcVcopy(out1 + m*3, in + i*3);
|
||||
m++;
|
||||
if (d[i] != 0)
|
||||
continue;
|
||||
}
|
||||
rcVcopy(out2 + n*3, in + i*3);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
|
||||
*nout1 = m;
|
||||
*nout2 = n;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void rasterizeTri(const float* v0, const float* v1, const float* v2,
|
||||
const unsigned char area, rcHeightfield& hf,
|
||||
const float* bmin, const float* bmax,
|
||||
@ -222,48 +250,57 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2,
|
||||
if (!overlapBounds(bmin, bmax, tmin, tmax))
|
||||
return;
|
||||
|
||||
// Calculate the footpring of the triangle on the grid.
|
||||
int x0 = (int)((tmin[0] - bmin[0])*ics);
|
||||
// Calculate the footprint of the triangle on the grid's y-axis
|
||||
int y0 = (int)((tmin[2] - bmin[2])*ics);
|
||||
int x1 = (int)((tmax[0] - bmin[0])*ics);
|
||||
int y1 = (int)((tmax[2] - bmin[2])*ics);
|
||||
x0 = rcClamp(x0, 0, w-1);
|
||||
y0 = rcClamp(y0, 0, h-1);
|
||||
x1 = rcClamp(x1, 0, w-1);
|
||||
y1 = rcClamp(y1, 0, h-1);
|
||||
|
||||
// Clip the triangle into all grid cells it touches.
|
||||
float in[7*3], out[7*3], inrow[7*3];
|
||||
float buf[7*3*4];
|
||||
float *in = buf, *inrow = buf+7*3, *p1 = inrow+7*3, *p2 = p1+7*3;
|
||||
|
||||
rcVcopy(&in[0], v0);
|
||||
rcVcopy(&in[1*3], v1);
|
||||
rcVcopy(&in[2*3], v2);
|
||||
int nvrow, nvIn = 3;
|
||||
|
||||
for (int y = y0; y <= y1; ++y)
|
||||
{
|
||||
// Clip polygon to row.
|
||||
rcVcopy(&in[0], v0);
|
||||
rcVcopy(&in[1*3], v1);
|
||||
rcVcopy(&in[2*3], v2);
|
||||
int nvrow = 3;
|
||||
// Clip polygon to row. Store the remaining polygon as well
|
||||
const float cz = bmin[2] + y*cs;
|
||||
nvrow = clipPoly(in, nvrow, out, 0, 1, -cz);
|
||||
if (nvrow < 3) continue;
|
||||
nvrow = clipPoly(out, nvrow, inrow, 0, -1, cz+cs);
|
||||
dividePoly(in, nvIn, inrow, &nvrow, p1, &nvIn, cz+cs, 2);
|
||||
rcSwap(in, p1);
|
||||
if (nvrow < 3) continue;
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Clip polygon to column.
|
||||
int nv = nvrow;
|
||||
// Clip polygon to column. store the remaining polygon as well
|
||||
const float cx = bmin[0] + x*cs;
|
||||
nv = clipPoly(inrow, nv, out, 1, 0, -cx);
|
||||
if (nv < 3) continue;
|
||||
nv = clipPoly(out, nv, in, -1, 0, cx+cs);
|
||||
dividePoly(inrow, nv2, p1, &nv, p2, &nv2, cx+cs, 0);
|
||||
rcSwap(inrow, p2);
|
||||
if (nv < 3) continue;
|
||||
|
||||
// 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)
|
||||
{
|
||||
smin = rcMin(smin, in[i*3+1]);
|
||||
smax = rcMax(smax, in[i*3+1]);
|
||||
smin = rcMin(smin, p1[i*3+1]);
|
||||
smax = rcMax(smax, p1[i*3+1]);
|
||||
}
|
||||
smin -= bmin[1];
|
||||
smax -= bmin[1];
|
||||
|
@ -299,7 +299,10 @@ static bool floodRegion(int x, int y, int i,
|
||||
if (nr & RC_BORDER_REG) // Do not take borders into account.
|
||||
continue;
|
||||
if (nr != 0 && nr != r)
|
||||
{
|
||||
ar = nr;
|
||||
break;
|
||||
}
|
||||
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
|
||||
@ -313,7 +316,10 @@ static bool floodRegion(int x, int y, int i,
|
||||
continue;
|
||||
unsigned short nr2 = srcReg[ai2];
|
||||
if (nr2 != 0 && nr2 != r)
|
||||
{
|
||||
ar = nr2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -399,29 +405,43 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
|
||||
rcCompactHeightfield& chf,
|
||||
unsigned short* srcReg, unsigned short* srcDist,
|
||||
unsigned short* dstReg, unsigned short* dstDist,
|
||||
rcIntArray& stack)
|
||||
rcIntArray& stack,
|
||||
bool fillStack)
|
||||
{
|
||||
const int w = chf.width;
|
||||
const int h = chf.height;
|
||||
|
||||
// Find cells revealed by the raised level.
|
||||
stack.resize(0);
|
||||
for (int y = 0; y < h; ++y)
|
||||
if (fillStack)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
// Find cells revealed by the raised level.
|
||||
stack.resize(0);
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
const rcCompactCell& c = chf.cells[x+y*w];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
|
||||
const rcCompactCell& c = chf.cells[x+y*w];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
stack.push(x);
|
||||
stack.push(y);
|
||||
stack.push(i);
|
||||
if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
|
||||
{
|
||||
stack.push(x);
|
||||
stack.push(y);
|
||||
stack.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // use cells in the input stack
|
||||
{
|
||||
// mark all cells which already have a region
|
||||
for (int j=0; j<stack.size(); j+=3)
|
||||
{
|
||||
int i = stack[j+2];
|
||||
if (srcReg[i] != 0)
|
||||
stack[j+2] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int iter = 0;
|
||||
while (stack.size() > 0)
|
||||
@ -493,6 +513,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
|
||||
{
|
||||
inline rcRegion(unsigned short i) :
|
||||
@ -1531,6 +1606,12 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
|
||||
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 visited(1024);
|
||||
|
||||
@ -1565,14 +1646,25 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
chf.borderSize = borderSize;
|
||||
}
|
||||
|
||||
int sId = -1;
|
||||
while (level > 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);
|
||||
|
||||
// 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(srcDist, dstDist);
|
||||
@ -1583,18 +1675,15 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FLOOD);
|
||||
|
||||
// Mark new regions with IDs.
|
||||
for (int y = 0; y < h; ++y)
|
||||
for (int j=0; j<lvlStacks[sId].size(); j+=3)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
int x = lvlStacks[sId][j];
|
||||
int y = lvlStacks[sId][j+1];
|
||||
int i = lvlStacks[sId][j+2];
|
||||
if (i >= 0 && srcReg[i] == 0)
|
||||
{
|
||||
const rcCompactCell& c = chf.cells[x+y*w];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
if (chf.dist[i] < level || srcReg[i] != 0 || chf.areas[i] == RC_NULL_AREA)
|
||||
continue;
|
||||
if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
|
||||
regionId++;
|
||||
}
|
||||
if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
|
||||
regionId++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1602,7 +1691,7 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
}
|
||||
|
||||
// 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(srcDist, dstDist);
|
||||
|
6
RecastDemo/Bin/Tests/raycast_test.txt
Normal file
6
RecastDemo/Bin/Tests/raycast_test.txt
Normal file
@ -0,0 +1,6 @@
|
||||
s Tile Mesh
|
||||
f nav_test.obj
|
||||
rc 45.133884 -0.533207 -3.775568 47.078232 7.797605 14.293253 0xffef 0x0
|
||||
rc 52.979847 -2.778793 -2.914886 50.628868 -2.350212 13.917850 0xffef 0x0
|
||||
rc 45.209217 2.024442 1.838851 46.888412 7.797606 15.772338 0xffef 0x0
|
||||
rc 45.388317 -0.562073 -3.673226 46.651001 7.797606 15.513507 0xffef 0x0
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,5 @@
|
||||
// stb_truetype.h - v0.3 - public domain - 2009 Sean Barrett / RAD Game Tools
|
||||
// stb_truetype.h - v0.7 - public domain
|
||||
// authored from 2009-2013 by Sean Barrett / RAD Game Tools
|
||||
//
|
||||
// This library processes TrueType files:
|
||||
// parse files
|
||||
@ -9,20 +10,52 @@
|
||||
// Todo:
|
||||
// non-MS cmaps
|
||||
// crashproof on bad data
|
||||
// hinting
|
||||
// subpixel positioning when rendering bitmap
|
||||
// cleartype-style AA
|
||||
// hinting? (no longer patented)
|
||||
// cleartype-style AA?
|
||||
// optimize: use simple memory allocator for intermediates
|
||||
// optimize: build edge-list directly from curves
|
||||
// optimize: rasterize directly from curves?
|
||||
//
|
||||
// ADDITIONAL CONTRIBUTORS
|
||||
//
|
||||
// Mikko Mononen: compound shape support, more cmap formats
|
||||
// Tor Andersson: kerning, subpixel rendering
|
||||
//
|
||||
// VERSIONS
|
||||
// Bug/warning reports:
|
||||
// "Zer" on mollyrocket (with fix)
|
||||
// Cass Everitt
|
||||
// stoiko (Haemimont Games)
|
||||
// Brian Hook
|
||||
// Walter van Niftrik
|
||||
//
|
||||
// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM)
|
||||
// VERSION HISTORY
|
||||
//
|
||||
// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back
|
||||
// 0.6c (2012-07-24) improve documentation
|
||||
// 0.6b (2012-07-20) fix a few more warnings
|
||||
// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels,
|
||||
// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty
|
||||
// 0.5 (2011-12-09) bugfixes:
|
||||
// subpixel glyph renderer computed wrong bounding box
|
||||
// first vertex of shape can be off-curve (FreeSans)
|
||||
// 0.4b (2011-12-03) fixed an error in the font baking example
|
||||
// 0.4 (2011-12-01) kerning, subpixel rendering (tor)
|
||||
// bugfixes for:
|
||||
// codepoint-to-glyph conversion using table fmt=12
|
||||
// codepoint-to-glyph conversion using table fmt=4
|
||||
// stbtt_GetBakedQuad with non-square texture (Zer)
|
||||
// updated Hello World! sample to use kerning and subpixel
|
||||
// fixed some warnings
|
||||
// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM)
|
||||
// userdata, malloc-from-userdata, non-zero fill (STB)
|
||||
// 0.2 (2009-03-11) Fix unsigned/signed char warnings
|
||||
// 0.1 (2009-03-09) First public release
|
||||
// 0.2 (2009-03-11) Fix unsigned/signed char warnings
|
||||
// 0.1 (2009-03-09) First public release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// This software is in the public domain. Where that dedication is not
|
||||
// recognized, you are granted a perpetual, irrevokable license to copy
|
||||
// and modify this file as you see fit.
|
||||
//
|
||||
// USAGE
|
||||
//
|
||||
@ -32,8 +65,6 @@
|
||||
// before the #include of this file. This expands out the actual
|
||||
// implementation into that C/C++ file.
|
||||
//
|
||||
// Look at the header-file sections below for the API, but here's a quick skim:
|
||||
//
|
||||
// Simple 3D API (don't ship this, but it's fine for tools and quick start,
|
||||
// and you can cut and paste from it to move to more advanced)
|
||||
// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture
|
||||
@ -51,6 +82,83 @@
|
||||
// Character advance/positioning
|
||||
// stbtt_GetCodepointHMetrics()
|
||||
// stbtt_GetFontVMetrics()
|
||||
// stbtt_GetCodepointKernAdvance()
|
||||
//
|
||||
// ADDITIONAL DOCUMENTATION
|
||||
//
|
||||
// Immediately after this block comment are a series of sample programs.
|
||||
//
|
||||
// After the sample programs is the "header file" section. This section
|
||||
// includes documentation for each API function.
|
||||
//
|
||||
// Some important concepts to understand to use this library:
|
||||
//
|
||||
// Codepoint
|
||||
// Characters are defined by unicode codepoints, e.g. 65 is
|
||||
// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is
|
||||
// the hiragana for "ma".
|
||||
//
|
||||
// Glyph
|
||||
// A visual character shape (every codepoint is rendered as
|
||||
// some glyph)
|
||||
//
|
||||
// Glyph index
|
||||
// A font-specific integer ID representing a glyph
|
||||
//
|
||||
// Baseline
|
||||
// Glyph shapes are defined relative to a baseline, which is the
|
||||
// bottom of uppercase characters. Characters extend both above
|
||||
// and below the baseline.
|
||||
//
|
||||
// Current Point
|
||||
// As you draw text to the screen, you keep track of a "current point"
|
||||
// which is the origin of each character. The current point's vertical
|
||||
// position is the baseline. Even "baked fonts" use this model.
|
||||
//
|
||||
// Vertical Font Metrics
|
||||
// The vertical qualities of the font, used to vertically position
|
||||
// and space the characters. See docs for stbtt_GetFontVMetrics.
|
||||
//
|
||||
// Font Size in Pixels or Points
|
||||
// The preferred interface for specifying font sizes in stb_truetype
|
||||
// is to specify how tall the font's vertical extent should be in pixels.
|
||||
// If that sounds good enough, skip the next paragraph.
|
||||
//
|
||||
// Most font APIs instead use "points", which are a common typographic
|
||||
// measurement for describing font size, defined as 72 points per inch.
|
||||
// stb_truetype provides a point API for compatibility. However, true
|
||||
// "per inch" conventions don't make much sense on computer displays
|
||||
// since they different monitors have different number of pixels per
|
||||
// inch. For example, Windows traditionally uses a convention that
|
||||
// there are 96 pixels per inch, thus making 'inch' measurements have
|
||||
// nothing to do with inches, and thus effectively defining a point to
|
||||
// be 1.333 pixels. Additionally, the TrueType font data provides
|
||||
// an explicit scale factor to scale a given font's glyphs to points,
|
||||
// but the author has observed that this scale factor is often wrong
|
||||
// for non-commercial fonts, thus making fonts scaled in points
|
||||
// according to the TrueType spec incoherently sized in practice.
|
||||
//
|
||||
// ADVANCED USAGE
|
||||
//
|
||||
// Quality:
|
||||
//
|
||||
// - Use the functions with Subpixel at the end to allow your characters
|
||||
// to have subpixel positioning. Since the font is anti-aliased, not
|
||||
// hinted, this is very import for quality. (This is not possible with
|
||||
// baked fonts.)
|
||||
//
|
||||
// - Kerning is now supported, and if you're supporting subpixel rendering
|
||||
// then kerning is worth using to give your text a polished look.
|
||||
//
|
||||
// Performance:
|
||||
//
|
||||
// - Convert Unicode codepoints to glyph indexes and operate on the glyphs;
|
||||
// if you don't do this, stb_truetype is forced to do the conversion on
|
||||
// every call.
|
||||
//
|
||||
// - There are a lot of memory allocations. We should modify it to take
|
||||
// a temp buffer and allocate from the temp buffer (without freeing),
|
||||
// should help performance a lot.
|
||||
//
|
||||
// NOTES
|
||||
//
|
||||
@ -64,14 +172,14 @@
|
||||
// recommend it.
|
||||
//
|
||||
//
|
||||
// SOURCE STATISTICS (based on v0.3, 1800 LOC)
|
||||
// SOURCE STATISTICS (based on v0.6c, 2050 LOC)
|
||||
//
|
||||
// Documentation & header file 350 LOC \___ 500 LOC documentation
|
||||
// Documentation & header file 520 LOC \___ 660 LOC documentation
|
||||
// Sample code 140 LOC /
|
||||
// Truetype parsing 580 LOC ---- 600 LOC TrueType
|
||||
// Truetype parsing 620 LOC ---- 620 LOC TrueType
|
||||
// Software rasterization 240 LOC \ .
|
||||
// Curve tesselation 120 LOC \__ 500 LOC Bitmap creation
|
||||
// Bitmap management 70 LOC /
|
||||
// Curve tesselation 120 LOC \__ 550 LOC Bitmap creation
|
||||
// Bitmap management 100 LOC /
|
||||
// Baked bitmap interface 70 LOC /
|
||||
// Font name matching & access 150 LOC ---- 150
|
||||
// C runtime library abstraction 60 LOC ---- 60
|
||||
@ -92,7 +200,7 @@
|
||||
char ttf_buffer[1<<20];
|
||||
unsigned char temp_bitmap[512*512];
|
||||
|
||||
stbtt_chardata cdata[96]; // ASCII 32..126 is 95 glyphs
|
||||
stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs
|
||||
GLstbtt_uint ftex;
|
||||
|
||||
void my_stbtt_initfont(void)
|
||||
@ -177,33 +285,41 @@ int main(int argc, char **argv)
|
||||
// Complete program: print "Hello World!" banner, with bugs
|
||||
//
|
||||
#if 0
|
||||
char buffer[24<<20];
|
||||
unsigned char screen[20][79];
|
||||
|
||||
int main(int arg, char **argv)
|
||||
{
|
||||
unsigned char screen[20][79];
|
||||
int i,j, pos=0;
|
||||
float scale;
|
||||
stbtt_fontinfo font;
|
||||
int i,j,ascent,baseline,ch=0;
|
||||
float scale, xpos=0;
|
||||
char *text = "Heljo World!";
|
||||
|
||||
fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
|
||||
stbtt_InitFont(&font, buffer, 0);
|
||||
|
||||
scale = stbtt_ScaleForPixelHeight(&font, 16);
|
||||
memset(screen, 0, sizeof(screen));
|
||||
scale = stbtt_ScaleForPixelHeight(&font, 15);
|
||||
stbtt_GetFontVMetrics(&font, &ascent,0,0);
|
||||
baseline = (int) (ascent*scale);
|
||||
|
||||
while (*text) {
|
||||
int advance,lsb,x0,y0,x1,y1, newpos, baseline=13;
|
||||
stbtt_GetCodepointHMetrics(&font, *text, &advance, &lsb);
|
||||
stbtt_GetCodepointBitmapBox(&font, *text, scale,scale, &x0,&y0,&x1,&y1);
|
||||
newpos = pos + (int) (lsb * scale) + x0;
|
||||
stbtt_MakeCodepointBitmap(&font, &screen[baseline + y0][newpos], x1-x0,y1-y0, 79, scale,scale, *text);
|
||||
while (text[ch]) {
|
||||
int advance,lsb,x0,y0,x1,y1;
|
||||
float x_shift = xpos - (float) floor(xpos);
|
||||
stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);
|
||||
stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);
|
||||
stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);
|
||||
// note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong
|
||||
// because this API is really for baking character bitmaps into textures
|
||||
pos += (int) (advance * scale);
|
||||
++text;
|
||||
// because this API is really for baking character bitmaps into textures. if you want to render
|
||||
// a sequence of characters, you really need to render each bitmap to a temp buffer, then
|
||||
// "alpha blend" that into the working buffer
|
||||
xpos += (advance * scale);
|
||||
if (text[ch+1])
|
||||
xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);
|
||||
++ch;
|
||||
}
|
||||
|
||||
for (j=0; j < 20; ++j) {
|
||||
for (i=0; i < 79; ++i)
|
||||
for (i=0; i < 78; ++i)
|
||||
putchar(" .:ioVM@"[screen[j][i]>>5]);
|
||||
putchar('\n');
|
||||
}
|
||||
@ -216,8 +332,10 @@ int main(int arg, char **argv)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
////
|
||||
//// INTEGRATION WITH RUNTIME LIBRARIES
|
||||
//// INTEGRATION WITH YOUR CODEBASE
|
||||
////
|
||||
//// The following sections allow you to supply alternate definitions
|
||||
//// of C library functions used by stb_truetype.
|
||||
|
||||
#ifdef STB_TRUETYPE_IMPLEMENTATION
|
||||
// #define your own (u)stbtt_int8/16/32 before including to override this
|
||||
@ -320,6 +438,12 @@ extern void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, // sa
|
||||
int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier
|
||||
// Call GetBakedQuad with char_index = 'character - first_char', and it
|
||||
// creates the quad you need to draw and advances the current position.
|
||||
//
|
||||
// The coordinate system used assumes y increases downwards.
|
||||
//
|
||||
// Characters will extend both above and below the current position;
|
||||
// see discussion of "BASELINE" above.
|
||||
//
|
||||
// It's inefficient; you might want to c&p it and optimize it.
|
||||
|
||||
|
||||
@ -330,35 +454,35 @@ extern void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, // sa
|
||||
//
|
||||
|
||||
extern int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
|
||||
// Each .ttf file may have more than one font. Each has a sequential index
|
||||
// number starting from 0. Call this function to get the font offset for a
|
||||
// given index; it returns -1 if the index is out of range. A regular .ttf
|
||||
// Each .ttf/.ttc file may have more than one font. Each font has a sequential
|
||||
// index number starting from 0. Call this function to get the font offset for
|
||||
// a given index; it returns -1 if the index is out of range. A regular .ttf
|
||||
// file will only define one font and it always be at offset 0, so it will
|
||||
// return '0' for index 0, and -1 for all other indices. You can just skip
|
||||
// this step if you know it's that kind of font.
|
||||
|
||||
|
||||
// The following structure is defined publically so you can declare one on
|
||||
// the stack or as a global or etc.
|
||||
typedef struct
|
||||
// the stack or as a global or etc, but you should treat it as opaque.
|
||||
typedef struct stbtt_fontinfo
|
||||
{
|
||||
void *userdata;
|
||||
unsigned char *data; // pointer to .ttf file
|
||||
int fontstart; // offset of start of font
|
||||
void * userdata;
|
||||
unsigned char * data; // pointer to .ttf file
|
||||
int fontstart; // offset of start of font
|
||||
|
||||
int numGlyphs; // number of glyphs, needed for range checking
|
||||
int numGlyphs; // number of glyphs, needed for range checking
|
||||
|
||||
int loca,head,glyf,hhea,hmtx; // table locations as offset from start of .ttf
|
||||
int index_map; // a cmap mapping for our chosen character encoding
|
||||
int indexToLocFormat; // format needed to map from glyph index to glyph
|
||||
int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf
|
||||
int index_map; // a cmap mapping for our chosen character encoding
|
||||
int indexToLocFormat; // format needed to map from glyph index to glyph
|
||||
} stbtt_fontinfo;
|
||||
|
||||
extern int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
|
||||
// Given an offset into the file that defines a font, this function builds
|
||||
// the necessary cached info for the rest of the system. You must allocate
|
||||
// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
|
||||
// need to do anything special to free it, because the contents are a pure
|
||||
// cache with no additional data structures. Returns 0 on failure.
|
||||
// need to do anything special to free it, because the contents are pure
|
||||
// value data with no additional data structures. Returns 0 on failure.
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@ -385,12 +509,21 @@ extern float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels)
|
||||
// scale = pixels / (ascent - descent)
|
||||
// so if you prefer to measure height by the ascent only, use a similar calculation.
|
||||
|
||||
extern float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);
|
||||
// computes a scale factor to produce a font whose EM size is mapped to
|
||||
// 'pixels' tall. This is probably what traditional APIs compute, but
|
||||
// I'm not positive.
|
||||
|
||||
extern void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);
|
||||
// ascent is the coordinate above the baseline the font extends; descent
|
||||
// is the coordinate below the baseline the font extends (i.e. it is typically negative)
|
||||
// lineGap is the spacing between one row's descent and the next row's ascent...
|
||||
// so you should advance the vertical position by "*ascent - *descent + *lineGap"
|
||||
// these are expressed in unscaled coordinates
|
||||
// these are expressed in unscaled coordinates, so you must multiply by
|
||||
// the scale factor for a given size
|
||||
|
||||
extern void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
|
||||
// the bounding box around all possible characters
|
||||
|
||||
extern void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);
|
||||
// leftSideBearing is the offset from the current horizontal position to the left edge of the character
|
||||
@ -434,6 +567,9 @@ extern int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *
|
||||
} stbtt_vertex;
|
||||
#endif
|
||||
|
||||
extern int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);
|
||||
// returns non-zero if nothing is drawn for this glyph
|
||||
|
||||
extern int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);
|
||||
extern int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);
|
||||
// returns # of vertices and fills *vertices with the pointer to them
|
||||
@ -459,11 +595,19 @@ extern unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float
|
||||
//
|
||||
// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
|
||||
|
||||
extern unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
|
||||
// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
|
||||
// shift for the character
|
||||
|
||||
extern void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);
|
||||
// the same as above, but you pass in storage for the bitmap in the form
|
||||
// of 'output', with row spacing of 'out_stride' bytes. the bitmap is
|
||||
// clipped to out_w/out_h bytes. call the next function to get the
|
||||
// height and width and positioning info
|
||||
// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap
|
||||
// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap
|
||||
// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the
|
||||
// width and height and positioning info for it first.
|
||||
|
||||
extern void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);
|
||||
// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
|
||||
// shift for the character
|
||||
|
||||
extern void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
|
||||
// get the bbox of the bitmap centered around the glyph origin; so the
|
||||
@ -472,11 +616,19 @@ extern void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoin
|
||||
// (Note that the bitmap uses y-increases-down, but the shape uses
|
||||
// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
|
||||
|
||||
extern unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);
|
||||
extern void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
|
||||
extern void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
|
||||
extern void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
|
||||
// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel
|
||||
// shift for the character
|
||||
|
||||
// the following functions are equivalent to the above functions, but operate
|
||||
// on glyph indices instead of Unicode codepoints (for efficiency)
|
||||
extern unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);
|
||||
extern unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);
|
||||
extern void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
|
||||
extern void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);
|
||||
extern void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
|
||||
extern void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
|
||||
|
||||
//extern void stbtt_get_true_bbox(stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
|
||||
|
||||
// @TODO: don't expose this structure
|
||||
typedef struct
|
||||
@ -485,7 +637,7 @@ typedef struct
|
||||
unsigned char *pixels;
|
||||
} stbtt__bitmap;
|
||||
|
||||
extern void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, int x_off, int y_off, int invert, void *userdata);
|
||||
extern void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@ -524,7 +676,7 @@ extern int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const ch
|
||||
// returns 1/0 whether the first string interpreted as utf8 is identical to
|
||||
// the second string interpreted as big-endian utf16... useful for strings from next func
|
||||
|
||||
extern char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);
|
||||
extern const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);
|
||||
// returns the string (which may be big-endian double byte, e.g. for unicode)
|
||||
// and puts the length in bytes in *length.
|
||||
//
|
||||
@ -544,21 +696,21 @@ enum { // encodingID for STBTT_PLATFORM_ID_UNICODE
|
||||
STBTT_UNICODE_EID_UNICODE_1_1 =1,
|
||||
STBTT_UNICODE_EID_ISO_10646 =2,
|
||||
STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,
|
||||
STBTT_UNICODE_EID_UNICODE_2_0_FULL=4,
|
||||
STBTT_UNICODE_EID_UNICODE_2_0_FULL=4
|
||||
};
|
||||
|
||||
enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT
|
||||
STBTT_MS_EID_SYMBOL =0,
|
||||
STBTT_MS_EID_UNICODE_BMP =1,
|
||||
STBTT_MS_EID_SHIFTJIS =2,
|
||||
STBTT_MS_EID_UNICODE_FULL =10,
|
||||
STBTT_MS_EID_UNICODE_FULL =10
|
||||
};
|
||||
|
||||
enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes
|
||||
STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4,
|
||||
STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5,
|
||||
STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6,
|
||||
STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7,
|
||||
STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7
|
||||
};
|
||||
|
||||
enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...
|
||||
@ -568,7 +720,7 @@ enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...
|
||||
STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412,
|
||||
STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419,
|
||||
STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409,
|
||||
STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D,
|
||||
STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D
|
||||
};
|
||||
|
||||
enum { // languageID for STBTT_PLATFORM_ID_MAC
|
||||
@ -578,7 +730,7 @@ enum { // languageID for STBTT_PLATFORM_ID_MAC
|
||||
STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 ,
|
||||
STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 ,
|
||||
STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,
|
||||
STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19,
|
||||
STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -630,7 +782,7 @@ enum { // languageID for STBTT_PLATFORM_ID_MAC
|
||||
static int stbtt__isfont(const stbtt_uint8 *font)
|
||||
{
|
||||
// check the version number
|
||||
if (stbtt_tag(font, "1")) return 1; // TrueType 1
|
||||
if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1
|
||||
if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this!
|
||||
if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF
|
||||
if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0
|
||||
@ -679,12 +831,13 @@ int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data2, int fontsta
|
||||
info->data = data;
|
||||
info->fontstart = fontstart;
|
||||
|
||||
cmap = stbtt__find_table(data, fontstart, "cmap");
|
||||
info->loca = stbtt__find_table(data, fontstart, "loca");
|
||||
info->head = stbtt__find_table(data, fontstart, "head");
|
||||
info->glyf = stbtt__find_table(data, fontstart, "glyf");
|
||||
info->hhea = stbtt__find_table(data, fontstart, "hhea");
|
||||
info->hmtx = stbtt__find_table(data, fontstart, "hmtx");
|
||||
cmap = stbtt__find_table(data, fontstart, "cmap"); // required
|
||||
info->loca = stbtt__find_table(data, fontstart, "loca"); // required
|
||||
info->head = stbtt__find_table(data, fontstart, "head"); // required
|
||||
info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required
|
||||
info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required
|
||||
info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
|
||||
info->kern = stbtt__find_table(data, fontstart, "kern"); // not required
|
||||
if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx)
|
||||
return 0;
|
||||
|
||||
@ -746,7 +899,7 @@ int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)
|
||||
stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;
|
||||
stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);
|
||||
stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;
|
||||
stbtt_uint16 item, offset, start, end;
|
||||
stbtt_uint16 item, offset, start;
|
||||
|
||||
// do a binary search of the segments
|
||||
stbtt_uint32 endCount = index_map + 14;
|
||||
@ -763,11 +916,9 @@ int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)
|
||||
// now decrement to bias correctly to find smallest
|
||||
search -= 2;
|
||||
while (entrySelector) {
|
||||
stbtt_uint16 start, end;
|
||||
stbtt_uint16 end;
|
||||
searchRange >>= 1;
|
||||
start = ttUSHORT(data + search + 2 + segcount*2 + 2);
|
||||
end = ttUSHORT(data + search + 2);
|
||||
start = ttUSHORT(data + search + searchRange*2 + segcount*2 + 2);
|
||||
end = ttUSHORT(data + search + searchRange*2);
|
||||
if (unicode_codepoint > end)
|
||||
search += searchRange*2;
|
||||
@ -779,31 +930,33 @@ int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)
|
||||
|
||||
STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
|
||||
start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
|
||||
end = ttUSHORT(data + index_map + 14 + 2 + 2*item);
|
||||
if (unicode_codepoint < start)
|
||||
return 0;
|
||||
|
||||
offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
|
||||
if (offset == 0)
|
||||
return unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item);
|
||||
return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
|
||||
|
||||
return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
|
||||
} else if (format == 12) {
|
||||
stbtt_uint16 ngroups = ttUSHORT(data+index_map+6);
|
||||
} else if (format == 12 || format == 13) {
|
||||
stbtt_uint32 ngroups = ttULONG(data+index_map+12);
|
||||
stbtt_int32 low,high;
|
||||
low = 0; high = (stbtt_int32)ngroups;
|
||||
// Binary search the right group.
|
||||
while (low <= high) {
|
||||
while (low < high) {
|
||||
stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high
|
||||
stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);
|
||||
stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);
|
||||
if ((stbtt_uint32) unicode_codepoint < start_char)
|
||||
high = mid-1;
|
||||
high = mid;
|
||||
else if ((stbtt_uint32) unicode_codepoint > end_char)
|
||||
low = mid+1;
|
||||
else {
|
||||
stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);
|
||||
return start_glyph + unicode_codepoint-start_char;
|
||||
if (format == 12)
|
||||
return start_glyph + unicode_codepoint-start_char;
|
||||
else // format == 13
|
||||
return start_glyph;
|
||||
}
|
||||
}
|
||||
return 0; // not found
|
||||
@ -818,13 +971,13 @@ int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, s
|
||||
return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);
|
||||
}
|
||||
|
||||
static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int16 x, stbtt_int16 y, stbtt_int16 cx, stbtt_int16 cy)
|
||||
static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)
|
||||
{
|
||||
v->type = type;
|
||||
v->x = x;
|
||||
v->y = y;
|
||||
v->cx = cx;
|
||||
v->cy = cy;
|
||||
v->x = (stbtt_int16) x;
|
||||
v->y = (stbtt_int16) y;
|
||||
v->cx = (stbtt_int16) cx;
|
||||
v->cy = (stbtt_int16) cy;
|
||||
}
|
||||
|
||||
static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)
|
||||
@ -862,6 +1015,31 @@ int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, in
|
||||
return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);
|
||||
}
|
||||
|
||||
int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)
|
||||
{
|
||||
stbtt_int16 numberOfContours;
|
||||
int g = stbtt__GetGlyfOffset(info, glyph_index);
|
||||
if (g < 0) return 1;
|
||||
numberOfContours = ttSHORT(info->data + g);
|
||||
return numberOfContours == 0;
|
||||
}
|
||||
|
||||
static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,
|
||||
stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)
|
||||
{
|
||||
if (start_off) {
|
||||
if (was_off)
|
||||
stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
|
||||
stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);
|
||||
} else {
|
||||
if (was_off)
|
||||
stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);
|
||||
else
|
||||
stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);
|
||||
}
|
||||
return num_vertices;
|
||||
}
|
||||
|
||||
int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
|
||||
{
|
||||
stbtt_int16 numberOfContours;
|
||||
@ -879,8 +1057,8 @@ int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_verte
|
||||
|
||||
if (numberOfContours > 0) {
|
||||
stbtt_uint8 flags=0,flagcount;
|
||||
stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off;
|
||||
stbtt_int16 x,y,cx,cy,sx,sy;
|
||||
stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
|
||||
stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;
|
||||
stbtt_uint8 *points;
|
||||
endPtsOfContours = (data + g + 10);
|
||||
ins = ttUSHORT(data + g + 10 + numberOfContours * 2);
|
||||
@ -888,7 +1066,7 @@ int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_verte
|
||||
|
||||
n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);
|
||||
|
||||
m = n + numberOfContours; // a loose bound on how many vertices we might need
|
||||
m = n + 2*numberOfContours; // a loose bound on how many vertices we might need
|
||||
vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);
|
||||
if (vertices == 0)
|
||||
return 0;
|
||||
@ -927,7 +1105,7 @@ int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_verte
|
||||
points += 2;
|
||||
}
|
||||
}
|
||||
vertices[off+i].x = x;
|
||||
vertices[off+i].x = (stbtt_int16) x;
|
||||
}
|
||||
|
||||
// now load y coordinates
|
||||
@ -943,32 +1121,46 @@ int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_verte
|
||||
points += 2;
|
||||
}
|
||||
}
|
||||
vertices[off+i].y = y;
|
||||
vertices[off+i].y = (stbtt_int16) y;
|
||||
}
|
||||
|
||||
// now convert them to our format
|
||||
num_vertices=0;
|
||||
sx = sy = cx = cy = 0;
|
||||
sx = sy = cx = cy = scx = scy = 0;
|
||||
for (i=0; i < n; ++i) {
|
||||
flags = vertices[off+i].type;
|
||||
x = (stbtt_int16) vertices[off+i].x;
|
||||
y = (stbtt_int16) vertices[off+i].y;
|
||||
|
||||
if (next_move == i) {
|
||||
// when we get to the end, we have to close the shape explicitly
|
||||
if (i != 0) {
|
||||
if (was_off)
|
||||
stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);
|
||||
else
|
||||
stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);
|
||||
}
|
||||
if (i != 0)
|
||||
num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
|
||||
|
||||
// now start the new one
|
||||
stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,x,y,0,0);
|
||||
start_off = !(flags & 1);
|
||||
if (start_off) {
|
||||
// if we start off with an off-curve point, then when we need to find a point on the curve
|
||||
// where we can start, and we need to save some state for when we wraparound.
|
||||
scx = x;
|
||||
scy = y;
|
||||
if (!(vertices[off+i+1].type & 1)) {
|
||||
// next point is also a curve point, so interpolate an on-point curve
|
||||
sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;
|
||||
sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;
|
||||
} else {
|
||||
// otherwise just use the next point as our start point
|
||||
sx = (stbtt_int32) vertices[off+i+1].x;
|
||||
sy = (stbtt_int32) vertices[off+i+1].y;
|
||||
++i; // we're using point i+1 as the starting point, so skip it
|
||||
}
|
||||
} else {
|
||||
sx = x;
|
||||
sy = y;
|
||||
}
|
||||
stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);
|
||||
was_off = 0;
|
||||
next_move = 1 + ttUSHORT(endPtsOfContours+j*2);
|
||||
++j;
|
||||
was_off = 0;
|
||||
sx = x;
|
||||
sy = y;
|
||||
} else {
|
||||
if (!(flags & 1)) { // if it's a curve
|
||||
if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint
|
||||
@ -985,12 +1177,7 @@ int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_verte
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i != 0) {
|
||||
if (was_off)
|
||||
stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);
|
||||
else
|
||||
stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);
|
||||
}
|
||||
num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
|
||||
} else if (numberOfContours == -1) {
|
||||
// Compound shapes.
|
||||
int more = 1;
|
||||
@ -1091,14 +1278,41 @@ void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *ad
|
||||
}
|
||||
}
|
||||
|
||||
int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo * /*info*/, int /*glyph1*/, int /*glyph2*/)
|
||||
int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
|
||||
{
|
||||
stbtt_uint8 *data = info->data + info->kern;
|
||||
stbtt_uint32 needle, straw;
|
||||
int l, r, m;
|
||||
|
||||
// we only look at the first table. it must be 'horizontal' and format 0.
|
||||
if (!info->kern)
|
||||
return 0;
|
||||
if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
|
||||
return 0;
|
||||
if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
|
||||
return 0;
|
||||
|
||||
l = 0;
|
||||
r = ttUSHORT(data+10) - 1;
|
||||
needle = glyph1 << 16 | glyph2;
|
||||
while (l <= r) {
|
||||
m = (l + r) >> 1;
|
||||
straw = ttULONG(data+18+(m*6)); // note: unaligned read
|
||||
if (needle < straw)
|
||||
r = m - 1;
|
||||
else if (needle > straw)
|
||||
l = m + 1;
|
||||
else
|
||||
return ttSHORT(data+22+(m*6));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo * /*info*/, int /*ch1*/, int /*ch2*/)
|
||||
int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)
|
||||
{
|
||||
return 0;
|
||||
if (!info->kern) // if no kerning table, don't waste time looking up both codepoint->glyphs
|
||||
return 0;
|
||||
return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
|
||||
}
|
||||
|
||||
void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)
|
||||
@ -1113,12 +1327,26 @@ void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent
|
||||
if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);
|
||||
}
|
||||
|
||||
void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)
|
||||
{
|
||||
*x0 = ttSHORT(info->data + info->head + 36);
|
||||
*y0 = ttSHORT(info->data + info->head + 38);
|
||||
*x1 = ttSHORT(info->data + info->head + 40);
|
||||
*y1 = ttSHORT(info->data + info->head + 42);
|
||||
}
|
||||
|
||||
float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)
|
||||
{
|
||||
int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);
|
||||
return (float) height / fheight;
|
||||
}
|
||||
|
||||
float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels)
|
||||
{
|
||||
int unitsPerEm = ttUSHORT(info->data + info->head + 18);
|
||||
return pixels / unitsPerEm;
|
||||
}
|
||||
|
||||
void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
|
||||
{
|
||||
STBTT_free(v, info->userdata);
|
||||
@ -1129,21 +1357,30 @@ void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
|
||||
// antialiasing software rasterizer
|
||||
//
|
||||
|
||||
void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
|
||||
void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
|
||||
{
|
||||
int x0,y0,x1,y1;
|
||||
if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1))
|
||||
x0=y0=x1=y1=0; // e.g. space character
|
||||
// now move to integral bboxes (treating pixels as little squares, what pixels get touched)?
|
||||
if (ix0) *ix0 = STBTT_ifloor(x0 * scale_x);
|
||||
if (iy0) *iy0 = -STBTT_iceil (y1 * scale_y);
|
||||
if (ix1) *ix1 = STBTT_iceil (x1 * scale_x);
|
||||
if (iy1) *iy1 = -STBTT_ifloor(y0 * scale_y);
|
||||
if (ix0) *ix0 = STBTT_ifloor(x0 * scale_x + shift_x);
|
||||
if (iy0) *iy0 = -STBTT_iceil (y1 * scale_y + shift_y);
|
||||
if (ix1) *ix1 = STBTT_iceil (x1 * scale_x + shift_x);
|
||||
if (iy1) *iy1 = -STBTT_ifloor(y0 * scale_y + shift_y);
|
||||
}
|
||||
void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
|
||||
{
|
||||
stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
|
||||
}
|
||||
|
||||
void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
|
||||
{
|
||||
stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);
|
||||
}
|
||||
|
||||
void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
|
||||
{
|
||||
stbtt_GetGlyphBitmapBox(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y, ix0,iy0,ix1,iy1);
|
||||
stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);
|
||||
}
|
||||
|
||||
typedef struct stbtt__edge {
|
||||
@ -1343,7 +1580,7 @@ typedef struct
|
||||
float x,y;
|
||||
} stbtt__point;
|
||||
|
||||
static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, int off_x, int off_y, int invert, void *userdata)
|
||||
static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata)
|
||||
{
|
||||
float y_scale_inv = invert ? -scale_y : scale_y;
|
||||
stbtt__edge *e;
|
||||
@ -1376,10 +1613,10 @@ static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcou
|
||||
e[n].invert = 1;
|
||||
a=j,b=k;
|
||||
}
|
||||
e[n].x0 = p[a].x * scale_x;
|
||||
e[n].y0 = p[a].y * y_scale_inv * vsubsample;
|
||||
e[n].x1 = p[b].x * scale_x;
|
||||
e[n].y1 = p[b].y * y_scale_inv * vsubsample;
|
||||
e[n].x0 = p[a].x * scale_x + shift_x;
|
||||
e[n].y0 = p[a].y * y_scale_inv * vsubsample + shift_y;
|
||||
e[n].x1 = p[b].x * scale_x + shift_x;
|
||||
e[n].y1 = p[b].y * y_scale_inv * vsubsample + shift_y;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
@ -1491,13 +1728,13 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, int x_off, int y_off, int invert, void *userdata)
|
||||
void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
|
||||
{
|
||||
float scale = scale_x > scale_y ? scale_y : scale_x;
|
||||
int winding_count, *winding_lengths;
|
||||
stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
|
||||
if (windings) {
|
||||
stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, x_off, y_off, invert, userdata);
|
||||
stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
|
||||
STBTT_free(winding_lengths, userdata);
|
||||
STBTT_free(windings, userdata);
|
||||
}
|
||||
@ -1508,7 +1745,7 @@ void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)
|
||||
STBTT_free(bitmap, userdata);
|
||||
}
|
||||
|
||||
unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
|
||||
unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)
|
||||
{
|
||||
int ix0,iy0,ix1,iy1;
|
||||
stbtt__bitmap gbm;
|
||||
@ -1521,7 +1758,7 @@ unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, f
|
||||
scale_y = scale_x;
|
||||
}
|
||||
|
||||
stbtt_GetGlyphBitmapBox(info, glyph, scale_x, scale_y, &ix0,&iy0,&ix1,&iy1);
|
||||
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);
|
||||
|
||||
// now we get the size
|
||||
gbm.w = (ix1 - ix0);
|
||||
@ -1538,47 +1775,67 @@ unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, f
|
||||
if (gbm.pixels) {
|
||||
gbm.stride = gbm.w;
|
||||
|
||||
stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, ix0, iy0, 1, info->userdata);
|
||||
stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);
|
||||
}
|
||||
}
|
||||
STBTT_free(vertices, info->userdata);
|
||||
return gbm.pixels;
|
||||
}
|
||||
|
||||
void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)
|
||||
unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
|
||||
{
|
||||
return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);
|
||||
}
|
||||
|
||||
void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)
|
||||
{
|
||||
int ix0,iy0;
|
||||
stbtt_vertex *vertices;
|
||||
int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
|
||||
stbtt__bitmap gbm;
|
||||
|
||||
stbtt_GetGlyphBitmapBox(info, glyph, scale_x, scale_y, &ix0,&iy0,0,0);
|
||||
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);
|
||||
gbm.pixels = output;
|
||||
gbm.w = out_w;
|
||||
gbm.h = out_h;
|
||||
gbm.stride = out_stride;
|
||||
|
||||
if (gbm.w && gbm.h)
|
||||
stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, ix0,iy0, 1, info->userdata);
|
||||
stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);
|
||||
|
||||
STBTT_free(vertices, info->userdata);
|
||||
}
|
||||
|
||||
void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)
|
||||
{
|
||||
stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);
|
||||
}
|
||||
|
||||
unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
|
||||
{
|
||||
return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
|
||||
}
|
||||
|
||||
void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)
|
||||
{
|
||||
stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
|
||||
}
|
||||
|
||||
unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
|
||||
{
|
||||
return stbtt_GetGlyphBitmap(info, scale_x, scale_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
|
||||
return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
|
||||
}
|
||||
|
||||
void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)
|
||||
{
|
||||
stbtt_MakeGlyphBitmap(info, output, out_w, out_h, out_stride, scale_x, scale_y, stbtt_FindGlyphIndex(info,codepoint));
|
||||
stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// bitmap baking
|
||||
//
|
||||
// This is SUPER-SHITTY packing to keep source code small
|
||||
// This is SUPER-CRAPPY packing to keep source code small
|
||||
|
||||
extern int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf)
|
||||
float pixel_height, // height of font in pixels
|
||||
@ -1638,8 +1895,8 @@ void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_inde
|
||||
q->y1 = round_y + b->y1 - b->y0 + d3d_bias;
|
||||
|
||||
q->s0 = b->x0 * ipw;
|
||||
q->t0 = b->y0 * ipw;
|
||||
q->s1 = b->x1 * iph;
|
||||
q->t0 = b->y0 * iph;
|
||||
q->s1 = b->x1 * ipw;
|
||||
q->t1 = b->y1 * iph;
|
||||
|
||||
*xpos += b->xadvance;
|
||||
@ -1651,7 +1908,7 @@ void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_inde
|
||||
//
|
||||
|
||||
// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string
|
||||
static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
|
||||
static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const stbtt_uint8 *s1, stbtt_int32 len1, const stbtt_uint8 *s2, stbtt_int32 len2)
|
||||
{
|
||||
stbtt_int32 i=0;
|
||||
|
||||
@ -1692,12 +1949,12 @@ static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, s
|
||||
|
||||
int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)
|
||||
{
|
||||
return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);
|
||||
return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((const stbtt_uint8*) s1, len1, (const stbtt_uint8*) s2, len2);
|
||||
}
|
||||
|
||||
// returns results in whatever encoding you request... but note that 2-byte encodings
|
||||
// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare
|
||||
char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)
|
||||
const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)
|
||||
{
|
||||
stbtt_int32 i,count,stringOffset;
|
||||
stbtt_uint8 *fc = font->data;
|
||||
@ -1712,7 +1969,7 @@ char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platf
|
||||
if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)
|
||||
&& languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {
|
||||
*length = ttUSHORT(fc+loc+8);
|
||||
return (char *) (fc+stringOffset+ttUSHORT(fc+loc+10));
|
||||
return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@ -1765,7 +2022,7 @@ static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name,
|
||||
|
||||
static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)
|
||||
{
|
||||
stbtt_int32 nlen = STBTT_strlen((char *) name);
|
||||
stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);
|
||||
stbtt_uint32 nm,hd;
|
||||
if (!stbtt__isfont(fc+offset)) return 0;
|
||||
|
||||
|
@ -26,6 +26,7 @@ class TestCase
|
||||
enum TestType
|
||||
{
|
||||
TEST_PATHFIND,
|
||||
TEST_RAYCAST,
|
||||
};
|
||||
|
||||
struct Test
|
||||
@ -39,6 +40,7 @@ class TestCase
|
||||
|
||||
TestType type;
|
||||
float spos[3], epos[3];
|
||||
float nspos[3], nepos[3];
|
||||
float radius;
|
||||
int includeFlags, excludeFlags;
|
||||
bool expand;
|
||||
|
@ -155,7 +155,7 @@ void CrowdToolState::init(class Sample* sample)
|
||||
crowd->init(MAX_AGENTS, m_sample->getAgentRadius(), nav);
|
||||
|
||||
// Make polygons with 'disabled' flag invalid.
|
||||
crowd->getEditableFilter()->setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED);
|
||||
crowd->getEditableFilter(0)->setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED);
|
||||
|
||||
// Setup local avoidance params to different qualities.
|
||||
dtObstacleAvoidanceParams params;
|
||||
@ -707,7 +707,7 @@ void CrowdToolState::setMoveTarget(const float* p, bool adjust)
|
||||
// Find nearest point on navmesh and set move request to that location.
|
||||
dtNavMeshQuery* navquery = m_sample->getNavMeshQuery();
|
||||
dtCrowd* crowd = m_sample->getCrowd();
|
||||
const dtQueryFilter* filter = crowd->getFilter();
|
||||
const dtQueryFilter* filter = crowd->getFilter(0);
|
||||
const float* ext = crowd->getQueryExtents();
|
||||
|
||||
if (adjust)
|
||||
@ -1068,6 +1068,7 @@ void CrowdTool::handleToggle()
|
||||
|
||||
void CrowdTool::handleUpdate(const float dt)
|
||||
{
|
||||
rcIgnoreUnused(dt);
|
||||
}
|
||||
|
||||
void CrowdTool::handleRender()
|
||||
@ -1076,6 +1077,9 @@ void CrowdTool::handleRender()
|
||||
|
||||
void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view)
|
||||
{
|
||||
rcIgnoreUnused(model);
|
||||
rcIgnoreUnused(proj);
|
||||
|
||||
// Tool help
|
||||
const int h = view[3];
|
||||
int ty = h-40;
|
||||
|
@ -174,8 +174,12 @@ bool InputGeom::load(rcContext* ctx, const char* filePath)
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
fread(buf, bufSize, 1, fp);
|
||||
size_t readLen = fread(buf, bufSize, 1, fp);
|
||||
fclose(fp);
|
||||
if (readLen != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_offMeshConCount = 0;
|
||||
m_volumeCount = 0;
|
||||
|
@ -78,7 +78,6 @@ void rcMeshLoaderObj::addTriangle(int a, int b, int c, int& cap)
|
||||
|
||||
static char* parseRow(char* buf, char* bufEnd, char* row, int len)
|
||||
{
|
||||
bool cont = false;
|
||||
bool start = true;
|
||||
bool done = false;
|
||||
int n = 0;
|
||||
@ -90,7 +89,6 @@ static char* parseRow(char* buf, char* bufEnd, char* row, int len)
|
||||
switch (c)
|
||||
{
|
||||
case '\\':
|
||||
cont = true; // multirow
|
||||
break;
|
||||
case '\n':
|
||||
if (start) break;
|
||||
@ -103,7 +101,6 @@ static char* parseRow(char* buf, char* bufEnd, char* row, int len)
|
||||
if (start) break;
|
||||
default:
|
||||
start = false;
|
||||
cont = false;
|
||||
row[n++] = c;
|
||||
if (n >= len-1)
|
||||
done = true;
|
||||
@ -153,9 +150,14 @@ bool rcMeshLoaderObj::load(const char* filename)
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
fread(buf, bufSize, 1, fp);
|
||||
size_t readLen = fread(buf, bufSize, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
if (readLen != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char* src = buf;
|
||||
char* srcEnd = buf + bufSize;
|
||||
char row[512];
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
}
|
||||
m_size = n;
|
||||
}
|
||||
inline void push(int item) { resize(m_size+1); m_data[m_size-1] = item; }
|
||||
inline void push(dtPolyRef item) { resize(m_size+1); m_data[m_size-1] = item; }
|
||||
inline dtPolyRef pop() { if (m_size > 0) m_size--; return m_data[m_size]; }
|
||||
inline const dtPolyRef& operator[](int i) const { return m_data[i]; }
|
||||
inline dtPolyRef& operator[](int i) { return m_data[i]; }
|
||||
@ -261,8 +261,11 @@ void NavMeshPruneTool::handleMenu()
|
||||
}
|
||||
}
|
||||
|
||||
void NavMeshPruneTool::handleClick(const float* /*s*/, const float* p, bool shift)
|
||||
void NavMeshPruneTool::handleClick(const float* s, const float* p, bool shift)
|
||||
{
|
||||
rcIgnoreUnused(s);
|
||||
rcIgnoreUnused(shift);
|
||||
|
||||
if (!m_sample) return;
|
||||
InputGeom* geom = m_sample->getInputGeom();
|
||||
if (!geom) return;
|
||||
@ -341,9 +344,11 @@ void NavMeshPruneTool::handleRender()
|
||||
|
||||
void NavMeshPruneTool::handleRenderOverlay(double* proj, double* model, int* view)
|
||||
{
|
||||
rcIgnoreUnused(model);
|
||||
rcIgnoreUnused(proj);
|
||||
|
||||
// Tool help
|
||||
const int h = view[3];
|
||||
|
||||
imguiDrawText(280, h-40, IMGUI_ALIGN_LEFT, "LMB: Click fill area.", imguiRGBA(255,255,255,192));
|
||||
|
||||
}
|
||||
|
@ -101,6 +101,66 @@ static int fixupCorridor(dtPolyRef* path, const int npath, const int maxPath,
|
||||
return req+size;
|
||||
}
|
||||
|
||||
// This function checks if the path has a small U-turn, that is,
|
||||
// a polygon further in the path is adjacent to the first polygon
|
||||
// in the path. If that happens, a shortcut is taken.
|
||||
// This can happen if the target (T) location is at tile boundary,
|
||||
// and we're (S) approaching it parallel to the tile edge.
|
||||
// The choice at the vertex can be arbitrary,
|
||||
// +---+---+
|
||||
// |:::|:::|
|
||||
// +-S-+-T-+
|
||||
// |:::| | <-- the step can end up in here, resulting U-turn path.
|
||||
// +---+---+
|
||||
static int fixupShortcuts(dtPolyRef* path, int npath, dtNavMeshQuery* navQuery)
|
||||
{
|
||||
if (npath < 3)
|
||||
return npath;
|
||||
|
||||
// Get connected polygons
|
||||
static const int maxNeis = 16;
|
||||
dtPolyRef neis[maxNeis];
|
||||
int nneis = 0;
|
||||
|
||||
const dtMeshTile* tile = 0;
|
||||
const dtPoly* poly = 0;
|
||||
if (dtStatusFailed(navQuery->getAttachedNavMesh()->getTileAndPolyByRef(path[0], &tile, &poly)))
|
||||
return npath;
|
||||
|
||||
for (unsigned int k = poly->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
|
||||
{
|
||||
const dtLink* link = &tile->links[k];
|
||||
if (link->ref != 0)
|
||||
{
|
||||
if (nneis < maxNeis)
|
||||
neis[nneis++] = link->ref;
|
||||
}
|
||||
}
|
||||
|
||||
// If any of the neighbour polygons is within the next few polygons
|
||||
// in the path, short cut to that polygon directly.
|
||||
static const int maxLookAhead = 6;
|
||||
int cut = 0;
|
||||
for (int i = dtMin(maxLookAhead, npath) - 1; i > 1 && cut == 0; i--) {
|
||||
for (int j = 0; j < nneis; j++)
|
||||
{
|
||||
if (path[i] == neis[j]) {
|
||||
cut = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cut > 1)
|
||||
{
|
||||
int offset = cut-1;
|
||||
npath -= offset;
|
||||
for (int i = 1; i < npath; i++)
|
||||
path[i] = path[i+offset];
|
||||
}
|
||||
|
||||
return npath;
|
||||
}
|
||||
|
||||
static bool getSteerTarget(dtNavMeshQuery* navQuery, const float* startPos, const float* endPos,
|
||||
const float minTargetDist,
|
||||
const dtPolyRef* path, const int pathSize,
|
||||
@ -446,8 +506,8 @@ void NavMeshTesterTool::handleToggle()
|
||||
if (m_pathIterPolyCount)
|
||||
{
|
||||
// Iterate over the path to find smooth path on the detail mesh surface.
|
||||
m_navQuery->closestPointOnPoly(m_startRef, m_spos, m_iterPos);
|
||||
m_navQuery->closestPointOnPoly(m_pathIterPolys[m_pathIterPolyCount-1], m_epos, m_targetPos);
|
||||
m_navQuery->closestPointOnPoly(m_startRef, m_spos, m_iterPos, 0);
|
||||
m_navQuery->closestPointOnPoly(m_pathIterPolys[m_pathIterPolyCount-1], m_epos, m_targetPos, 0);
|
||||
|
||||
m_nsmoothPath = 0;
|
||||
|
||||
@ -503,6 +563,8 @@ void NavMeshTesterTool::handleToggle()
|
||||
m_navQuery->moveAlongSurface(m_pathIterPolys[0], m_iterPos, moveTgt, &m_filter,
|
||||
result, visited, &nvisited, 16);
|
||||
m_pathIterPolyCount = fixupCorridor(m_pathIterPolys, m_pathIterPolyCount, MAX_POLYS, visited, nvisited);
|
||||
m_pathIterPolyCount = fixupShortcuts(m_pathIterPolys, m_pathIterPolyCount, m_navQuery);
|
||||
|
||||
float h = 0;
|
||||
m_navQuery->getPolyHeight(m_pathIterPolys[0], result, &h);
|
||||
result[1] = h;
|
||||
@ -588,7 +650,7 @@ void NavMeshTesterTool::handleUpdate(const float /*dt*/)
|
||||
float epos[3];
|
||||
dtVcopy(epos, m_epos);
|
||||
if (m_polys[m_npolys-1] != m_endRef)
|
||||
m_navQuery->closestPointOnPoly(m_polys[m_npolys-1], m_epos, epos);
|
||||
m_navQuery->closestPointOnPoly(m_polys[m_npolys-1], m_epos, epos, 0);
|
||||
|
||||
m_navQuery->findStraightPath(m_spos, epos, m_polys, m_npolys,
|
||||
m_straightPath, m_straightPathFlags,
|
||||
@ -653,8 +715,8 @@ void NavMeshTesterTool::recalc()
|
||||
int npolys = m_npolys;
|
||||
|
||||
float iterPos[3], targetPos[3];
|
||||
m_navQuery->closestPointOnPoly(m_startRef, m_spos, iterPos);
|
||||
m_navQuery->closestPointOnPoly(polys[npolys-1], m_epos, targetPos);
|
||||
m_navQuery->closestPointOnPoly(m_startRef, m_spos, iterPos, 0);
|
||||
m_navQuery->closestPointOnPoly(polys[npolys-1], m_epos, targetPos, 0);
|
||||
|
||||
static const float STEP_SIZE = 0.5f;
|
||||
static const float SLOP = 0.01f;
|
||||
@ -700,6 +762,8 @@ void NavMeshTesterTool::recalc()
|
||||
result, visited, &nvisited, 16);
|
||||
|
||||
npolys = fixupCorridor(polys, npolys, MAX_POLYS, visited, nvisited);
|
||||
npolys = fixupShortcuts(polys, npolys, m_navQuery);
|
||||
|
||||
float h = 0;
|
||||
m_navQuery->getPolyHeight(polys[0], result, &h);
|
||||
result[1] = h;
|
||||
@ -791,7 +855,7 @@ void NavMeshTesterTool::recalc()
|
||||
float epos[3];
|
||||
dtVcopy(epos, m_epos);
|
||||
if (m_polys[m_npolys-1] != m_endRef)
|
||||
m_navQuery->closestPointOnPoly(m_polys[m_npolys-1], m_epos, epos);
|
||||
m_navQuery->closestPointOnPoly(m_polys[m_npolys-1], m_epos, epos, 0);
|
||||
|
||||
m_navQuery->findStraightPath(m_spos, epos, m_polys, m_npolys,
|
||||
m_straightPath, m_straightPathFlags,
|
||||
@ -1297,7 +1361,7 @@ void NavMeshTesterTool::handleRender()
|
||||
for (int i = 0; i < m_nrandPoints; i++)
|
||||
{
|
||||
const float* p = &m_randPoints[i*3];
|
||||
dd.vertex(p[0],p[1]+0.1,p[2], duRGBA(220,32,16,192));
|
||||
dd.vertex(p[0],p[1]+0.1f,p[2], duRGBA(220,32,16,192));
|
||||
}
|
||||
dd.end();
|
||||
|
||||
|
@ -312,8 +312,8 @@ bool FileIO::write(const void* ptr, const size_t size)
|
||||
bool FileIO::read(void* ptr, const size_t size)
|
||||
{
|
||||
if (!m_fp || m_mode != 2) return false;
|
||||
fread(ptr, size, 1, m_fp);
|
||||
return true;
|
||||
size_t readLen = fread(ptr, size, 1, m_fp);
|
||||
return readLen == 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -283,7 +283,12 @@ dtNavMesh* Sample_TileMesh::loadAll(const char* path)
|
||||
|
||||
// Read header.
|
||||
NavMeshSetHeader header;
|
||||
fread(&header, sizeof(NavMeshSetHeader), 1, fp);
|
||||
size_t readLen = fread(&header, sizeof(NavMeshSetHeader), 1, fp);
|
||||
if (readLen != 1)
|
||||
{
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
if (header.magic != NAVMESHSET_MAGIC)
|
||||
{
|
||||
fclose(fp);
|
||||
@ -312,14 +317,19 @@ dtNavMesh* Sample_TileMesh::loadAll(const char* path)
|
||||
for (int i = 0; i < header.numTiles; ++i)
|
||||
{
|
||||
NavMeshTileHeader tileHeader;
|
||||
fread(&tileHeader, sizeof(tileHeader), 1, fp);
|
||||
readLen = fread(&tileHeader, sizeof(tileHeader), 1, fp);
|
||||
if (readLen != 1)
|
||||
return 0;
|
||||
|
||||
if (!tileHeader.tileRef || !tileHeader.dataSize)
|
||||
break;
|
||||
|
||||
unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
|
||||
if (!data) break;
|
||||
memset(data, 0, tileHeader.dataSize);
|
||||
fread(data, tileHeader.dataSize, 1, fp);
|
||||
readLen = fread(data, tileHeader.dataSize, 1, fp);
|
||||
if (readLen != 1)
|
||||
return 0;
|
||||
|
||||
mesh->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0);
|
||||
}
|
||||
|
@ -106,8 +106,12 @@ bool TestCase::load(const char* filePath)
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
fread(buf, bufSize, 1, fp);
|
||||
size_t readLen = fread(buf, bufSize, 1, fp);
|
||||
fclose(fp);
|
||||
if (readLen != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char* src = buf;
|
||||
char* srcEnd = buf + bufSize;
|
||||
@ -141,6 +145,20 @@ bool TestCase::load(const char* filePath)
|
||||
&test->epos[0], &test->epos[1], &test->epos[2],
|
||||
&test->includeFlags, &test->excludeFlags);
|
||||
}
|
||||
else if (row[0] == 'r' && row[1] == 'c')
|
||||
{
|
||||
// Pathfind test.
|
||||
Test* test = new Test;
|
||||
memset(test, 0, sizeof(Test));
|
||||
test->type = TEST_RAYCAST;
|
||||
test->expand = false;
|
||||
test->next = m_tests;
|
||||
m_tests = test;
|
||||
sscanf(row+2, "%f %f %f %f %f %f %x %x",
|
||||
&test->spos[0], &test->spos[1], &test->spos[2],
|
||||
&test->epos[0], &test->epos[1], &test->epos[2],
|
||||
&test->includeFlags, &test->excludeFlags);
|
||||
}
|
||||
}
|
||||
|
||||
delete [] buf;
|
||||
@ -187,8 +205,8 @@ void TestCase::doTests(dtNavMesh* navmesh, dtNavMeshQuery* navquery)
|
||||
TimeVal findNearestPolyStart = getPerfTime();
|
||||
|
||||
dtPolyRef startRef, endRef;
|
||||
navquery->findNearestPoly(iter->spos, polyPickExt, &filter, &startRef, 0);
|
||||
navquery->findNearestPoly(iter->epos, polyPickExt, &filter, &endRef, 0);
|
||||
navquery->findNearestPoly(iter->spos, polyPickExt, &filter, &startRef, iter->nspos);
|
||||
navquery->findNearestPoly(iter->epos, polyPickExt, &filter, &endRef, iter->nepos);
|
||||
|
||||
TimeVal findNearestPolyEnd = getPerfTime();
|
||||
iter->findNearestPolyTime += getPerfDeltaTimeUsec(findNearestPolyStart, findNearestPolyEnd);
|
||||
@ -196,35 +214,82 @@ void TestCase::doTests(dtNavMesh* navmesh, dtNavMeshQuery* navquery)
|
||||
if (!startRef || ! endRef)
|
||||
continue;
|
||||
|
||||
// Find path
|
||||
TimeVal findPathStart = getPerfTime();
|
||||
|
||||
navquery->findPath(startRef, endRef, iter->spos, iter->epos, &filter, polys, &iter->npolys, MAX_POLYS);
|
||||
|
||||
TimeVal findPathEnd = getPerfTime();
|
||||
iter->findPathTime += getPerfDeltaTimeUsec(findPathStart, findPathEnd);
|
||||
|
||||
// Find straight path
|
||||
if (iter->npolys)
|
||||
if (iter->type == TEST_PATHFIND)
|
||||
{
|
||||
TimeVal findStraightPathStart = getPerfTime();
|
||||
// Find path
|
||||
TimeVal findPathStart = getPerfTime();
|
||||
|
||||
navquery->findStraightPath(iter->spos, iter->epos, polys, iter->npolys,
|
||||
straight, 0, 0, &iter->nstraight, MAX_POLYS);
|
||||
TimeVal findStraightPathEnd = getPerfTime();
|
||||
iter->findStraightPathTime += getPerfDeltaTimeUsec(findStraightPathStart, findStraightPathEnd);
|
||||
navquery->findPath(startRef, endRef, iter->spos, iter->epos, &filter, polys, &iter->npolys, MAX_POLYS);
|
||||
|
||||
TimeVal findPathEnd = getPerfTime();
|
||||
iter->findPathTime += getPerfDeltaTimeUsec(findPathStart, findPathEnd);
|
||||
|
||||
// Find straight path
|
||||
if (iter->npolys)
|
||||
{
|
||||
TimeVal findStraightPathStart = getPerfTime();
|
||||
|
||||
navquery->findStraightPath(iter->spos, iter->epos, polys, iter->npolys,
|
||||
straight, 0, 0, &iter->nstraight, MAX_POLYS);
|
||||
TimeVal findStraightPathEnd = getPerfTime();
|
||||
iter->findStraightPathTime += getPerfDeltaTimeUsec(findStraightPathStart, findStraightPathEnd);
|
||||
}
|
||||
|
||||
// Copy results
|
||||
if (iter->npolys)
|
||||
{
|
||||
iter->polys = new dtPolyRef[iter->npolys];
|
||||
memcpy(iter->polys, polys, sizeof(dtPolyRef)*iter->npolys);
|
||||
}
|
||||
if (iter->nstraight)
|
||||
{
|
||||
iter->straight = new float[iter->nstraight*3];
|
||||
memcpy(iter->straight, straight, sizeof(float)*3*iter->nstraight);
|
||||
}
|
||||
}
|
||||
else if (iter->type == TEST_RAYCAST)
|
||||
{
|
||||
float t = 0;
|
||||
float hitNormal[3], hitPos[3];
|
||||
|
||||
// Copy results
|
||||
if (iter->npolys)
|
||||
{
|
||||
iter->polys = new dtPolyRef[iter->npolys];
|
||||
memcpy(iter->polys, polys, sizeof(dtPolyRef)*iter->npolys);
|
||||
}
|
||||
if (iter->nstraight)
|
||||
{
|
||||
iter->straight = new float[iter->nstraight*3];
|
||||
memcpy(iter->straight, straight, sizeof(float)*3*iter->nstraight);
|
||||
iter->straight = new float[2*3];
|
||||
iter->nstraight = 2;
|
||||
|
||||
iter->straight[0] = iter->spos[0];
|
||||
iter->straight[1] = iter->spos[1];
|
||||
iter->straight[2] = iter->spos[2];
|
||||
|
||||
TimeVal findPathStart = getPerfTime();
|
||||
|
||||
navquery->raycast(startRef, iter->spos, iter->epos, &filter, &t, hitNormal, polys, &iter->npolys, MAX_POLYS);
|
||||
|
||||
TimeVal findPathEnd = getPerfTime();
|
||||
iter->findPathTime += getPerfDeltaTimeUsec(findPathStart, findPathEnd);
|
||||
|
||||
if (t > 1)
|
||||
{
|
||||
// No hit
|
||||
dtVcopy(hitPos, iter->epos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hit
|
||||
dtVlerp(hitPos, iter->spos, iter->epos, t);
|
||||
}
|
||||
// Adjust height.
|
||||
if (iter->npolys > 0)
|
||||
{
|
||||
float h = 0;
|
||||
navquery->getPolyHeight(polys[iter->npolys-1], hitPos, &h);
|
||||
hitPos[1] = h;
|
||||
}
|
||||
dtVcopy(&iter->straight[3], hitPos);
|
||||
|
||||
if (iter->npolys)
|
||||
{
|
||||
iter->polys = new dtPolyRef[iter->npolys];
|
||||
memcpy(iter->polys, polys, sizeof(dtPolyRef)*iter->npolys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -260,6 +325,32 @@ void TestCase::handleRender()
|
||||
glVertex3f(iter->epos[0],iter->epos[1]-0.3f,iter->epos[2]);
|
||||
glVertex3f(iter->epos[0],iter->epos[1]+0.3f,iter->epos[2]);
|
||||
|
||||
if (iter->expand)
|
||||
{
|
||||
const float s = 0.1f;
|
||||
glColor4ub(255,32,0,128);
|
||||
glVertex3f(iter->spos[0]-s,iter->spos[1],iter->spos[2]);
|
||||
glVertex3f(iter->spos[0]+s,iter->spos[1],iter->spos[2]);
|
||||
glVertex3f(iter->spos[0],iter->spos[1],iter->spos[2]-s);
|
||||
glVertex3f(iter->spos[0],iter->spos[1],iter->spos[2]+s);
|
||||
glColor4ub(255,192,0,255);
|
||||
glVertex3f(iter->nspos[0]-s,iter->nspos[1],iter->nspos[2]);
|
||||
glVertex3f(iter->nspos[0]+s,iter->nspos[1],iter->nspos[2]);
|
||||
glVertex3f(iter->nspos[0],iter->nspos[1],iter->nspos[2]-s);
|
||||
glVertex3f(iter->nspos[0],iter->nspos[1],iter->nspos[2]+s);
|
||||
|
||||
glColor4ub(255,32,0,128);
|
||||
glVertex3f(iter->epos[0]-s,iter->epos[1],iter->epos[2]);
|
||||
glVertex3f(iter->epos[0]+s,iter->epos[1],iter->epos[2]);
|
||||
glVertex3f(iter->epos[0],iter->epos[1],iter->epos[2]-s);
|
||||
glVertex3f(iter->epos[0],iter->epos[1],iter->epos[2]+s);
|
||||
glColor4ub(255,192,0,255);
|
||||
glVertex3f(iter->nepos[0]-s,iter->nepos[1],iter->nepos[2]);
|
||||
glVertex3f(iter->nepos[0]+s,iter->nepos[1],iter->nepos[2]);
|
||||
glVertex3f(iter->nepos[0],iter->nepos[1],iter->nepos[2]-s);
|
||||
glVertex3f(iter->nepos[0],iter->nepos[1],iter->nepos[2]+s);
|
||||
}
|
||||
|
||||
if (iter->expand)
|
||||
glColor4ub(255,192,0,255);
|
||||
else
|
||||
|
@ -247,7 +247,7 @@ bool imguiRenderGLInit(const char* fontpath)
|
||||
FILE* fp = fopen(fontpath, "rb");
|
||||
if (!fp) return false;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int size = ftell(fp);
|
||||
size_t size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
unsigned char* ttfBuffer = (unsigned char*)malloc(size);
|
||||
@ -257,8 +257,13 @@ bool imguiRenderGLInit(const char* fontpath)
|
||||
return false;
|
||||
}
|
||||
|
||||
fread(ttfBuffer, 1, size, fp);
|
||||
size_t readLen = fread(ttfBuffer, 1, size, fp);
|
||||
fclose(fp);
|
||||
if (readLen != size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
fp = 0;
|
||||
|
||||
unsigned char* bmap = (unsigned char*)malloc(512*512);
|
||||
|
@ -101,7 +101,8 @@ int main(int /*argc*/, char** /*argv*/)
|
||||
}
|
||||
else
|
||||
{
|
||||
width = vi->current_w - 20;
|
||||
width = rcMin(vi->current_w, (int)(vi->current_h * 16.0 / 9.0));
|
||||
width = width - 80;
|
||||
height = vi->current_h - 80;
|
||||
screen = SDL_SetVideoMode(width, height, 0, SDL_OPENGL);
|
||||
}
|
||||
@ -817,7 +818,6 @@ int main(int /*argc*/, char** /*argv*/)
|
||||
{
|
||||
delete geom;
|
||||
geom = 0;
|
||||
|
||||
showLog = true;
|
||||
logScroll = 0;
|
||||
ctx.dumpLog("Geom load log %s:", meshName);
|
||||
@ -827,6 +827,10 @@ int main(int /*argc*/, char** /*argv*/)
|
||||
sample->handleMeshChanged(geom);
|
||||
}
|
||||
|
||||
// This will ensure that tile & poly bits are updated in tiled sample.
|
||||
if (sample)
|
||||
sample->handleSettings();
|
||||
|
||||
ctx.resetLog();
|
||||
if (sample && !sample->handleBuild())
|
||||
{
|
||||
@ -860,7 +864,7 @@ int main(int /*argc*/, char** /*argv*/)
|
||||
}
|
||||
rx = 45;
|
||||
ry = -45;
|
||||
glFogf(GL_FOG_START, camr*0.1f);
|
||||
glFogf(GL_FOG_START, camr*0.2f);
|
||||
glFogf(GL_FOG_END, camr*1.25f);
|
||||
}
|
||||
|
||||
|
@ -16,21 +16,22 @@ solution "recastnavigation"
|
||||
-- extra warnings, no exceptions or rtti
|
||||
flags {
|
||||
"ExtraWarnings",
|
||||
"FloatFast",
|
||||
"NoExceptions",
|
||||
"NoRTTI"
|
||||
"NoRTTI",
|
||||
"Symbols"
|
||||
}
|
||||
|
||||
-- debug configs
|
||||
configuration "Debug*"
|
||||
defines { "DEBUG" }
|
||||
flags { "Symbols" }
|
||||
targetdir ( "Build/" .. action .. "/Debug" )
|
||||
targetdir ( todir .. "/lib/Debug" )
|
||||
|
||||
-- release configs
|
||||
configuration "Release*"
|
||||
defines { "NDEBUG" }
|
||||
flags { "Optimize" }
|
||||
targetdir ( "Build/" .. action .. "/Release" )
|
||||
targetdir ( todir .. "/lib/Release" )
|
||||
|
||||
-- windows specific
|
||||
configuration "windows"
|
||||
@ -50,7 +51,6 @@ project "DebugUtils"
|
||||
"../DebugUtils/Include/*.h",
|
||||
"../DebugUtils/Source/*.cpp"
|
||||
}
|
||||
targetdir (todir .. "/lib")
|
||||
|
||||
project "Detour"
|
||||
language "C++"
|
||||
@ -62,7 +62,6 @@ project "Detour"
|
||||
"../Detour/Include/*.h",
|
||||
"../Detour/Source/*.cpp"
|
||||
}
|
||||
targetdir (todir .. "/lib")
|
||||
|
||||
project "DetourCrowd"
|
||||
language "C++"
|
||||
@ -76,7 +75,6 @@ project "DetourCrowd"
|
||||
"../DetourCrowd/Include/*.h",
|
||||
"../DetourCrowd/Source/*.cpp"
|
||||
}
|
||||
targetdir (todir .. "/lib")
|
||||
|
||||
project "DetourTileCache"
|
||||
language "C++"
|
||||
@ -90,7 +88,6 @@ project "DetourTileCache"
|
||||
"../DetourTileCache/Include/*.h",
|
||||
"../DetourTileCache/Source/*.cpp"
|
||||
}
|
||||
targetdir (todir .. "/lib")
|
||||
|
||||
project "Recast"
|
||||
language "C++"
|
||||
@ -102,7 +99,6 @@ project "Recast"
|
||||
"../Recast/Include/*.h",
|
||||
"../Recast/Source/*.cpp"
|
||||
}
|
||||
targetdir (todir .. "/lib")
|
||||
|
||||
project "RecastDemo"
|
||||
language "C++"
|
||||
|
Loading…
x
Reference in New Issue
Block a user