mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-15 04:11:30 +00:00
Update recast
This commit is contained in:
parent
913fb6c22e
commit
ec58d92e42
@ -210,6 +210,10 @@ public:
|
||||
virtual void end();
|
||||
void clear();
|
||||
void draw(struct duDebugDraw* dd);
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
duDisplayList(const duDisplayList&);
|
||||
duDisplayList& operator=(const duDisplayList&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -31,7 +31,6 @@ enum DrawNavMeshFlags
|
||||
};
|
||||
|
||||
void duDebugDrawNavMesh(struct duDebugDraw* dd, const dtNavMesh& mesh, unsigned char flags);
|
||||
void duDebugDrawNavMeshTile(struct duDebugDraw* dd, const dtNavMesh& mesh, int w, int h, int layer, unsigned char flags);
|
||||
void duDebugDrawNavMeshWithClosedList(struct duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery& query, unsigned char flags);
|
||||
void duDebugDrawNavMeshNodes(struct duDebugDraw* dd, const dtNavMeshQuery& query);
|
||||
void duDebugDrawNavMeshBVTree(struct duDebugDraw* dd, const dtNavMesh& mesh);
|
||||
|
||||
@ -250,19 +250,6 @@ void duDebugDrawNavMesh(duDebugDraw* dd, const dtNavMesh& mesh, unsigned char fl
|
||||
}
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshTile(struct duDebugDraw* dd, const dtNavMesh& mesh, int w, int h, int layer, unsigned char flags) {
|
||||
const dtMeshTile* tile = mesh.getTileAt(w, h, layer);
|
||||
if (!tile) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tile->header) {
|
||||
return;
|
||||
}
|
||||
|
||||
drawMeshTile(dd, mesh, 0, tile, flags);
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshWithClosedList(struct duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery& query, unsigned char flags)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
@ -19,6 +19,8 @@
|
||||
#ifndef DETOURALLOCATOR_H
|
||||
#define DETOURALLOCATOR_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/// Provides hint values to the memory allocator on how long the
|
||||
/// memory is expected to be used.
|
||||
enum dtAllocHint
|
||||
@ -32,7 +34,7 @@ enum dtAllocHint
|
||||
// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use.
|
||||
// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||
/// @see dtAllocSetCustom
|
||||
typedef void* (dtAllocFunc)(int size, dtAllocHint hint);
|
||||
typedef void* (dtAllocFunc)(size_t size, dtAllocHint hint);
|
||||
|
||||
/// A memory deallocation function.
|
||||
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAllocFunc.
|
||||
@ -49,7 +51,7 @@ void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc);
|
||||
/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
|
||||
/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||
/// @see dtFree
|
||||
void* dtAlloc(int size, dtAllocHint hint);
|
||||
void* dtAlloc(size_t size, dtAllocHint hint);
|
||||
|
||||
/// Deallocates a memory block.
|
||||
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAlloc.
|
||||
|
||||
@ -118,11 +118,10 @@ enum dtStraightPathOptions
|
||||
};
|
||||
|
||||
|
||||
/// Options for dtNavMeshQuery::findPath
|
||||
/// Options for dtNavMeshQuery::initSlicedFindPath and updateSlicedFindPath
|
||||
enum dtFindPathOptions
|
||||
{
|
||||
DT_FINDPATH_LOW_QUALITY_FAR = 0x01, ///< [provisional] trade quality for performance far from the origin. The idea is that by then a new query will be issued
|
||||
DT_FINDPATH_ANY_ANGLE = 0x02, ///< use raycasts during pathfind to "shortcut" (raycast still consider costs)
|
||||
DT_FINDPATH_ANY_ANGLE = 0x02, ///< use raycasts during pathfind to "shortcut" (raycast still consider costs)
|
||||
};
|
||||
|
||||
/// Options for dtNavMeshQuery::raycast
|
||||
@ -146,7 +145,7 @@ enum dtPolyTypes
|
||||
};
|
||||
|
||||
|
||||
/// Defines a polyogn within a dtMeshTile object.
|
||||
/// Defines a polygon within a dtMeshTile object.
|
||||
/// @ingroup detour
|
||||
struct dtPoly
|
||||
{
|
||||
@ -301,6 +300,9 @@ struct dtMeshTile
|
||||
int dataSize; ///< Size of the tile data.
|
||||
int flags; ///< Tile flags. (See: #dtTileFlags)
|
||||
dtMeshTile* next; ///< The next free tile, or the next tile in the spatial grid.
|
||||
private:
|
||||
dtMeshTile(const dtMeshTile&);
|
||||
dtMeshTile& operator=(const dtMeshTile&);
|
||||
};
|
||||
|
||||
/// Configuration parameters used to define multi-tile navigation meshes.
|
||||
@ -592,6 +594,9 @@ public:
|
||||
/// @}
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
dtNavMesh(const dtNavMesh&);
|
||||
dtNavMesh& operator=(const dtNavMesh&);
|
||||
|
||||
/// Returns pointer to tile in the tile array.
|
||||
dtMeshTile* getTile(int i);
|
||||
@ -620,7 +625,7 @@ private:
|
||||
void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||
|
||||
/// Removes external links at specified side.
|
||||
void unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target);
|
||||
void unconnectLinks(dtMeshTile* tile, dtMeshTile* target);
|
||||
|
||||
|
||||
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed for off-mesh connection finding.
|
||||
|
||||
@ -131,6 +131,9 @@ struct dtRaycastHit
|
||||
|
||||
/// hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
||||
float hitNormal[3];
|
||||
|
||||
/// The index of the edge on the final polygon where the wall was hit.
|
||||
int hitEdgeIndex;
|
||||
|
||||
/// Pointer to an array of reference ids of the visited polygons. [opt]
|
||||
dtPolyRef* path;
|
||||
@ -472,6 +475,9 @@ public:
|
||||
/// @}
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator
|
||||
dtNavMeshQuery(const dtNavMeshQuery&);
|
||||
dtNavMeshQuery& operator=(const dtNavMeshQuery&);
|
||||
|
||||
/// Returns neighbour tile based on side.
|
||||
dtMeshTile* getNeighbourTileAt(int x, int y, int side) const;
|
||||
|
||||
@ -42,17 +42,13 @@ struct dtNode
|
||||
dtPolyRef id; ///< Polygon ref the node corresponds to.
|
||||
};
|
||||
|
||||
|
||||
static const int DT_MAX_STATES_PER_NODE = 4; // number of extra states per node. See dtNode::state
|
||||
|
||||
|
||||
|
||||
class dtNodePool
|
||||
{
|
||||
public:
|
||||
dtNodePool(int maxNodes, int hashSize);
|
||||
~dtNodePool();
|
||||
inline void operator=(const dtNodePool&) {}
|
||||
void clear();
|
||||
|
||||
// Get a dtNode by ref and extra state information. If there is none then - allocate
|
||||
@ -64,19 +60,19 @@ public:
|
||||
inline unsigned int getNodeIdx(const dtNode* node) const
|
||||
{
|
||||
if (!node) return 0;
|
||||
return (unsigned int)(node - m_nodes)+1;
|
||||
return (unsigned int)(node - m_nodes) + 1;
|
||||
}
|
||||
|
||||
inline dtNode* getNodeAtIdx(unsigned int idx)
|
||||
{
|
||||
if (!idx) return 0;
|
||||
return &m_nodes[idx-1];
|
||||
return &m_nodes[idx - 1];
|
||||
}
|
||||
|
||||
inline const dtNode* getNodeAtIdx(unsigned int idx) const
|
||||
{
|
||||
if (!idx) return 0;
|
||||
return &m_nodes[idx-1];
|
||||
return &m_nodes[idx - 1];
|
||||
}
|
||||
|
||||
inline int getMemUsed() const
|
||||
@ -95,6 +91,9 @@ public:
|
||||
inline int getNodeCount() const { return m_nodeCount; }
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
dtNodePool(const dtNodePool&);
|
||||
dtNodePool& operator=(const dtNodePool&);
|
||||
|
||||
dtNode* m_nodes;
|
||||
dtNodeIndex* m_first;
|
||||
@ -109,17 +108,10 @@ class dtNodeQueue
|
||||
public:
|
||||
dtNodeQueue(int n);
|
||||
~dtNodeQueue();
|
||||
inline void operator=(dtNodeQueue&) {}
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
inline void clear() { m_size = 0; }
|
||||
|
||||
inline dtNode* top()
|
||||
{
|
||||
return m_heap[0];
|
||||
}
|
||||
inline dtNode* top() { return m_heap[0]; }
|
||||
|
||||
inline dtNode* pop()
|
||||
{
|
||||
@ -152,12 +144,16 @@ public:
|
||||
inline int getMemUsed() const
|
||||
{
|
||||
return sizeof(*this) +
|
||||
sizeof(dtNode*)*(m_capacity+1);
|
||||
sizeof(dtNode*) * (m_capacity + 1);
|
||||
}
|
||||
|
||||
inline int getCapacity() const { return m_capacity; }
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
dtNodeQueue(const dtNodeQueue&);
|
||||
dtNodeQueue& operator=(const dtNodeQueue&);
|
||||
|
||||
void bubbleUp(int i, dtNode* node);
|
||||
void trickleDown(int i, dtNode* node);
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "DetourAlloc.h"
|
||||
|
||||
static void *dtAllocDefault(int size, dtAllocHint)
|
||||
static void *dtAllocDefault(size_t size, dtAllocHint)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
@ -38,7 +38,7 @@ void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc)
|
||||
sFreeFunc = freeFunc ? freeFunc : dtFreeDefault;
|
||||
}
|
||||
|
||||
void* dtAlloc(int size, dtAllocHint hint)
|
||||
void* dtAlloc(size_t size, dtAllocHint hint)
|
||||
{
|
||||
return sAllocFunc(size, hint);
|
||||
}
|
||||
|
||||
@ -350,7 +350,7 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb,
|
||||
return n;
|
||||
}
|
||||
|
||||
void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target)
|
||||
void dtNavMesh::unconnectLinks(dtMeshTile* tile, dtMeshTile* target)
|
||||
{
|
||||
if (!tile || !target) return;
|
||||
|
||||
@ -363,10 +363,9 @@ void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target)
|
||||
unsigned int pj = DT_NULL_LINK;
|
||||
while (j != DT_NULL_LINK)
|
||||
{
|
||||
if (tile->links[j].side != 0xff &&
|
||||
decodePolyIdTile(tile->links[j].ref) == targetNum)
|
||||
if (decodePolyIdTile(tile->links[j].ref) == targetNum)
|
||||
{
|
||||
// Revove link.
|
||||
// Remove link.
|
||||
unsigned int nj = tile->links[j].next;
|
||||
if (pj == DT_NULL_LINK)
|
||||
poly->firstLink = nj;
|
||||
@ -838,6 +837,11 @@ int dtNavMesh::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, co
|
||||
/// tile will be restored to the same values they were before the tile was
|
||||
/// removed.
|
||||
///
|
||||
/// The nav mesh assumes exclusive access to the data passed and will make
|
||||
/// changes to the dynamic portion of the data. For that reason the data
|
||||
/// should not be reused in other nav meshes until the tile has been successfully
|
||||
/// removed from this nav mesh.
|
||||
///
|
||||
/// @see dtCreateNavMeshData, #removeTile
|
||||
dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
||||
dtTileRef lastRef, dtTileRef* result)
|
||||
@ -1192,25 +1196,24 @@ dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSiz
|
||||
}
|
||||
|
||||
// Remove connections to neighbour tiles.
|
||||
// Create connections with neighbour tiles.
|
||||
static const int MAX_NEIS = 32;
|
||||
dtMeshTile* neis[MAX_NEIS];
|
||||
int nneis;
|
||||
|
||||
// Connect with layers in current tile.
|
||||
// Disconnect from other layers in current tile.
|
||||
nneis = getTilesAt(tile->header->x, tile->header->y, neis, MAX_NEIS);
|
||||
for (int j = 0; j < nneis; ++j)
|
||||
{
|
||||
if (neis[j] == tile) continue;
|
||||
unconnectExtLinks(neis[j], tile);
|
||||
unconnectLinks(neis[j], tile);
|
||||
}
|
||||
|
||||
// Connect with neighbour tiles.
|
||||
// Disconnect from neighbour tiles.
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
nneis = getNeighbourTilesAt(tile->header->x, tile->header->y, i, neis, MAX_NEIS);
|
||||
for (int j = 0; j < nneis; ++j)
|
||||
unconnectExtLinks(neis[j], tile);
|
||||
unconnectLinks(neis[j], tile);
|
||||
}
|
||||
|
||||
// Reset tile.
|
||||
|
||||
@ -712,7 +712,8 @@ dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* exten
|
||||
{
|
||||
dtAssert(m_nav);
|
||||
|
||||
*nearestRef = 0;
|
||||
if (!nearestRef)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
|
||||
// Get nearby polygons from proximity grid.
|
||||
const int MAX_SEARCH = 128;
|
||||
@ -721,8 +722,15 @@ dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* exten
|
||||
if (dtStatusFailed(queryPolygons(center, extents, filter, polys, &polyCount, MAX_SEARCH)))
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
|
||||
*nearestRef = 0;
|
||||
|
||||
if (polyCount == 0)
|
||||
return DT_SUCCESS;
|
||||
|
||||
// Find nearest polygon amongst the nearby polygons.
|
||||
dtPolyRef nearest = 0;
|
||||
float nearestPoint[3];
|
||||
|
||||
float nearestDistanceSqr = FLT_MAX;
|
||||
for (int i = 0; i < polyCount; ++i)
|
||||
{
|
||||
@ -751,15 +759,17 @@ dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* exten
|
||||
|
||||
if (d < nearestDistanceSqr)
|
||||
{
|
||||
if (nearestPt)
|
||||
dtVcopy(nearestPt, closestPtPoly);
|
||||
dtVcopy(nearestPoint, closestPtPoly);
|
||||
|
||||
nearestDistanceSqr = d;
|
||||
nearest = ref;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearestRef)
|
||||
*nearestRef = nearest;
|
||||
*nearestRef = nearest;
|
||||
|
||||
if (nearestPt)
|
||||
dtVcopy(nearestPt, nearestPoint);
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
@ -2420,6 +2430,9 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons
|
||||
hit->pathCount = n;
|
||||
return status;
|
||||
}
|
||||
|
||||
hit->hitEdgeIndex = segMax;
|
||||
|
||||
// Keep track of furthest t so far.
|
||||
if (tmax > hit->t)
|
||||
hit->t = tmax;
|
||||
|
||||
@ -164,7 +164,10 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
dtTileCache(const dtTileCache&);
|
||||
dtTileCache& operator=(const dtTileCache&);
|
||||
|
||||
enum ObstacleRequestAction
|
||||
{
|
||||
REQUEST_ADD,
|
||||
@ -203,7 +206,6 @@ private:
|
||||
static const int MAX_UPDATE = 64;
|
||||
dtCompressedTileRef m_update[MAX_UPDATE];
|
||||
int m_nupdate;
|
||||
|
||||
};
|
||||
|
||||
dtTileCache* dtAllocTileCache();
|
||||
|
||||
@ -78,13 +78,11 @@ struct dtTileCachePolyMesh
|
||||
|
||||
struct dtTileCacheAlloc
|
||||
{
|
||||
virtual ~dtTileCacheAlloc() { }
|
||||
virtual ~dtTileCacheAlloc() {}
|
||||
|
||||
virtual void reset()
|
||||
{
|
||||
}
|
||||
virtual void reset() {}
|
||||
|
||||
virtual void* alloc(const int size)
|
||||
virtual void* alloc(const size_t size)
|
||||
{
|
||||
return dtAlloc(size, DT_ALLOC_TEMP);
|
||||
}
|
||||
|
||||
@ -40,10 +40,10 @@ inline int computeTileHash(int x, int y, const int mask)
|
||||
}
|
||||
|
||||
|
||||
struct BuildContext
|
||||
struct NavMeshTileBuildContext
|
||||
{
|
||||
inline BuildContext(struct dtTileCacheAlloc* a) : layer(0), lcset(0), lmesh(0), alloc(a) {}
|
||||
inline ~BuildContext() { purge(); }
|
||||
inline NavMeshTileBuildContext(struct dtTileCacheAlloc* a) : layer(0), lcset(0), lmesh(0), alloc(a) {}
|
||||
inline ~NavMeshTileBuildContext() { purge(); }
|
||||
void purge()
|
||||
{
|
||||
dtFreeTileCacheLayer(alloc, layer);
|
||||
@ -350,7 +350,7 @@ dtStatus dtTileCache::removeTile(dtCompressedTileRef ref, unsigned char** data,
|
||||
}
|
||||
|
||||
|
||||
dtObstacleRef dtTileCache::addObstacle(const float* pos, const float radius, const float height, dtObstacleRef* result)
|
||||
dtStatus dtTileCache::addObstacle(const float* pos, const float radius, const float height, dtObstacleRef* result)
|
||||
{
|
||||
if (m_nreqs >= MAX_REQUESTS)
|
||||
return DT_FAILURE | DT_BUFFER_TOO_SMALL;
|
||||
@ -384,7 +384,7 @@ dtObstacleRef dtTileCache::addObstacle(const float* pos, const float radius, con
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtObstacleRef dtTileCache::removeObstacle(const dtObstacleRef ref)
|
||||
dtStatus dtTileCache::removeObstacle(const dtObstacleRef ref)
|
||||
{
|
||||
if (!ref)
|
||||
return DT_SUCCESS;
|
||||
@ -587,7 +587,7 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh*
|
||||
|
||||
m_talloc->reset();
|
||||
|
||||
BuildContext bc(m_talloc);
|
||||
NavMeshTileBuildContext bc(m_talloc);
|
||||
const int walkableClimbVx = (int)(m_params.walkableClimb / m_params.ch);
|
||||
dtStatus status;
|
||||
|
||||
@ -631,7 +631,11 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh*
|
||||
|
||||
// Early out if the mesh tile is empty.
|
||||
if (!bc.lmesh->npolys)
|
||||
{
|
||||
// Remove existing tile.
|
||||
navmesh->removeTile(navmesh->getTileRefAt(tile->header->tx,tile->header->ty,tile->header->tlayer),0,0);
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtNavMeshCreateParams params;
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
@ -127,7 +127,7 @@ public:
|
||||
inline void resetTimers() { if (m_timerEnabled) doResetTimers(); }
|
||||
|
||||
/// Starts the specified performance timer.
|
||||
/// @param label The category of timer.
|
||||
/// @param label The category of the timer.
|
||||
inline void startTimer(const rcTimerLabel label) { if (m_timerEnabled) doStartTimer(label); }
|
||||
|
||||
/// Stops the specified performance timer.
|
||||
@ -173,6 +173,26 @@ protected:
|
||||
bool m_timerEnabled;
|
||||
};
|
||||
|
||||
/// A helper to first start a timer and then stop it when this helper goes out of scope.
|
||||
/// @see rcContext
|
||||
class rcScopedTimer
|
||||
{
|
||||
public:
|
||||
/// Constructs an instance and starts the timer.
|
||||
/// @param[in] ctx The context to use.
|
||||
/// @param[in] label The category of the timer.
|
||||
inline rcScopedTimer(rcContext* ctx, const rcTimerLabel label) : m_ctx(ctx), m_label(label) { m_ctx->startTimer(m_label); }
|
||||
inline ~rcScopedTimer() { m_ctx->stopTimer(m_label); }
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
rcScopedTimer(const rcScopedTimer&);
|
||||
rcScopedTimer& operator=(const rcScopedTimer&);
|
||||
|
||||
rcContext* const m_ctx;
|
||||
const rcTimerLabel m_label;
|
||||
};
|
||||
|
||||
/// Specifies a configuration to use when performing Recast builds.
|
||||
/// @ingroup recast
|
||||
struct rcConfig
|
||||
@ -245,7 +265,7 @@ struct rcConfig
|
||||
/// Defines the number of bits allocated to rcSpan::smin and rcSpan::smax.
|
||||
static const int RC_SPAN_HEIGHT_BITS = 13;
|
||||
/// Defines the maximum value for rcSpan::smin and rcSpan::smax.
|
||||
static const int RC_SPAN_MAX_HEIGHT = (1<<RC_SPAN_HEIGHT_BITS)-1;
|
||||
static const int RC_SPAN_MAX_HEIGHT = (1 << RC_SPAN_HEIGHT_BITS) - 1;
|
||||
|
||||
/// The number of spans allocated per span spool.
|
||||
/// @see rcSpanPool
|
||||
@ -255,10 +275,10 @@ static const int RC_SPANS_PER_POOL = 2048;
|
||||
/// @see rcHeightfield
|
||||
struct rcSpan
|
||||
{
|
||||
unsigned int smin : 13; ///< The lower limit of the span. [Limit: < #smax]
|
||||
unsigned int smax : 13; ///< The upper limit of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT]
|
||||
unsigned int area : 6; ///< The area id assigned to the span.
|
||||
rcSpan* next; ///< The next span higher up in column.
|
||||
unsigned int smin : RC_SPAN_HEIGHT_BITS; ///< The lower limit of the span. [Limit: < #smax]
|
||||
unsigned int smax : RC_SPAN_HEIGHT_BITS; ///< The upper limit of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT]
|
||||
unsigned int area : 6; ///< The area id assigned to the span.
|
||||
rcSpan* next; ///< The next span higher up in column.
|
||||
};
|
||||
|
||||
/// A memory pool used for quick allocation of spans within a heightfield.
|
||||
@ -376,6 +396,7 @@ struct rcContourSet
|
||||
int width; ///< The width of the set. (Along the x-axis in cell units.)
|
||||
int height; ///< The height of the set. (Along the z-axis in cell units.)
|
||||
int borderSize; ///< The AABB border size used to generate the source data from which the contours were derived.
|
||||
float maxError; ///< The max edge error that this contour set was simplified with.
|
||||
};
|
||||
|
||||
/// Represents a polygon mesh suitable for use in building a navigation mesh.
|
||||
@ -396,6 +417,7 @@ struct rcPolyMesh
|
||||
float cs; ///< The size of each cell. (On the xz-plane.)
|
||||
float ch; ///< The height of each cell. (The minimum increment along the y-axis.)
|
||||
int borderSize; ///< The AABB border size used to generate the source data from which the mesh was derived.
|
||||
float maxEdgeError; ///< The max error of the polygon edges in the mesh.
|
||||
};
|
||||
|
||||
/// Contains triangle meshes that represent detailed height data associated
|
||||
@ -497,6 +519,14 @@ void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh);
|
||||
/// @see rcCompactSpan::reg
|
||||
static const unsigned short RC_BORDER_REG = 0x8000;
|
||||
|
||||
/// Polygon touches multiple regions.
|
||||
/// If a polygon has this region ID it was merged with or created
|
||||
/// from polygons of different regions during the polymesh
|
||||
/// build step that removes redundant border vertices.
|
||||
/// (Used during the polymesh and detail polymesh build processes)
|
||||
/// @see rcPolyMesh::regs
|
||||
static const unsigned short RC_MULTIPLE_REGS = 0;
|
||||
|
||||
/// Border vertex flag.
|
||||
/// If a region ID has this bit set, then the associated element lies on
|
||||
/// a tile border. If a contour vertex's region ID has this bit set, the
|
||||
@ -747,6 +777,7 @@ void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int*
|
||||
/// @param[in] bmax The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu]
|
||||
/// @param[in] cs The xz-plane cell size to use for the field. [Limit: > 0] [Units: wu]
|
||||
/// @param[in] ch The y-axis cell size to use for field. [Limit: > 0] [Units: wu]
|
||||
/// @returns True if the operation completed successfully.
|
||||
bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height,
|
||||
const float* bmin, const float* bmax,
|
||||
float cs, float ch);
|
||||
@ -790,7 +821,8 @@ void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
|
||||
/// @param[in] smax The maximum height of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT] [Units: vx]
|
||||
/// @param[in] area The area id of the span. [Limit: <= #RC_WALKABLE_AREA)
|
||||
/// @param[in] flagMergeThr The merge theshold. [Limit: >= 0] [Units: vx]
|
||||
void rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y,
|
||||
/// @returns True if the operation completed successfully.
|
||||
bool rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y,
|
||||
const unsigned short smin, const unsigned short smax,
|
||||
const unsigned char area, const int flagMergeThr);
|
||||
|
||||
@ -804,7 +836,8 @@ void rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y,
|
||||
/// @param[in,out] solid An initialized heightfield.
|
||||
/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
|
||||
/// [Limit: >= 0] [Units: vx]
|
||||
void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
|
||||
/// @returns True if the operation completed successfully.
|
||||
bool rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
|
||||
const unsigned char area, rcHeightfield& solid,
|
||||
const int flagMergeThr = 1);
|
||||
|
||||
@ -819,7 +852,8 @@ void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const
|
||||
/// @param[in,out] solid An initialized heightfield.
|
||||
/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
|
||||
/// [Limit: >= 0] [Units: vx]
|
||||
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
|
||||
/// @returns True if the operation completed successfully.
|
||||
bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
|
||||
const int* tris, const unsigned char* areas, const int nt,
|
||||
rcHeightfield& solid, const int flagMergeThr = 1);
|
||||
|
||||
@ -834,7 +868,8 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
|
||||
/// @param[in,out] solid An initialized heightfield.
|
||||
/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
|
||||
/// [Limit: >= 0] [Units: vx]
|
||||
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
|
||||
/// @returns True if the operation completed successfully.
|
||||
bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
|
||||
const unsigned short* tris, const unsigned char* areas, const int nt,
|
||||
rcHeightfield& solid, const int flagMergeThr = 1);
|
||||
|
||||
@ -847,7 +882,8 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
|
||||
/// @param[in,out] solid An initialized heightfield.
|
||||
/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
|
||||
/// [Limit: >= 0] [Units: vx]
|
||||
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
|
||||
/// @returns True if the operation completed successfully.
|
||||
bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
|
||||
rcHeightfield& solid, const int flagMergeThr = 1);
|
||||
|
||||
/// Marks non-walkable spans as walkable if their maximum is within @p walkableClimp of a walkable neihbor.
|
||||
@ -1037,7 +1073,7 @@ inline int rcGetCon(const rcCompactSpan& s, int dir)
|
||||
/// in the direction.
|
||||
inline int rcGetDirOffsetX(int dir)
|
||||
{
|
||||
const int offset[4] = { -1, 0, 1, 0, };
|
||||
static const int offset[4] = { -1, 0, 1, 0, };
|
||||
return offset[dir&0x03];
|
||||
}
|
||||
|
||||
@ -1047,10 +1083,20 @@ inline int rcGetDirOffsetX(int dir)
|
||||
/// in the direction.
|
||||
inline int rcGetDirOffsetY(int dir)
|
||||
{
|
||||
const int offset[4] = { 0, 1, 0, -1 };
|
||||
static const int offset[4] = { 0, 1, 0, -1 };
|
||||
return offset[dir&0x03];
|
||||
}
|
||||
|
||||
/// Gets the direction for the specified offset. One of x and y should be 0.
|
||||
/// @param[in] x The x offset. [Limits: -1 <= value <= 1]
|
||||
/// @param[in] y The y offset. [Limits: -1 <= value <= 1]
|
||||
/// @return The direction that represents the offset.
|
||||
inline int rcGetDirForOffset(int x, int y)
|
||||
{
|
||||
static const int dirs[5] = { 3, 0, -1, 2, 1 };
|
||||
return dirs[((y+1)<<1)+x];
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Layer, Contour, Polymesh, and Detail Mesh Functions
|
||||
/// @see rcHeightfieldLayer, rcContourSet, rcPolyMesh, rcPolyMeshDetail
|
||||
|
||||
@ -19,6 +19,8 @@
|
||||
#ifndef RECASTALLOC_H
|
||||
#define RECASTALLOC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/// Provides hint values to the memory allocator on how long the
|
||||
/// memory is expected to be used.
|
||||
enum rcAllocHint
|
||||
@ -32,7 +34,7 @@ enum rcAllocHint
|
||||
// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use.
|
||||
// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||
/// @see rcAllocSetCustom
|
||||
typedef void* (rcAllocFunc)(int size, rcAllocHint hint);
|
||||
typedef void* (rcAllocFunc)(size_t size, rcAllocHint hint);
|
||||
|
||||
/// A memory deallocation function.
|
||||
/// @param[in] ptr A pointer to a memory block previously allocated using #rcAllocFunc.
|
||||
@ -49,7 +51,7 @@ void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc);
|
||||
/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
|
||||
/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||
/// @see rcFree
|
||||
void* rcAlloc(int size, rcAllocHint hint);
|
||||
void* rcAlloc(size_t size, rcAllocHint hint);
|
||||
|
||||
/// Deallocates a memory block.
|
||||
/// @param[in] ptr A pointer to a memory block previously allocated using #rcAlloc.
|
||||
@ -62,42 +64,58 @@ class rcIntArray
|
||||
{
|
||||
int* m_data;
|
||||
int m_size, m_cap;
|
||||
inline rcIntArray(const rcIntArray&);
|
||||
inline rcIntArray& operator=(const rcIntArray&);
|
||||
public:
|
||||
|
||||
void doResize(int n);
|
||||
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
rcIntArray(const rcIntArray&);
|
||||
rcIntArray& operator=(const rcIntArray&);
|
||||
|
||||
public:
|
||||
/// Constructs an instance with an initial array size of zero.
|
||||
inline rcIntArray() : m_data(0), m_size(0), m_cap(0) {}
|
||||
rcIntArray() : m_data(0), m_size(0), m_cap(0) {}
|
||||
|
||||
/// Constructs an instance initialized to the specified size.
|
||||
/// @param[in] n The initial size of the integer array.
|
||||
inline rcIntArray(int n) : m_data(0), m_size(0), m_cap(0) { resize(n); }
|
||||
inline ~rcIntArray() { rcFree(m_data); }
|
||||
rcIntArray(int n) : m_data(0), m_size(0), m_cap(0) { resize(n); }
|
||||
~rcIntArray() { rcFree(m_data); }
|
||||
|
||||
/// Specifies the new size of the integer array.
|
||||
/// @param[in] n The new size of the integer array.
|
||||
void resize(int n);
|
||||
void resize(int n)
|
||||
{
|
||||
if (n > m_cap)
|
||||
doResize(n);
|
||||
|
||||
m_size = n;
|
||||
}
|
||||
|
||||
/// Push the specified integer onto the end of the array and increases the size by one.
|
||||
/// @param[in] item The new value.
|
||||
inline void push(int item) { resize(m_size+1); m_data[m_size-1] = item; }
|
||||
void push(int item) { resize(m_size+1); m_data[m_size-1] = item; }
|
||||
|
||||
/// Returns the value at the end of the array and reduces the size by one.
|
||||
/// @return The value at the end of the array.
|
||||
inline int pop() { if (m_size > 0) m_size--; return m_data[m_size]; }
|
||||
int pop()
|
||||
{
|
||||
if (m_size > 0)
|
||||
m_size--;
|
||||
|
||||
return m_data[m_size];
|
||||
}
|
||||
|
||||
/// The value at the specified array index.
|
||||
/// @warning Does not provide overflow protection.
|
||||
/// @param[in] i The index of the value.
|
||||
inline const int& operator[](int i) const { return m_data[i]; }
|
||||
const int& operator[](int i) const { return m_data[i]; }
|
||||
|
||||
/// The value at the specified array index.
|
||||
/// @warning Does not provide overflow protection.
|
||||
/// @param[in] i The index of the value.
|
||||
inline int& operator[](int i) { return m_data[i]; }
|
||||
int& operator[](int i) { return m_data[i]; }
|
||||
|
||||
/// The current size of the integer array.
|
||||
inline int size() const { return m_size; }
|
||||
int size() const { return m_size; }
|
||||
};
|
||||
|
||||
/// A simple helper class used to delete an array when it goes out of scope.
|
||||
@ -119,6 +137,11 @@ public:
|
||||
/// The root array pointer.
|
||||
/// @return The root array pointer.
|
||||
inline operator T*() { return ptr; }
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
rcScopedDelete(const rcScopedDelete&);
|
||||
rcScopedDelete& operator=(const rcScopedDelete&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -257,7 +257,7 @@ void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
|
||||
|
||||
for (int i = 0; i < nt; ++i)
|
||||
{
|
||||
const int* tri = &tris[i*3];
|
||||
const int* tri = &tris[i*3];
|
||||
calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
|
||||
// Check if the face is walkable.
|
||||
if (norm[1] > walkableThr)
|
||||
@ -329,7 +329,7 @@ bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const i
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
|
||||
|
||||
const int w = hf.width;
|
||||
const int h = hf.height;
|
||||
@ -456,8 +456,6 @@ bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const i
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers %d (max: %d)",
|
||||
tooHighNeighbour, MAX_LAYERS);
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
#include <string.h>
|
||||
#include "RecastAlloc.h"
|
||||
|
||||
static void *rcAllocDefault(int size, rcAllocHint)
|
||||
static void *rcAllocDefault(size_t size, rcAllocHint)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
@ -41,7 +41,7 @@ void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc)
|
||||
}
|
||||
|
||||
/// @see rcAllocSetCustom
|
||||
void* rcAlloc(int size, rcAllocHint hint)
|
||||
void* rcAlloc(size_t size, rcAllocHint hint)
|
||||
{
|
||||
return sRecastAllocFunc(size, hint);
|
||||
}
|
||||
@ -72,17 +72,13 @@ void rcFree(void* ptr)
|
||||
/// Using this method ensures the array is at least large enough to hold
|
||||
/// the specified number of elements. This can improve performance by
|
||||
/// avoiding auto-resizing during use.
|
||||
void rcIntArray::resize(int n)
|
||||
void rcIntArray::doResize(int n)
|
||||
{
|
||||
if (n > m_cap)
|
||||
{
|
||||
if (!m_cap) m_cap = n;
|
||||
while (m_cap < n) m_cap *= 2;
|
||||
int* newData = (int*)rcAlloc(m_cap*sizeof(int), RC_ALLOC_TEMP);
|
||||
if (m_size && newData) memcpy(newData, m_data, m_size*sizeof(int));
|
||||
rcFree(m_data);
|
||||
m_data = newData;
|
||||
}
|
||||
m_size = n;
|
||||
if (!m_cap) m_cap = n;
|
||||
while (m_cap < n) m_cap *= 2;
|
||||
int* newData = (int*)rcAlloc(m_cap*sizeof(int), RC_ALLOC_TEMP);
|
||||
if (m_size && newData) memcpy(newData, m_data, m_size*sizeof(int));
|
||||
rcFree(m_data);
|
||||
m_data = newData;
|
||||
}
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf)
|
||||
const int w = chf.width;
|
||||
const int h = chf.height;
|
||||
|
||||
ctx->startTimer(RC_TIMER_ERODE_AREA);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_ERODE_AREA);
|
||||
|
||||
unsigned char* dist = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP);
|
||||
if (!dist)
|
||||
@ -215,8 +215,6 @@ bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf)
|
||||
|
||||
rcFree(dist);
|
||||
|
||||
ctx->stopTimer(RC_TIMER_ERODE_AREA);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -245,7 +243,7 @@ bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf)
|
||||
const int w = chf.width;
|
||||
const int h = chf.height;
|
||||
|
||||
ctx->startTimer(RC_TIMER_MEDIAN_AREA);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_MEDIAN_AREA);
|
||||
|
||||
unsigned char* areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP);
|
||||
if (!areas)
|
||||
@ -306,8 +304,6 @@ bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf)
|
||||
memcpy(chf.areas, areas, sizeof(unsigned char)*chf.spanCount);
|
||||
|
||||
rcFree(areas);
|
||||
|
||||
ctx->stopTimer(RC_TIMER_MEDIAN_AREA);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -322,7 +318,7 @@ void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigne
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_MARK_BOX_AREA);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_MARK_BOX_AREA);
|
||||
|
||||
int minx = (int)((bmin[0]-chf.bmin[0])/chf.cs);
|
||||
int miny = (int)((bmin[1]-chf.bmin[1])/chf.ch);
|
||||
@ -357,9 +353,6 @@ void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigne
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_MARK_BOX_AREA);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -391,7 +384,7 @@ void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts,
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_MARK_CONVEXPOLY_AREA);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_MARK_CONVEXPOLY_AREA);
|
||||
|
||||
float bmin[3], bmax[3];
|
||||
rcVcopy(bmin, verts);
|
||||
@ -448,8 +441,6 @@ void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_MARK_CONVEXPOLY_AREA);
|
||||
}
|
||||
|
||||
int rcOffsetPoly(const float* verts, const int nverts, const float offset,
|
||||
@ -541,7 +532,7 @@ void rcMarkCylinderArea(rcContext* ctx, const float* pos,
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_MARK_CYLINDER_AREA);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_MARK_CYLINDER_AREA);
|
||||
|
||||
float bmin[3], bmax[3];
|
||||
bmin[0] = pos[0] - r;
|
||||
@ -597,6 +588,4 @@ void rcMarkCylinderArea(rcContext* ctx, const float* pos,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_MARK_CYLINDER_AREA);
|
||||
}
|
||||
|
||||
@ -731,7 +731,7 @@ static void mergeRegionHoles(rcContext* ctx, rcContourRegion& region)
|
||||
for (int i = 0; i < region.nholes; i++)
|
||||
maxVerts += region.holes[i].contour->nverts;
|
||||
|
||||
rcScopedDelete<rcPotentialDiagonal> diags = (rcPotentialDiagonal*)rcAlloc(sizeof(rcPotentialDiagonal)*maxVerts, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<rcPotentialDiagonal> diags((rcPotentialDiagonal*)rcAlloc(sizeof(rcPotentialDiagonal)*maxVerts, RC_ALLOC_TEMP));
|
||||
if (!diags)
|
||||
{
|
||||
ctx->log(RC_LOG_WARNING, "mergeRegionHoles: Failed to allocated diags %d.", maxVerts);
|
||||
@ -831,7 +831,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
const int h = chf.height;
|
||||
const int borderSize = chf.borderSize;
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_CONTOURS);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_BUILD_CONTOURS);
|
||||
|
||||
rcVcopy(cset.bmin, chf.bmin);
|
||||
rcVcopy(cset.bmax, chf.bmax);
|
||||
@ -849,6 +849,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
cset.width = chf.width - chf.borderSize*2;
|
||||
cset.height = chf.height - chf.borderSize*2;
|
||||
cset.borderSize = chf.borderSize;
|
||||
cset.maxError = maxError;
|
||||
|
||||
int maxContours = rcMax((int)chf.maxRegions, 8);
|
||||
cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM);
|
||||
@ -856,7 +857,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
return false;
|
||||
cset.nconts = 0;
|
||||
|
||||
rcScopedDelete<unsigned char> flags = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<unsigned char> flags((unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP));
|
||||
if (!flags)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'flags' (%d).", chf.spanCount);
|
||||
@ -1008,7 +1009,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
if (cset.nconts > 0)
|
||||
{
|
||||
// Calculate winding of all polygons.
|
||||
rcScopedDelete<char> winding = (char*)rcAlloc(sizeof(char)*cset.nconts, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<char> winding((char*)rcAlloc(sizeof(char)*cset.nconts, RC_ALLOC_TEMP));
|
||||
if (!winding)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'hole' (%d).", cset.nconts);
|
||||
@ -1029,7 +1030,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
// Collect outline contour and holes contours per region.
|
||||
// We assume that there is one outline and multiple holes.
|
||||
const int nregions = chf.maxRegions+1;
|
||||
rcScopedDelete<rcContourRegion> regions = (rcContourRegion*)rcAlloc(sizeof(rcContourRegion)*nregions, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<rcContourRegion> regions((rcContourRegion*)rcAlloc(sizeof(rcContourRegion)*nregions, RC_ALLOC_TEMP));
|
||||
if (!regions)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'regions' (%d).", nregions);
|
||||
@ -1037,7 +1038,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
}
|
||||
memset(regions, 0, sizeof(rcContourRegion)*nregions);
|
||||
|
||||
rcScopedDelete<rcContourHole> holes = (rcContourHole*)rcAlloc(sizeof(rcContourHole)*cset.nconts, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<rcContourHole> holes((rcContourHole*)rcAlloc(sizeof(rcContourHole)*cset.nconts, RC_ALLOC_TEMP));
|
||||
if (!holes)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'holes' (%d).", cset.nconts);
|
||||
@ -1100,7 +1101,5 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_FILTER_LOW_OBSTACLES);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_FILTER_LOW_OBSTACLES);
|
||||
|
||||
const int w = solid.width;
|
||||
const int h = solid.height;
|
||||
@ -67,8 +67,6 @@ void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_FILTER_LOW_OBSTACLES);
|
||||
}
|
||||
|
||||
/// @par
|
||||
@ -86,7 +84,7 @@ void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walk
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_FILTER_BORDER);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_FILTER_BORDER);
|
||||
|
||||
const int w = solid.width;
|
||||
const int h = solid.height;
|
||||
@ -156,20 +154,19 @@ void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walk
|
||||
// The current span is close to a ledge if the drop to any
|
||||
// neighbour span is less than the walkableClimb.
|
||||
if (minh < -walkableClimb)
|
||||
{
|
||||
s->area = RC_NULL_AREA;
|
||||
|
||||
}
|
||||
// If the difference between all neighbours is too large,
|
||||
// we are at steep slope, mark the span as ledge.
|
||||
if ((asmax - asmin) > walkableClimb)
|
||||
else if ((asmax - asmin) > walkableClimb)
|
||||
{
|
||||
s->area = RC_NULL_AREA;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_FILTER_BORDER);
|
||||
}
|
||||
}
|
||||
|
||||
/// @par
|
||||
///
|
||||
@ -181,7 +178,7 @@ void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeight
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_FILTER_WALKABLE);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_FILTER_WALKABLE);
|
||||
|
||||
const int w = solid.width;
|
||||
const int h = solid.height;
|
||||
@ -202,6 +199,4 @@ void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_FILTER_WALKABLE);
|
||||
}
|
||||
|
||||
@ -87,12 +87,12 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_LAYERS);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_BUILD_LAYERS);
|
||||
|
||||
const int w = chf.width;
|
||||
const int h = chf.height;
|
||||
|
||||
rcScopedDelete<unsigned char> srcReg = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<unsigned char> srcReg((unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP));
|
||||
if (!srcReg)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'srcReg' (%d).", chf.spanCount);
|
||||
@ -101,7 +101,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
memset(srcReg,0xff,sizeof(unsigned char)*chf.spanCount);
|
||||
|
||||
const int nsweeps = chf.width;
|
||||
rcScopedDelete<rcLayerSweepSpan> sweeps = (rcLayerSweepSpan*)rcAlloc(sizeof(rcLayerSweepSpan)*nsweeps, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<rcLayerSweepSpan> sweeps((rcLayerSweepSpan*)rcAlloc(sizeof(rcLayerSweepSpan)*nsweeps, RC_ALLOC_TEMP));
|
||||
if (!sweeps)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'sweeps' (%d).", nsweeps);
|
||||
@ -212,7 +212,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
|
||||
// Allocate and init layer regions.
|
||||
const int nregs = (int)regId;
|
||||
rcScopedDelete<rcLayerRegion> regs = (rcLayerRegion*)rcAlloc(sizeof(rcLayerRegion)*nregs, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<rcLayerRegion> regs((rcLayerRegion*)rcAlloc(sizeof(rcLayerRegion)*nregs, RC_ALLOC_TEMP));
|
||||
if (!regs)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'regs' (%d).", nregs);
|
||||
@ -258,7 +258,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
const int ay = y + rcGetDirOffsetY(dir);
|
||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
|
||||
const unsigned char rai = srcReg[ai];
|
||||
if (rai != 0xff && rai != ri)
|
||||
if (rai != 0xff && rai != ri && regs[ri].nneis < RC_MAX_NEIS)
|
||||
addUnique(regs[ri].neis, regs[ri].nneis, rai);
|
||||
}
|
||||
}
|
||||
@ -446,10 +446,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
|
||||
// No layers, return empty.
|
||||
if (layerId == 0)
|
||||
{
|
||||
ctx->stopTimer(RC_TIMER_BUILD_LAYERS);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create layers.
|
||||
rcAssert(lset.layers == 0);
|
||||
@ -612,7 +609,5 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
layer->miny = layer->maxy = 0;
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_LAYERS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -528,8 +528,8 @@ static int getPolyMergeValue(unsigned short* pa, unsigned short* pb,
|
||||
return dx*dx + dy*dy;
|
||||
}
|
||||
|
||||
static void mergePolys(unsigned short* pa, unsigned short* pb, int ea, int eb,
|
||||
unsigned short* tmp, const int nvp)
|
||||
static void mergePolyVerts(unsigned short* pa, unsigned short* pb, int ea, int eb,
|
||||
unsigned short* tmp, const int nvp)
|
||||
{
|
||||
const int na = countPolyVerts(pa, nvp);
|
||||
const int nb = countPolyVerts(pb, nvp);
|
||||
@ -601,7 +601,7 @@ static bool canRemoveVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned sho
|
||||
// Find edges which share the removed vertex.
|
||||
const int maxEdges = numTouchedVerts*2;
|
||||
int nedges = 0;
|
||||
rcScopedDelete<int> edges = (int*)rcAlloc(sizeof(int)*maxEdges*3, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> edges((int*)rcAlloc(sizeof(int)*maxEdges*3, RC_ALLOC_TEMP));
|
||||
if (!edges)
|
||||
{
|
||||
ctx->log(RC_LOG_WARNING, "canRemoveVertex: Out of memory 'edges' (%d).", maxEdges*3);
|
||||
@ -681,7 +681,7 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
|
||||
}
|
||||
|
||||
int nedges = 0;
|
||||
rcScopedDelete<int> edges = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp*4, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> edges((int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp*4, RC_ALLOC_TEMP));
|
||||
if (!edges)
|
||||
{
|
||||
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'edges' (%d).", numRemovedVerts*nvp*4);
|
||||
@ -689,15 +689,15 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
|
||||
}
|
||||
|
||||
int nhole = 0;
|
||||
rcScopedDelete<int> hole = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> hole((int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP));
|
||||
if (!hole)
|
||||
{
|
||||
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hole' (%d).", numRemovedVerts*nvp);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int nhreg = 0;
|
||||
rcScopedDelete<int> hreg = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> hreg((int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP));
|
||||
if (!hreg)
|
||||
{
|
||||
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hreg' (%d).", numRemovedVerts*nvp);
|
||||
@ -705,7 +705,7 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
|
||||
}
|
||||
|
||||
int nharea = 0;
|
||||
rcScopedDelete<int> harea = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> harea((int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP));
|
||||
if (!harea)
|
||||
{
|
||||
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'harea' (%d).", numRemovedVerts*nvp);
|
||||
@ -822,21 +822,21 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
|
||||
break;
|
||||
}
|
||||
|
||||
rcScopedDelete<int> tris = (int*)rcAlloc(sizeof(int)*nhole*3, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> tris((int*)rcAlloc(sizeof(int)*nhole*3, RC_ALLOC_TEMP));
|
||||
if (!tris)
|
||||
{
|
||||
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tris' (%d).", nhole*3);
|
||||
return false;
|
||||
}
|
||||
|
||||
rcScopedDelete<int> tverts = (int*)rcAlloc(sizeof(int)*nhole*4, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> tverts((int*)rcAlloc(sizeof(int)*nhole*4, RC_ALLOC_TEMP));
|
||||
if (!tverts)
|
||||
{
|
||||
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tverts' (%d).", nhole*4);
|
||||
return false;
|
||||
}
|
||||
|
||||
rcScopedDelete<int> thole = (int*)rcAlloc(sizeof(int)*nhole, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> thole((int*)rcAlloc(sizeof(int)*nhole, RC_ALLOC_TEMP));
|
||||
if (!thole)
|
||||
{
|
||||
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'thole' (%d).", nhole);
|
||||
@ -863,19 +863,19 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
|
||||
}
|
||||
|
||||
// Merge the hole triangles back to polygons.
|
||||
rcScopedDelete<unsigned short> polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*(ntris+1)*nvp, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<unsigned short> polys((unsigned short*)rcAlloc(sizeof(unsigned short)*(ntris+1)*nvp, RC_ALLOC_TEMP));
|
||||
if (!polys)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'polys' (%d).", (ntris+1)*nvp);
|
||||
return false;
|
||||
}
|
||||
rcScopedDelete<unsigned short> pregs = (unsigned short*)rcAlloc(sizeof(unsigned short)*ntris, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<unsigned short> pregs((unsigned short*)rcAlloc(sizeof(unsigned short)*ntris, RC_ALLOC_TEMP));
|
||||
if (!pregs)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pregs' (%d).", ntris);
|
||||
return false;
|
||||
}
|
||||
rcScopedDelete<unsigned char> pareas = (unsigned char*)rcAlloc(sizeof(unsigned char)*ntris, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<unsigned char> pareas((unsigned char*)rcAlloc(sizeof(unsigned char)*ntris, RC_ALLOC_TEMP));
|
||||
if (!pareas)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pareas' (%d).", ntris);
|
||||
@ -895,7 +895,14 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
|
||||
polys[npolys*nvp+0] = (unsigned short)hole[t[0]];
|
||||
polys[npolys*nvp+1] = (unsigned short)hole[t[1]];
|
||||
polys[npolys*nvp+2] = (unsigned short)hole[t[2]];
|
||||
pregs[npolys] = (unsigned short)hreg[t[0]];
|
||||
|
||||
// If this polygon covers multiple region types then
|
||||
// mark it as such
|
||||
if (hreg[t[0]] != hreg[t[1]] || hreg[t[1]] != hreg[t[2]])
|
||||
pregs[npolys] = RC_MULTIPLE_REGS;
|
||||
else
|
||||
pregs[npolys] = (unsigned short)hreg[t[0]];
|
||||
|
||||
pareas[npolys] = (unsigned char)harea[t[0]];
|
||||
npolys++;
|
||||
}
|
||||
@ -936,7 +943,10 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
|
||||
// Found best, merge.
|
||||
unsigned short* pa = &polys[bestPa*nvp];
|
||||
unsigned short* pb = &polys[bestPb*nvp];
|
||||
mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp);
|
||||
mergePolyVerts(pa, pb, bestEa, bestEb, tmpPoly, nvp);
|
||||
if (pregs[bestPa] != pregs[bestPb])
|
||||
pregs[bestPa] = RC_MULTIPLE_REGS;
|
||||
|
||||
unsigned short* last = &polys[(npolys-1)*nvp];
|
||||
if (pb != last)
|
||||
memcpy(pb, last, sizeof(unsigned short)*nvp);
|
||||
@ -983,13 +993,14 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_POLYMESH);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_BUILD_POLYMESH);
|
||||
|
||||
rcVcopy(mesh.bmin, cset.bmin);
|
||||
rcVcopy(mesh.bmax, cset.bmax);
|
||||
mesh.cs = cset.cs;
|
||||
mesh.ch = cset.ch;
|
||||
mesh.borderSize = cset.borderSize;
|
||||
mesh.maxEdgeError = cset.maxError;
|
||||
|
||||
int maxVertices = 0;
|
||||
int maxTris = 0;
|
||||
@ -1009,7 +1020,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
|
||||
return false;
|
||||
}
|
||||
|
||||
rcScopedDelete<unsigned char> vflags = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxVertices, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<unsigned char> vflags((unsigned char*)rcAlloc(sizeof(unsigned char)*maxVertices, RC_ALLOC_TEMP));
|
||||
if (!vflags)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'vflags' (%d).", maxVertices);
|
||||
@ -1052,7 +1063,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
|
||||
memset(mesh.regs, 0, sizeof(unsigned short)*maxTris);
|
||||
memset(mesh.areas, 0, sizeof(unsigned char)*maxTris);
|
||||
|
||||
rcScopedDelete<int> nextVert = (int*)rcAlloc(sizeof(int)*maxVertices, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> nextVert((int*)rcAlloc(sizeof(int)*maxVertices, RC_ALLOC_TEMP));
|
||||
if (!nextVert)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'nextVert' (%d).", maxVertices);
|
||||
@ -1060,7 +1071,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
|
||||
}
|
||||
memset(nextVert, 0, sizeof(int)*maxVertices);
|
||||
|
||||
rcScopedDelete<int> firstVert = (int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> firstVert((int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP));
|
||||
if (!firstVert)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT);
|
||||
@ -1069,19 +1080,19 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
|
||||
for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i)
|
||||
firstVert[i] = -1;
|
||||
|
||||
rcScopedDelete<int> indices = (int*)rcAlloc(sizeof(int)*maxVertsPerCont, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> indices((int*)rcAlloc(sizeof(int)*maxVertsPerCont, RC_ALLOC_TEMP));
|
||||
if (!indices)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'indices' (%d).", maxVertsPerCont);
|
||||
return false;
|
||||
}
|
||||
rcScopedDelete<int> tris = (int*)rcAlloc(sizeof(int)*maxVertsPerCont*3, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> tris((int*)rcAlloc(sizeof(int)*maxVertsPerCont*3, RC_ALLOC_TEMP));
|
||||
if (!tris)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'tris' (%d).", maxVertsPerCont*3);
|
||||
return false;
|
||||
}
|
||||
rcScopedDelete<unsigned short> polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*(maxVertsPerCont+1)*nvp, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<unsigned short> polys((unsigned short*)rcAlloc(sizeof(unsigned short)*(maxVertsPerCont+1)*nvp, RC_ALLOC_TEMP));
|
||||
if (!polys)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'polys' (%d).", maxVertsPerCont*nvp);
|
||||
@ -1182,7 +1193,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
|
||||
// Found best, merge.
|
||||
unsigned short* pa = &polys[bestPa*nvp];
|
||||
unsigned short* pb = &polys[bestPb*nvp];
|
||||
mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp);
|
||||
mergePolyVerts(pa, pb, bestEa, bestEb, tmpPoly, nvp);
|
||||
unsigned short* lastPoly = &polys[(npolys-1)*nvp];
|
||||
if (pb != lastPoly)
|
||||
memcpy(pb, lastPoly, sizeof(unsigned short)*nvp);
|
||||
@ -1293,8 +1304,6 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff);
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_POLYMESH);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1306,7 +1315,7 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
|
||||
if (!nmeshes || !meshes)
|
||||
return true;
|
||||
|
||||
ctx->startTimer(RC_TIMER_MERGE_POLYMESH);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_MERGE_POLYMESH);
|
||||
|
||||
mesh.nvp = meshes[0]->nvp;
|
||||
mesh.cs = meshes[0]->cs;
|
||||
@ -1367,7 +1376,7 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
|
||||
}
|
||||
memset(mesh.flags, 0, sizeof(unsigned short)*maxPolys);
|
||||
|
||||
rcScopedDelete<int> nextVert = (int*)rcAlloc(sizeof(int)*maxVerts, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> nextVert((int*)rcAlloc(sizeof(int)*maxVerts, RC_ALLOC_TEMP));
|
||||
if (!nextVert)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'nextVert' (%d).", maxVerts);
|
||||
@ -1375,7 +1384,7 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
|
||||
}
|
||||
memset(nextVert, 0, sizeof(int)*maxVerts);
|
||||
|
||||
rcScopedDelete<int> firstVert = (int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> firstVert((int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP));
|
||||
if (!firstVert)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT);
|
||||
@ -1384,7 +1393,7 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
|
||||
for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i)
|
||||
firstVert[i] = -1;
|
||||
|
||||
rcScopedDelete<unsigned short> vremap = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVertsPerMesh, RC_ALLOC_PERM);
|
||||
rcScopedDelete<unsigned short> vremap((unsigned short*)rcAlloc(sizeof(unsigned short)*maxVertsPerMesh, RC_ALLOC_PERM));
|
||||
if (!vremap)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'vremap' (%d).", maxVertsPerMesh);
|
||||
@ -1474,8 +1483,6 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
|
||||
ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff);
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_MERGE_POLYMESH);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1499,6 +1506,7 @@ bool rcCopyPolyMesh(rcContext* ctx, const rcPolyMesh& src, rcPolyMesh& dst)
|
||||
dst.cs = src.cs;
|
||||
dst.ch = src.ch;
|
||||
dst.borderSize = src.borderSize;
|
||||
dst.maxEdgeError = src.maxEdgeError;
|
||||
|
||||
dst.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.nverts*3, RC_ALLOC_PERM);
|
||||
if (!dst.verts)
|
||||
|
||||
@ -202,7 +202,7 @@ static float distToPoly(int nvert, const float* verts, const float* p)
|
||||
|
||||
static unsigned short getHeight(const float fx, const float fy, const float fz,
|
||||
const float /*cs*/, const float ics, const float ch,
|
||||
const rcHeightPatch& hp)
|
||||
const int radius, const rcHeightPatch& hp)
|
||||
{
|
||||
int ix = (int)floorf(fx*ics + 0.01f);
|
||||
int iz = (int)floorf(fz*ics + 0.01f);
|
||||
@ -212,23 +212,69 @@ static unsigned short getHeight(const float fx, const float fy, const float fz,
|
||||
if (h == RC_UNSET_HEIGHT)
|
||||
{
|
||||
// Special case when data might be bad.
|
||||
// Find nearest neighbour pixel which has valid height.
|
||||
const int off[8*2] = { -1,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1};
|
||||
// Walk adjacent cells in a spiral up to 'radius', and look
|
||||
// for a pixel which has a valid height.
|
||||
int x = 1, z = 0, dx = 1, dz = 0;
|
||||
int maxSize = radius * 2 + 1;
|
||||
int maxIter = maxSize * maxSize - 1;
|
||||
|
||||
int nextRingIterStart = 8;
|
||||
int nextRingIters = 16;
|
||||
|
||||
float dmin = FLT_MAX;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
for (int i = 0; i < maxIter; i++)
|
||||
{
|
||||
const int nx = ix+off[i*2+0];
|
||||
const int nz = iz+off[i*2+1];
|
||||
if (nx < 0 || nz < 0 || nx >= hp.width || nz >= hp.height) continue;
|
||||
const unsigned short nh = hp.data[nx+nz*hp.width];
|
||||
if (nh == RC_UNSET_HEIGHT) continue;
|
||||
|
||||
const float d = fabsf(nh*ch - fy);
|
||||
if (d < dmin)
|
||||
const int nx = ix + x;
|
||||
const int nz = iz + z;
|
||||
|
||||
if (nx >= 0 && nz >= 0 && nx < hp.width && nz < hp.height)
|
||||
{
|
||||
h = nh;
|
||||
dmin = d;
|
||||
const unsigned short nh = hp.data[nx + nz*hp.width];
|
||||
if (nh != RC_UNSET_HEIGHT)
|
||||
{
|
||||
const float d = fabsf(nh*ch - fy);
|
||||
if (d < dmin)
|
||||
{
|
||||
h = nh;
|
||||
dmin = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We are searching in a grid which looks approximately like this:
|
||||
// __________
|
||||
// |2 ______ 2|
|
||||
// | |1 __ 1| |
|
||||
// | | |__| | |
|
||||
// | |______| |
|
||||
// |__________|
|
||||
// We want to find the best height as close to the center cell as possible. This means that
|
||||
// if we find a height in one of the neighbor cells to the center, we don't want to
|
||||
// expand further out than the 8 neighbors - we want to limit our search to the closest
|
||||
// of these "rings", but the best height in the ring.
|
||||
// For example, the center is just 1 cell. We checked that at the entrance to the function.
|
||||
// The next "ring" contains 8 cells (marked 1 above). Those are all the neighbors to the center cell.
|
||||
// The next one again contains 16 cells (marked 2). In general each ring has 8 additional cells, which
|
||||
// can be thought of as adding 2 cells around the "center" of each side when we expand the ring.
|
||||
// Here we detect if we are about to enter the next ring, and if we are and we have found
|
||||
// a height, we abort the search.
|
||||
if (i + 1 == nextRingIterStart)
|
||||
{
|
||||
if (h != RC_UNSET_HEIGHT)
|
||||
break;
|
||||
|
||||
nextRingIterStart += nextRingIters;
|
||||
nextRingIters += 8;
|
||||
}
|
||||
|
||||
if ((x == z) || ((x < 0) && (x == -z)) || ((x > 0) && (x == 1 - z)))
|
||||
{
|
||||
int tmp = dx;
|
||||
dx = -dz;
|
||||
dz = tmp;
|
||||
}
|
||||
x += dx;
|
||||
z += dz;
|
||||
}
|
||||
}
|
||||
return h;
|
||||
@ -511,7 +557,7 @@ static float polyMinExtent(const float* verts, const int nverts)
|
||||
inline int prev(int i, int n) { return i-1 >= 0 ? i-1 : n-1; }
|
||||
inline int next(int i, int n) { return i+1 < n ? i+1 : 0; }
|
||||
|
||||
static void triangulateHull(const int nverts, const float* verts, const int nhull, const int* hull, rcIntArray& tris)
|
||||
static void triangulateHull(const int /*nverts*/, const float* verts, const int nhull, const int* hull, rcIntArray& tris)
|
||||
{
|
||||
int start = 0, left = 1, right = nhull-1;
|
||||
|
||||
@ -590,9 +636,9 @@ inline float getJitterY(const int i)
|
||||
|
||||
static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||
const float sampleDist, const float sampleMaxError,
|
||||
const rcCompactHeightfield& chf, const rcHeightPatch& hp,
|
||||
float* verts, int& nverts, rcIntArray& tris,
|
||||
rcIntArray& edges, rcIntArray& samples)
|
||||
const int heightSearchRadius, const rcCompactHeightfield& chf,
|
||||
const rcHeightPatch& hp, float* verts, int& nverts,
|
||||
rcIntArray& tris, rcIntArray& edges, rcIntArray& samples)
|
||||
{
|
||||
static const int MAX_VERTS = 127;
|
||||
static const int MAX_TRIS = 255; // Max tris for delaunay is 2n-2-k (n=num verts, k=num hull verts).
|
||||
@ -661,7 +707,7 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||
pos[0] = vj[0] + dx*u;
|
||||
pos[1] = vj[1] + dy*u;
|
||||
pos[2] = vj[2] + dz*u;
|
||||
pos[1] = getHeight(pos[0],pos[1],pos[2], cs, ics, chf.ch, hp)*chf.ch;
|
||||
pos[1] = getHeight(pos[0],pos[1],pos[2], cs, ics, chf.ch, heightSearchRadius, hp)*chf.ch;
|
||||
}
|
||||
// Simplify samples.
|
||||
int idx[MAX_VERTS_PER_EDGE] = {0,nn};
|
||||
@ -769,7 +815,7 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||
// Make sure the samples are not too close to the edges.
|
||||
if (distToPoly(nin,in,pt) > -sampleDist/2) continue;
|
||||
samples.push(x);
|
||||
samples.push(getHeight(pt[0], pt[1], pt[2], cs, ics, chf.ch, hp));
|
||||
samples.push(getHeight(pt[0], pt[1], pt[2], cs, ics, chf.ch, heightSearchRadius, hp));
|
||||
samples.push(z);
|
||||
samples.push(0); // Not added
|
||||
}
|
||||
@ -834,33 +880,25 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void getHeightDataSeedsFromVertices(const rcCompactHeightfield& chf,
|
||||
const unsigned short* poly, const int npoly,
|
||||
const unsigned short* verts, const int bs,
|
||||
rcHeightPatch& hp, rcIntArray& stack)
|
||||
static void seedArrayWithPolyCenter(rcContext* ctx, const rcCompactHeightfield& chf,
|
||||
const unsigned short* poly, const int npoly,
|
||||
const unsigned short* verts, const int bs,
|
||||
rcHeightPatch& hp, rcIntArray& array)
|
||||
{
|
||||
// Floodfill the heightfield to get 2D height data,
|
||||
// starting at vertex locations as seeds.
|
||||
|
||||
// Note: Reads to the compact heightfield are offset by border size (bs)
|
||||
// since border size offset is already removed from the polymesh vertices.
|
||||
|
||||
memset(hp.data, 0, sizeof(unsigned short)*hp.width*hp.height);
|
||||
|
||||
stack.resize(0);
|
||||
|
||||
static const int offset[9*2] =
|
||||
{
|
||||
0,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1, -1,0,
|
||||
};
|
||||
|
||||
// Use poly vertices as seed points for the flood fill.
|
||||
for (int j = 0; j < npoly; ++j)
|
||||
// Find cell closest to a poly vertex
|
||||
int startCellX = 0, startCellY = 0, startSpanIndex = -1;
|
||||
int dmin = RC_UNSET_HEIGHT;
|
||||
for (int j = 0; j < npoly && dmin > 0; ++j)
|
||||
{
|
||||
int cx = 0, cz = 0, ci =-1;
|
||||
int dmin = RC_UNSET_HEIGHT;
|
||||
for (int k = 0; k < 9; ++k)
|
||||
for (int k = 0; k < 9 && dmin > 0; ++k)
|
||||
{
|
||||
const int ax = (int)verts[poly[j]*3+0] + offset[k*2+0];
|
||||
const int ay = (int)verts[poly[j]*3+1];
|
||||
@ -870,191 +908,208 @@ static void getHeightDataSeedsFromVertices(const rcCompactHeightfield& chf,
|
||||
continue;
|
||||
|
||||
const rcCompactCell& c = chf.cells[(ax+bs)+(az+bs)*chf.width];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni && dmin > 0; ++i)
|
||||
{
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
int d = rcAbs(ay - (int)s.y);
|
||||
if (d < dmin)
|
||||
{
|
||||
cx = ax;
|
||||
cz = az;
|
||||
ci = i;
|
||||
startCellX = ax;
|
||||
startCellY = az;
|
||||
startSpanIndex = i;
|
||||
dmin = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ci != -1)
|
||||
{
|
||||
stack.push(cx);
|
||||
stack.push(cz);
|
||||
stack.push(ci);
|
||||
}
|
||||
}
|
||||
|
||||
// Find center of the polygon using flood fill.
|
||||
int pcx = 0, pcz = 0;
|
||||
rcAssert(startSpanIndex != -1);
|
||||
// Find center of the polygon
|
||||
int pcx = 0, pcy = 0;
|
||||
for (int j = 0; j < npoly; ++j)
|
||||
{
|
||||
pcx += (int)verts[poly[j]*3+0];
|
||||
pcz += (int)verts[poly[j]*3+2];
|
||||
pcy += (int)verts[poly[j]*3+2];
|
||||
}
|
||||
pcx /= npoly;
|
||||
pcz /= npoly;
|
||||
pcy /= npoly;
|
||||
|
||||
for (int i = 0; i < stack.size(); i += 3)
|
||||
// Use seeds array as a stack for DFS
|
||||
array.resize(0);
|
||||
array.push(startCellX);
|
||||
array.push(startCellY);
|
||||
array.push(startSpanIndex);
|
||||
|
||||
int dirs[] = { 0, 1, 2, 3 };
|
||||
memset(hp.data, 0, sizeof(unsigned short)*hp.width*hp.height);
|
||||
// DFS to move to the center. Note that we need a DFS here and can not just move
|
||||
// directly towards the center without recording intermediate nodes, even though the polygons
|
||||
// are convex. In very rare we can get stuck due to contour simplification if we do not
|
||||
// record nodes.
|
||||
int cx = -1, cy = -1, ci = -1;
|
||||
while (true)
|
||||
{
|
||||
int cx = stack[i+0];
|
||||
int cy = stack[i+1];
|
||||
int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width;
|
||||
hp.data[idx] = 1;
|
||||
}
|
||||
|
||||
while (stack.size() > 0)
|
||||
{
|
||||
int ci = stack.pop();
|
||||
int cy = stack.pop();
|
||||
int cx = stack.pop();
|
||||
|
||||
// Check if close to center of the polygon.
|
||||
if (rcAbs(cx-pcx) <= 1 && rcAbs(cy-pcz) <= 1)
|
||||
if (array.size() < 3)
|
||||
{
|
||||
stack.resize(0);
|
||||
stack.push(cx);
|
||||
stack.push(cy);
|
||||
stack.push(ci);
|
||||
ctx->log(RC_LOG_WARNING, "Walk towards polygon center failed to reach center");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
ci = array.pop();
|
||||
cy = array.pop();
|
||||
cx = array.pop();
|
||||
|
||||
if (cx == pcx && cy == pcy)
|
||||
break;
|
||||
|
||||
// If we are already at the correct X-position, prefer direction
|
||||
// directly towards the center in the Y-axis; otherwise prefer
|
||||
// direction in the X-axis
|
||||
int directDir;
|
||||
if (cx == pcx)
|
||||
directDir = rcGetDirForOffset(0, pcy > cy ? 1 : -1);
|
||||
else
|
||||
directDir = rcGetDirForOffset(pcx > cx ? 1 : -1, 0);
|
||||
|
||||
// Push the direct dir last so we start with this on next iteration
|
||||
rcSwap(dirs[directDir], dirs[3]);
|
||||
|
||||
const rcCompactSpan& cs = chf.spans[ci];
|
||||
|
||||
for (int dir = 0; dir < 4; ++dir)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (rcGetCon(cs, dir) == RC_NOT_CONNECTED) continue;
|
||||
|
||||
const int ax = cx + rcGetDirOffsetX(dir);
|
||||
const int ay = cy + rcGetDirOffsetY(dir);
|
||||
|
||||
if (ax < hp.xmin || ax >= (hp.xmin+hp.width) ||
|
||||
ay < hp.ymin || ay >= (hp.ymin+hp.height))
|
||||
int dir = dirs[i];
|
||||
if (rcGetCon(cs, dir) == RC_NOT_CONNECTED)
|
||||
continue;
|
||||
|
||||
if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != 0)
|
||||
|
||||
int newX = cx + rcGetDirOffsetX(dir);
|
||||
int newY = cy + rcGetDirOffsetY(dir);
|
||||
|
||||
int hpx = newX - hp.xmin;
|
||||
int hpy = newY - hp.ymin;
|
||||
if (hpx < 0 || hpx >= hp.width || hpy < 0 || hpy >= hp.height)
|
||||
continue;
|
||||
|
||||
const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir);
|
||||
|
||||
int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width;
|
||||
hp.data[idx] = 1;
|
||||
|
||||
stack.push(ax);
|
||||
stack.push(ay);
|
||||
stack.push(ai);
|
||||
|
||||
if (hp.data[hpx+hpy*hp.width] != 0)
|
||||
continue;
|
||||
|
||||
hp.data[hpx+hpy*hp.width] = 1;
|
||||
array.push(newX);
|
||||
array.push(newY);
|
||||
array.push((int)chf.cells[(newX+bs)+(newY+bs)*chf.width].index + rcGetCon(cs, dir));
|
||||
}
|
||||
|
||||
rcSwap(dirs[directDir], dirs[3]);
|
||||
}
|
||||
|
||||
|
||||
array.resize(0);
|
||||
// getHeightData seeds are given in coordinates with borders
|
||||
array.push(cx+bs);
|
||||
array.push(cy+bs);
|
||||
array.push(ci);
|
||||
|
||||
memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height);
|
||||
|
||||
// Mark start locations.
|
||||
for (int i = 0; i < stack.size(); i += 3)
|
||||
{
|
||||
int cx = stack[i+0];
|
||||
int cy = stack[i+1];
|
||||
int ci = stack[i+2];
|
||||
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;
|
||||
}
|
||||
|
||||
const rcCompactSpan& cs = chf.spans[ci];
|
||||
hp.data[cx-hp.xmin+(cy-hp.ymin)*hp.width] = cs.y;
|
||||
}
|
||||
|
||||
|
||||
static void push3(rcIntArray& queue, int v1, int v2, int v3)
|
||||
{
|
||||
queue.resize(queue.size() + 3);
|
||||
queue[queue.size() - 3] = v1;
|
||||
queue[queue.size() - 2] = v2;
|
||||
queue[queue.size() - 1] = v3;
|
||||
}
|
||||
|
||||
static void getHeightData(const rcCompactHeightfield& chf,
|
||||
static void getHeightData(rcContext* ctx, const rcCompactHeightfield& chf,
|
||||
const unsigned short* poly, const int npoly,
|
||||
const unsigned short* verts, const int bs,
|
||||
rcHeightPatch& hp, rcIntArray& stack,
|
||||
rcHeightPatch& hp, rcIntArray& queue,
|
||||
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);
|
||||
queue.resize(0);
|
||||
// Set all heights to RC_UNSET_HEIGHT.
|
||||
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++)
|
||||
// We cannot sample from this poly if it was created from polys
|
||||
// of different regions. If it was then it could potentially be overlapping
|
||||
// with polys of that region and the heights sampled here could be wrong.
|
||||
if (region != RC_MULTIPLE_REGS)
|
||||
{
|
||||
int y = hp.ymin + hy + bs;
|
||||
for (int hx = 0; hx < hp.width; hx++)
|
||||
// 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 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)
|
||||
int y = hp.ymin + hy + bs;
|
||||
for (int hx = 0; hx < hp.width; hx++)
|
||||
{
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
if (s.reg == region)
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
if (s.reg == region)
|
||||
{
|
||||
if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
|
||||
{
|
||||
border = true;
|
||||
break;
|
||||
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)
|
||||
push3(queue, x, y, i);
|
||||
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 the polygon does not contain any points from the current region (rare, but happens)
|
||||
// or if it could potentially be overlapping polygons of the same region,
|
||||
// then use the center as the seed point.
|
||||
if (empty)
|
||||
getHeightDataSeedsFromVertices(chf, poly, npoly, verts, bs, hp, stack);
|
||||
seedArrayWithPolyCenter(ctx, chf, poly, npoly, verts, bs, hp, queue);
|
||||
|
||||
static const int RETRACT_SIZE = 256;
|
||||
int head = 0;
|
||||
|
||||
while (head*3 < stack.size())
|
||||
// We assume the seed is centered in the polygon, so a BFS to collect
|
||||
// height data will ensure we do not move onto overlapping polygons and
|
||||
// sample wrong heights.
|
||||
while (head*3 < queue.size())
|
||||
{
|
||||
int cx = stack[head*3+0];
|
||||
int cy = stack[head*3+1];
|
||||
int ci = stack[head*3+2];
|
||||
int cx = queue[head*3+0];
|
||||
int cy = queue[head*3+1];
|
||||
int ci = queue[head*3+2];
|
||||
head++;
|
||||
if (head >= RETRACT_SIZE)
|
||||
{
|
||||
head = 0;
|
||||
if (stack.size() > RETRACT_SIZE*3)
|
||||
memmove(&stack[0], &stack[RETRACT_SIZE*3], sizeof(int)*(stack.size()-RETRACT_SIZE*3));
|
||||
stack.resize(stack.size()-RETRACT_SIZE*3);
|
||||
if (queue.size() > RETRACT_SIZE*3)
|
||||
memmove(&queue[0], &queue[RETRACT_SIZE*3], sizeof(int)*(queue.size()-RETRACT_SIZE*3));
|
||||
queue.resize(queue.size()-RETRACT_SIZE*3);
|
||||
}
|
||||
|
||||
const rcCompactSpan& cs = chf.spans[ci];
|
||||
@ -1067,7 +1122,7 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
||||
const int hx = ax - hp.xmin - bs;
|
||||
const int hy = ay - hp.ymin - bs;
|
||||
|
||||
if (hx < 0 || hx >= hp.width || hy < 0 || hy >= hp.height)
|
||||
if ((unsigned int)hx >= (unsigned int)hp.width || (unsigned int)hy >= (unsigned int)hp.height)
|
||||
continue;
|
||||
|
||||
if (hp.data[hx + hy*hp.width] != RC_UNSET_HEIGHT)
|
||||
@ -1078,9 +1133,7 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
||||
|
||||
hp.data[hx + hy*hp.width] = as.y;
|
||||
|
||||
stack.push(ax);
|
||||
stack.push(ay);
|
||||
stack.push(ai);
|
||||
push3(queue, ax, ay, ai);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1120,7 +1173,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_POLYMESHDETAIL);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_BUILD_POLYMESHDETAIL);
|
||||
|
||||
if (mesh.nverts == 0 || mesh.npolys == 0)
|
||||
return true;
|
||||
@ -1130,23 +1183,24 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||
const float ch = mesh.ch;
|
||||
const float* orig = mesh.bmin;
|
||||
const int borderSize = mesh.borderSize;
|
||||
const int heightSearchRadius = rcMax(1, (int)ceilf(mesh.maxEdgeError));
|
||||
|
||||
rcIntArray edges(64);
|
||||
rcIntArray tris(512);
|
||||
rcIntArray stack(512);
|
||||
rcIntArray arr(512);
|
||||
rcIntArray samples(512);
|
||||
float verts[256*3];
|
||||
rcHeightPatch hp;
|
||||
int nPolyVerts = 0;
|
||||
int maxhw = 0, maxhh = 0;
|
||||
|
||||
rcScopedDelete<int> bounds = (int*)rcAlloc(sizeof(int)*mesh.npolys*4, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<int> bounds((int*)rcAlloc(sizeof(int)*mesh.npolys*4, RC_ALLOC_TEMP));
|
||||
if (!bounds)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'bounds' (%d).", mesh.npolys*4);
|
||||
return false;
|
||||
}
|
||||
rcScopedDelete<float> poly = (float*)rcAlloc(sizeof(float)*nvp*3, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<float> poly((float*)rcAlloc(sizeof(float)*nvp*3, RC_ALLOC_TEMP));
|
||||
if (!poly)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'poly' (%d).", nvp*3);
|
||||
@ -1240,13 +1294,14 @@ 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, mesh.regs[i]);
|
||||
getHeightData(ctx, chf, p, npoly, mesh.verts, borderSize, hp, arr, mesh.regs[i]);
|
||||
|
||||
// Build detail mesh.
|
||||
int nverts = 0;
|
||||
if (!buildPolyDetail(ctx, poly, npoly,
|
||||
sampleDist, sampleMaxError,
|
||||
chf, hp, verts, nverts, tris,
|
||||
heightSearchRadius, chf, hp,
|
||||
verts, nverts, tris,
|
||||
edges, samples))
|
||||
{
|
||||
return false;
|
||||
@ -1327,8 +1382,6 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||
}
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_POLYMESHDETAIL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1337,7 +1390,7 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_MERGE_POLYMESHDETAIL);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_MERGE_POLYMESHDETAIL);
|
||||
|
||||
int maxVerts = 0;
|
||||
int maxTris = 0;
|
||||
@ -1406,7 +1459,5 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
|
||||
}
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_MERGE_POLYMESHDETAIL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ static void freeSpan(rcHeightfield& hf, rcSpan* ptr)
|
||||
hf.freelist = ptr;
|
||||
}
|
||||
|
||||
static void addSpan(rcHeightfield& hf, const int x, const int y,
|
||||
static bool addSpan(rcHeightfield& hf, const int x, const int y,
|
||||
const unsigned short smin, const unsigned short smax,
|
||||
const unsigned char area, const int flagMergeThr)
|
||||
{
|
||||
@ -90,6 +90,8 @@ static void addSpan(rcHeightfield& hf, const int x, const int y,
|
||||
int idx = x + y*hf.width;
|
||||
|
||||
rcSpan* s = allocSpan(hf);
|
||||
if (!s)
|
||||
return false;
|
||||
s->smin = smin;
|
||||
s->smax = smax;
|
||||
s->area = area;
|
||||
@ -99,7 +101,7 @@ static void addSpan(rcHeightfield& hf, const int x, const int y,
|
||||
if (!hf.spans[idx])
|
||||
{
|
||||
hf.spans[idx] = s;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
rcSpan* prev = 0;
|
||||
rcSpan* cur = hf.spans[idx];
|
||||
@ -152,6 +154,8 @@ static void addSpan(rcHeightfield& hf, const int x, const int y,
|
||||
s->next = hf.spans[idx];
|
||||
hf.spans[idx] = s;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @par
|
||||
@ -161,12 +165,19 @@ static void addSpan(rcHeightfield& hf, const int x, const int y,
|
||||
/// from the existing span, the span flags are merged.
|
||||
///
|
||||
/// @see rcHeightfield, rcSpan.
|
||||
void rcAddSpan(rcContext* /*ctx*/, rcHeightfield& hf, const int x, const int y,
|
||||
bool rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y,
|
||||
const unsigned short smin, const unsigned short smax,
|
||||
const unsigned char area, const int flagMergeThr)
|
||||
{
|
||||
// rcAssert(ctx);
|
||||
addSpan(hf, x,y, smin, smax, area, flagMergeThr);
|
||||
rcAssert(ctx);
|
||||
|
||||
if (!addSpan(hf, x, y, smin, smax, area, flagMergeThr))
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcAddSpan: Out of memory.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// divides a convex polygons into two convex polygons on both sides of a line
|
||||
@ -227,7 +238,7 @@ static void dividePoly(const float* in, int nin,
|
||||
|
||||
|
||||
|
||||
static void rasterizeTri(const float* v0, const float* v1, const float* v2,
|
||||
static bool rasterizeTri(const float* v0, const float* v1, const float* v2,
|
||||
const unsigned char area, rcHeightfield& hf,
|
||||
const float* bmin, const float* bmax,
|
||||
const float cs, const float ics, const float ich,
|
||||
@ -248,7 +259,7 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2,
|
||||
|
||||
// If the triangle does not touch the bbox of the heightfield, skip the triagle.
|
||||
if (!overlapBounds(bmin, bmax, tmin, tmax))
|
||||
return;
|
||||
return true;
|
||||
|
||||
// Calculate the footprint of the triangle on the grid's y-axis
|
||||
int y0 = (int)((tmin[2] - bmin[2])*ics);
|
||||
@ -315,9 +326,12 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2,
|
||||
unsigned short ismin = (unsigned short)rcClamp((int)floorf(smin * ich), 0, RC_SPAN_MAX_HEIGHT);
|
||||
unsigned short ismax = (unsigned short)rcClamp((int)ceilf(smax * ich), (int)ismin+1, RC_SPAN_MAX_HEIGHT);
|
||||
|
||||
addSpan(hf, x, y, ismin, ismax, area, flagMergeThr);
|
||||
if (!addSpan(hf, x, y, ismin, ismax, area, flagMergeThr))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @par
|
||||
@ -325,19 +339,23 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2,
|
||||
/// No spans will be added if the triangle does not overlap the heightfield grid.
|
||||
///
|
||||
/// @see rcHeightfield
|
||||
void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
|
||||
bool rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
|
||||
const unsigned char area, rcHeightfield& solid,
|
||||
const int flagMergeThr)
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_RASTERIZE_TRIANGLES);
|
||||
|
||||
const float ics = 1.0f/solid.cs;
|
||||
const float ich = 1.0f/solid.ch;
|
||||
rasterizeTri(v0, v1, v2, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
|
||||
if (!rasterizeTri(v0, v1, v2, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr))
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcRasterizeTriangle: Out of memory.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @par
|
||||
@ -345,13 +363,13 @@ void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const
|
||||
/// Spans will only be added for triangles that overlap the heightfield grid.
|
||||
///
|
||||
/// @see rcHeightfield
|
||||
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
||||
bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
||||
const int* tris, const unsigned char* areas, const int nt,
|
||||
rcHeightfield& solid, const int flagMergeThr)
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_RASTERIZE_TRIANGLES);
|
||||
|
||||
const float ics = 1.0f/solid.cs;
|
||||
const float ich = 1.0f/solid.ch;
|
||||
@ -361,12 +379,15 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
||||
const float* v0 = &verts[tris[i*3+0]*3];
|
||||
const float* v1 = &verts[tris[i*3+1]*3];
|
||||
const float* v2 = &verts[tris[i*3+2]*3];
|
||||
|
||||
// Rasterize.
|
||||
rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
|
||||
if (!rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr))
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @par
|
||||
@ -374,13 +395,13 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
||||
/// Spans will only be added for triangles that overlap the heightfield grid.
|
||||
///
|
||||
/// @see rcHeightfield
|
||||
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
||||
bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
||||
const unsigned short* tris, const unsigned char* areas, const int nt,
|
||||
rcHeightfield& solid, const int flagMergeThr)
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_RASTERIZE_TRIANGLES);
|
||||
|
||||
const float ics = 1.0f/solid.cs;
|
||||
const float ich = 1.0f/solid.ch;
|
||||
@ -391,10 +412,14 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
||||
const float* v1 = &verts[tris[i*3+1]*3];
|
||||
const float* v2 = &verts[tris[i*3+2]*3];
|
||||
// Rasterize.
|
||||
rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
|
||||
if (!rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr))
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @par
|
||||
@ -402,12 +427,12 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
|
||||
/// Spans will only be added for triangles that overlap the heightfield grid.
|
||||
///
|
||||
/// @see rcHeightfield
|
||||
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
|
||||
bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
|
||||
rcHeightfield& solid, const int flagMergeThr)
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_RASTERIZE_TRIANGLES);
|
||||
|
||||
const float ics = 1.0f/solid.cs;
|
||||
const float ich = 1.0f/solid.ch;
|
||||
@ -418,8 +443,12 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned cha
|
||||
const float* v1 = &verts[(i*3+1)*3];
|
||||
const float* v2 = &verts[(i*3+2)*3];
|
||||
// Rasterize.
|
||||
rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
|
||||
if (!rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr))
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1041,7 +1041,7 @@ static void addUniqueConnection(rcRegion& reg, int n)
|
||||
static bool mergeAndFilterLayerRegions(rcContext* ctx, int minRegionArea,
|
||||
unsigned short& maxRegionId,
|
||||
rcCompactHeightfield& chf,
|
||||
unsigned short* srcReg, rcIntArray& overlaps)
|
||||
unsigned short* srcReg, rcIntArray& /*overlaps*/)
|
||||
{
|
||||
const int w = chf.width;
|
||||
const int h = chf.height;
|
||||
@ -1257,7 +1257,7 @@ bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf)
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_BUILD_DISTANCEFIELD);
|
||||
|
||||
if (chf.dist)
|
||||
{
|
||||
@ -1281,25 +1281,23 @@ bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf)
|
||||
|
||||
unsigned short maxDist = 0;
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD_DIST);
|
||||
|
||||
calculateDistanceField(chf, src, maxDist);
|
||||
chf.maxDistance = maxDist;
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD_DIST);
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD_BLUR);
|
||||
|
||||
// Blur
|
||||
if (boxBlur(chf, 1, src, dst) != src)
|
||||
rcSwap(src, dst);
|
||||
|
||||
// Store distance.
|
||||
chf.dist = src;
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD_BLUR);
|
||||
{
|
||||
rcScopedTimer timerDist(ctx, RC_TIMER_BUILD_DISTANCEFIELD_DIST);
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD);
|
||||
calculateDistanceField(chf, src, maxDist);
|
||||
chf.maxDistance = maxDist;
|
||||
}
|
||||
|
||||
{
|
||||
rcScopedTimer timerBlur(ctx, RC_TIMER_BUILD_DISTANCEFIELD_BLUR);
|
||||
|
||||
// Blur
|
||||
if (boxBlur(chf, 1, src, dst) != src)
|
||||
rcSwap(src, dst);
|
||||
|
||||
// Store distance.
|
||||
chf.dist = src;
|
||||
}
|
||||
|
||||
rcFree(dst);
|
||||
|
||||
@ -1359,13 +1357,13 @@ bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_BUILD_REGIONS);
|
||||
|
||||
const int w = chf.width;
|
||||
const int h = chf.height;
|
||||
unsigned short id = 1;
|
||||
|
||||
rcScopedDelete<unsigned short> srcReg = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<unsigned short> srcReg((unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP));
|
||||
if (!srcReg)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount);
|
||||
@ -1374,7 +1372,7 @@ bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
memset(srcReg,0,sizeof(unsigned short)*chf.spanCount);
|
||||
|
||||
const int nsweeps = rcMax(chf.width,chf.height);
|
||||
rcScopedDelete<rcSweepSpan> sweeps = (rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<rcSweepSpan> sweeps((rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP));
|
||||
if (!sweeps)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps);
|
||||
@ -1489,23 +1487,21 @@ bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
}
|
||||
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
||||
{
|
||||
rcScopedTimer timerFilter(ctx, RC_TIMER_BUILD_REGIONS_FILTER);
|
||||
|
||||
// Merge regions and filter out small regions.
|
||||
rcIntArray overlaps;
|
||||
chf.maxRegions = id;
|
||||
if (!mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg, overlaps))
|
||||
return false;
|
||||
// Merge regions and filter out small regions.
|
||||
rcIntArray overlaps;
|
||||
chf.maxRegions = id;
|
||||
if (!mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg, overlaps))
|
||||
return false;
|
||||
|
||||
// Monotone partitioning does not generate overlapping regions.
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
||||
// Monotone partitioning does not generate overlapping regions.
|
||||
}
|
||||
|
||||
// Store the result out.
|
||||
for (int i = 0; i < chf.spanCount; ++i)
|
||||
chf.spans[i].reg = srcReg[i];
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_REGIONS);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1534,12 +1530,12 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_BUILD_REGIONS);
|
||||
|
||||
const int w = chf.width;
|
||||
const int h = chf.height;
|
||||
|
||||
rcScopedDelete<unsigned short> buf = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount*4, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<unsigned short> buf((unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount*4, RC_ALLOC_TEMP));
|
||||
if (!buf)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildRegions: Out of memory 'tmp' (%d).", chf.spanCount*4);
|
||||
@ -1579,6 +1575,13 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
// Make sure border will not overflow.
|
||||
const int bw = rcMin(w, borderSize);
|
||||
const int bh = rcMin(h, borderSize);
|
||||
|
||||
if (regionId > 0xFFFB)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildRegions: Region ID overflow");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Paint regions
|
||||
paintRectRegion(0, bw, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
||||
paintRectRegion(w-bw, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
||||
@ -1603,33 +1606,41 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
|
||||
// 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, lvlStacks[sId], false) != srcReg)
|
||||
{
|
||||
rcSwap(srcReg, dstReg);
|
||||
rcSwap(srcDist, dstDist);
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_EXPAND);
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FLOOD);
|
||||
|
||||
// Mark new regions with IDs.
|
||||
for (int j=0; j<lvlStacks[sId].size(); j+=3)
|
||||
{
|
||||
int x = lvlStacks[sId][j];
|
||||
int y = lvlStacks[sId][j+1];
|
||||
int i = lvlStacks[sId][j+2];
|
||||
if (i >= 0 && srcReg[i] == 0)
|
||||
rcScopedTimer timerExpand(ctx, RC_TIMER_BUILD_REGIONS_EXPAND);
|
||||
|
||||
// Expand current regions until no empty connected cells found.
|
||||
if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, lvlStacks[sId], false) != srcReg)
|
||||
{
|
||||
if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
|
||||
regionId++;
|
||||
rcSwap(srcReg, dstReg);
|
||||
rcSwap(srcDist, dstDist);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FLOOD);
|
||||
{
|
||||
rcScopedTimer timerFloor(ctx, RC_TIMER_BUILD_REGIONS_FLOOD);
|
||||
|
||||
// Mark new regions with IDs.
|
||||
for (int j = 0; j<lvlStacks[sId].size(); j += 3)
|
||||
{
|
||||
int x = lvlStacks[sId][j];
|
||||
int y = lvlStacks[sId][j+1];
|
||||
int i = lvlStacks[sId][j+2];
|
||||
if (i >= 0 && srcReg[i] == 0)
|
||||
{
|
||||
if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
|
||||
{
|
||||
if (regionId == 0xFFFF)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildRegions: Region ID overflow");
|
||||
return false;
|
||||
}
|
||||
|
||||
regionId++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expand current regions until no empty connected cells found.
|
||||
@ -1641,28 +1652,26 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_WATERSHED);
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
||||
|
||||
// Merge regions and filter out smalle regions.
|
||||
rcIntArray overlaps;
|
||||
chf.maxRegions = regionId;
|
||||
if (!mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg, overlaps))
|
||||
return false;
|
||||
|
||||
// If overlapping regions were found during merging, split those regions.
|
||||
if (overlaps.size() > 0)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildRegions: %d overlapping regions.", overlaps.size());
|
||||
}
|
||||
rcScopedTimer timerFilter(ctx, RC_TIMER_BUILD_REGIONS_FILTER);
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
||||
// Merge regions and filter out smalle regions.
|
||||
rcIntArray overlaps;
|
||||
chf.maxRegions = regionId;
|
||||
if (!mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg, overlaps))
|
||||
return false;
|
||||
|
||||
// If overlapping regions were found during merging, split those regions.
|
||||
if (overlaps.size() > 0)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildRegions: %d overlapping regions.", overlaps.size());
|
||||
}
|
||||
}
|
||||
|
||||
// Write the result out.
|
||||
for (int i = 0; i < chf.spanCount; ++i)
|
||||
chf.spans[i].reg = srcReg[i];
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_REGIONS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1672,13 +1681,13 @@ bool rcBuildLayerRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
{
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS);
|
||||
rcScopedTimer timer(ctx, RC_TIMER_BUILD_REGIONS);
|
||||
|
||||
const int w = chf.width;
|
||||
const int h = chf.height;
|
||||
unsigned short id = 1;
|
||||
|
||||
rcScopedDelete<unsigned short> srcReg = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<unsigned short> srcReg((unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP));
|
||||
if (!srcReg)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount);
|
||||
@ -1687,7 +1696,7 @@ bool rcBuildLayerRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
memset(srcReg,0,sizeof(unsigned short)*chf.spanCount);
|
||||
|
||||
const int nsweeps = rcMax(chf.width,chf.height);
|
||||
rcScopedDelete<rcSweepSpan> sweeps = (rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP);
|
||||
rcScopedDelete<rcSweepSpan> sweeps((rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP));
|
||||
if (!sweeps)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps);
|
||||
@ -1802,22 +1811,20 @@ bool rcBuildLayerRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
}
|
||||
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
||||
|
||||
// Merge monotone regions to layers and remove small regions.
|
||||
rcIntArray overlaps;
|
||||
chf.maxRegions = id;
|
||||
if (!mergeAndFilterLayerRegions(ctx, minRegionArea, chf.maxRegions, chf, srcReg, overlaps))
|
||||
return false;
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER);
|
||||
{
|
||||
rcScopedTimer timerFilter(ctx, RC_TIMER_BUILD_REGIONS_FILTER);
|
||||
|
||||
// Merge monotone regions to layers and remove small regions.
|
||||
rcIntArray overlaps;
|
||||
chf.maxRegions = id;
|
||||
if (!mergeAndFilterLayerRegions(ctx, minRegionArea, chf.maxRegions, chf, srcReg, overlaps))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Store the result out.
|
||||
for (int i = 0; i < chf.spanCount; ++i)
|
||||
chf.spans[i].reg = srcReg[i];
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_REGIONS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user