Removed Recast timer and log, added rcBuildContext, improved build time printout, fixed issue 67, issue 77, issue 87

This commit is contained in:
Mikko Mononen 2010-08-19 09:26:55 +00:00
parent 5f7ac70cba
commit 613d61f453
13 changed files with 390 additions and 643 deletions

View File

@ -19,6 +19,72 @@
#ifndef RECAST_H #ifndef RECAST_H
#define RECAST_H #define RECAST_H
#ifdef __GNUC__
#include <stdint.h>
typedef int64_t rcTimeVal;
#else
typedef __int64 rcTimeVal;
#endif
enum rcLogCategory
{
RC_LOG_PROGRESS = 1,
RC_LOG_WARNING,
RC_LOG_ERROR,
};
enum rcBuilTimeLabel
{
RC_TIME_RASTERIZE_TRIANGLES,
RC_TIME_BUILD_COMPACTHEIGHFIELD,
RC_TIME_BUILD_CONTOURS,
RC_TIME_BUILD_CONTOURS_TRACE,
RC_TIME_BUILD_CONTOURS_SIMPLIFY,
RC_TIME_FILTER_BORDER,
RC_TIME_FILTER_WALKABLE,
RC_TIME_MEDIAN_AREA,
RC_TIME_FILTER_LOW_OBSTACLES,
RC_TIME_BUILD_POLYMESH,
RC_TIME_MERGE_POLYMESH,
RC_TIME_ERODE_AREA,
RC_TIME_MARK_BOX_AREA,
RC_TIME_MARK_CONVEXPOLY_AREA,
RC_TIME_BUILD_DISTANCEFIELD,
RC_TIME_BUILD_DISTANCEFIELD_DIST,
RC_TIME_BUILD_DISTANCEFIELD_BLUR,
RC_TIME_BUILD_REGIONS,
RC_TIME_BUILD_REGIONS_WATERSHED,
RC_TIME_BUILD_REGIONS_EXPAND,
RC_TIME_BUILD_REGIONS_FLOOD,
RC_TIME_BUILD_REGIONS_FILTER,
RC_TIME_BUILD_POLYMESHDETAIL,
RC_TIME_MERGE_POLYMESHDETAIL,
RC_MAX_TIMES
};
// Build context provides several optional utilities needed for the build process,
// such as timing, logging, and build time collecting.
struct rcBuildContext
{
// Get current time in platform specific units.
virtual rcTimeVal getTime() { return 0; }
// Returns time passed from 'start' to 'end' in microseconds.
virtual int getDeltaTimeUsec(const rcTimeVal /*start*/, const rcTimeVal /*end*/) { return 0; }
// Resets log.
virtual void resetLog() {}
// Logs a message.
virtual void log(const rcLogCategory /*category*/, const char* /*format*/, ...) {}
// Resets build time collecting.
virtual void resetBuildTimes() {}
// Reports build time of specified label for accumulation.
virtual void reportBuildTime(const rcBuilTimeLabel /*label*/, const int /*time*/) {}
// Returns accumulated build time for specified label, or -1 if no time was reported.
virtual int getBuildTime(const rcBuilTimeLabel /*label*/) { return -1; }
};
// The units of the parameters are specified in parenthesis as follows: // The units of the parameters are specified in parenthesis as follows:
// (vx) voxels, (wu) world units // (vx) voxels, (wu) world units
struct rcConfig struct rcConfig
@ -190,12 +256,6 @@ rcPolyMeshDetail* rcAllocPolyMeshDetail();
void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh); void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh);
/*enum rcSpanFlags
{
RC_WALKABLE = 0x01,
RC_LEDGE = 0x02,
};*/
// If heightfield region ID has the following bit set, the region is on border area // If heightfield region ID has the following bit set, the region is on border area
// and excluded from many calculations. // and excluded from many calculations.
static const unsigned short RC_BORDER_REG = 0x8000; static const unsigned short RC_BORDER_REG = 0x8000;
@ -348,11 +408,6 @@ inline bool rcVequal(const float* p0, const float* p1)
return d < thr; return d < thr;
} }
// Alloc helpers for different Recast objects.
rcHeightfield* rcAllocHeightfield();
void rcFreeHeightField(rcHeightfield* hf);
// Calculated bounding box of array of vertices. // Calculated bounding box of array of vertices.
// Params: // Params:
// verts - (in) array of vertices // verts - (in) array of vertices
@ -376,7 +431,7 @@ void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int*
// bmin, bmax - (in) bounding box of the heightfield // bmin, bmax - (in) bounding box of the heightfield
// cs - (in) grid cell size // cs - (in) grid cell size
// ch - (in) grid cell height // ch - (in) grid cell height
bool rcCreateHeightfield(rcHeightfield& hf, int width, int height, bool rcCreateHeightfield(rcBuildContext* ctx, rcHeightfield& hf, int width, int height,
const float* bmin, const float* bmax, const float* bmin, const float* bmax,
float cs, float ch); float cs, float ch);
@ -389,10 +444,8 @@ bool rcCreateHeightfield(rcHeightfield& hf, int width, int height,
// tris - (in) array of triangle vertex indices // tris - (in) array of triangle vertex indices
// nt - (in) triangle count // nt - (in) triangle count
// areas - (out) array of triangle area types // areas - (out) array of triangle area types
void rcMarkWalkableTriangles(const float walkableSlopeAngle, void rcMarkWalkableTriangles(rcBuildContext* ctx, const float walkableSlopeAngle, const float* verts, int nv,
const float* verts, int nv, const int* tris, int nt, unsigned char* areas);
const int* tris, int nt,
unsigned char* areas);
// Sets the RC_NULL_AREA for every triangle whose slope is steeper than // Sets the RC_NULL_AREA for every triangle whose slope is steeper than
// the maximun walkable slope angle. // the maximun walkable slope angle.
@ -403,10 +456,8 @@ void rcMarkWalkableTriangles(const float walkableSlopeAngle,
// tris - (in) array of triangle vertex indices // tris - (in) array of triangle vertex indices
// nt - (in) triangle count // nt - (in) triangle count
// areas - (out) array of triangle are types // areas - (out) array of triangle are types
void rcClearUnwalkableTriangles(const float walkableSlopeAngle, void rcClearUnwalkableTriangles(rcBuildContext* ctx, const float walkableSlopeAngle, const float* verts, int nv,
const float* verts, int nv, const int* tris, int nt, unsigned char* areas);
const int* tris, int nt,
unsigned char* areas);
// Adds span to heighfield. // Adds span to heighfield.
// The span addition can set to favor flags. If the span is merged to // The span addition can set to favor flags. If the span is merged to
@ -418,7 +469,7 @@ void rcClearUnwalkableTriangles(const float walkableSlopeAngle,
// smin,smax - (in) spans min/max height // smin,smax - (in) spans min/max height
// flags - (in) span flags (zero or WALKABLE) // flags - (in) span flags (zero or WALKABLE)
// flagMergeThr - (in) merge threshold. // flagMergeThr - (in) merge threshold.
void rcAddSpan(rcHeightfield& solid, const int x, const int y, void rcAddSpan(rcBuildContext* ctx, rcHeightfield& solid, const int x, const int y,
const unsigned short smin, const unsigned short smax, const unsigned short smin, const unsigned short smax,
const unsigned short area, const int flagMergeThr); const unsigned short area, const int flagMergeThr);
@ -428,7 +479,7 @@ void rcAddSpan(rcHeightfield& solid, const int x, const int y,
// area - (in) area type of the triangle. // area - (in) area type of the triangle.
// solid - (in) heighfield where the triangle is rasterized // solid - (in) heighfield where the triangle is rasterized
// flagMergeThr - (in) distance in voxel where walkable flag is favored over non-walkable. // flagMergeThr - (in) distance in voxel where walkable flag is favored over non-walkable.
void rcRasterizeTriangle(const float* v0, const float* v1, const float* v2, void rcRasterizeTriangle(rcBuildContext* ctx, const float* v0, const float* v1, const float* v2,
const unsigned char area, rcHeightfield& solid, const unsigned char area, rcHeightfield& solid,
const int flagMergeThr = 1); const int flagMergeThr = 1);
@ -441,7 +492,7 @@ void rcRasterizeTriangle(const float* v0, const float* v1, const float* v2,
// nt - (in) triangle count // nt - (in) triangle count
// solid - (in) heighfield where the triangles are rasterized // solid - (in) heighfield where the triangles are rasterized
// flagMergeThr - (in) distance in voxel where walkable flag is favored over non-walkable. // flagMergeThr - (in) distance in voxel where walkable flag is favored over non-walkable.
void rcRasterizeTriangles(const float* verts, const int nv, void rcRasterizeTriangles(rcBuildContext* ctx, const float* verts, const int nv,
const int* tris, const unsigned char* areas, const int nt, const int* tris, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr = 1); rcHeightfield& solid, const int flagMergeThr = 1);
@ -454,7 +505,7 @@ void rcRasterizeTriangles(const float* verts, const int nv,
// nt - (in) triangle count // nt - (in) triangle count
// solid - (in) heighfield where the triangles are rasterized // solid - (in) heighfield where the triangles are rasterized
// flagMergeThr - (in) distance in voxel where walkable flag is favored over non-walkable. // flagMergeThr - (in) distance in voxel where walkable flag is favored over non-walkable.
void rcRasterizeTriangles(const float* verts, const int nv, void rcRasterizeTriangles(rcBuildContext* ctx, const float* verts, const int nv,
const unsigned short* tris, const unsigned char* areas, const int nt, const unsigned short* tris, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr = 1); rcHeightfield& solid, const int flagMergeThr = 1);
@ -464,7 +515,7 @@ void rcRasterizeTriangles(const float* verts, const int nv,
// area - (in) array of triangle area types. // area - (in) array of triangle area types.
// nt - (in) triangle count // nt - (in) triangle count
// solid - (in) heighfield where the triangles are rasterized // solid - (in) heighfield where the triangles are rasterized
void rcRasterizeTriangles(const float* verts, const unsigned char* areas, const int nt, void rcRasterizeTriangles(rcBuildContext* ctx, const float* verts, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr = 1); rcHeightfield& solid, const int flagMergeThr = 1);
// Marks non-walkable low obstacles as walkable if they are closer than walkableClimb // Marks non-walkable low obstacles as walkable if they are closer than walkableClimb
@ -474,7 +525,7 @@ void rcRasterizeTriangles(const float* verts, const unsigned char* areas, const
// walkableHeight - (in) minimum height where the agent can still walk // walkableHeight - (in) minimum height where the agent can still walk
// solid - (in/out) heightfield describing the solid space // solid - (in/out) heightfield describing the solid space
// TODO: Missuses ledge flag, must be called before rcFilterLedgeSpans! // TODO: Missuses ledge flag, must be called before rcFilterLedgeSpans!
void rcFilterLowHangingWalkableObstacles(const int walkableClimb, rcHeightfield& solid); void rcFilterLowHangingWalkableObstacles(rcBuildContext* ctx, const int walkableClimb, rcHeightfield& solid);
// Removes WALKABLE flag from all spans that are at ledges. This filtering // Removes WALKABLE flag from all spans that are at ledges. This filtering
// removes possible overestimation of the conservative voxelization so that // removes possible overestimation of the conservative voxelization so that
@ -483,23 +534,20 @@ void rcFilterLowHangingWalkableObstacles(const int walkableClimb, rcHeightfield&
// walkableHeight - (in) minimum height where the agent can still walk // walkableHeight - (in) minimum height where the agent can still walk
// walkableClimb - (in) maximum height between grid cells the agent can climb // walkableClimb - (in) maximum height between grid cells the agent can climb
// solid - (in/out) heightfield describing the solid space // solid - (in/out) heightfield describing the solid space
void rcFilterLedgeSpans(const int walkableHeight, void rcFilterLedgeSpans(rcBuildContext* ctx, const int walkableHeight, const int walkableClimb, rcHeightfield& solid);
const int walkableClimb,
rcHeightfield& solid);
// Removes WALKABLE flag from all spans which have smaller than // Removes WALKABLE flag from all spans which have smaller than
// 'walkableHeight' clearane above them. // 'walkableHeight' clearane above them.
// Params: // Params:
// walkableHeight - (in) minimum height where the agent can still walk // walkableHeight - (in) minimum height where the agent can still walk
// solid - (in/out) heightfield describing the solid space // solid - (in/out) heightfield describing the solid space
void rcFilterWalkableLowHeightSpans(int walkableHeight, void rcFilterWalkableLowHeightSpans(rcBuildContext* ctx, int walkableHeight, rcHeightfield& solid);
rcHeightfield& solid);
// Returns number of spans contained in a heightfield. // Returns number of spans contained in a heightfield.
// Params: // Params:
// hf - (in) heightfield to be compacted // hf - (in) heightfield to be compacted
// Returns number of spans. // Returns number of spans.
int rcGetHeightFieldSpanCount(rcHeightfield& hf); int rcGetHeightFieldSpanCount(rcBuildContext* ctx, rcHeightfield& hf);
// Builds compact representation of the heightfield. // Builds compact representation of the heightfield.
// Params: // Params:
@ -509,7 +557,7 @@ int rcGetHeightFieldSpanCount(rcHeightfield& hf);
// hf - (in) heightfield to be compacted // hf - (in) heightfield to be compacted
// chf - (out) compact heightfield representing the open space. // chf - (out) compact heightfield representing the open space.
// Returns false if operation ran out of memory. // Returns false if operation ran out of memory.
bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb, bool rcBuildCompactHeightfield(rcBuildContext* ctx, const int walkableHeight, const int walkableClimb,
rcHeightfield& hf, rcCompactHeightfield& chf); rcHeightfield& hf, rcCompactHeightfield& chf);
// Erodes walkable area. // Erodes walkable area.
@ -517,20 +565,20 @@ bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb
// radius - (in) radius of erosion (max 255). // radius - (in) radius of erosion (max 255).
// chf - (in/out) compact heightfield to erode. // chf - (in/out) compact heightfield to erode.
// Returns false if operation ran out of memory. // Returns false if operation ran out of memory.
bool rcErodeWalkableArea(int radius, rcCompactHeightfield& chf); bool rcErodeWalkableArea(rcBuildContext* ctx, int radius, rcCompactHeightfield& chf);
// Applies median filter to walkable area types, removing noise. // Applies median filter to walkable area types, removing noise.
// Params: // Params:
// chf - (in/out) compact heightfield to erode. // chf - (in/out) compact heightfield to erode.
// Returns false if operation ran out of memory. // Returns false if operation ran out of memory.
bool rcMedianFilterWalkableArea(rcCompactHeightfield& chf); bool rcMedianFilterWalkableArea(rcBuildContext* ctx, rcCompactHeightfield& chf);
// Marks the area of the convex polygon into the area type of the compact heighfield. // Marks the area of the convex polygon into the area type of the compact heighfield.
// Params: // Params:
// bmin/bmax - (in) bounds of the axis aligned box. // bmin/bmax - (in) bounds of the axis aligned box.
// areaId - (in) area ID to mark. // areaId - (in) area ID to mark.
// chf - (in/out) compact heightfield to mark. // chf - (in/out) compact heightfield to mark.
void rcMarkBoxArea(const float* bmin, const float* bmax, unsigned char areaId, void rcMarkBoxArea(rcBuildContext* ctx, const float* bmin, const float* bmax, unsigned char areaId,
rcCompactHeightfield& chf); rcCompactHeightfield& chf);
// Marks the area of the convex polygon into the area type of the compact heighfield. // Marks the area of the convex polygon into the area type of the compact heighfield.
@ -540,7 +588,7 @@ void rcMarkBoxArea(const float* bmin, const float* bmax, unsigned char areaId,
// hmin/hmax - (in) min and max height of the polygon. // hmin/hmax - (in) min and max height of the polygon.
// areaId - (in) area ID to mark. // areaId - (in) area ID to mark.
// chf - (in/out) compact heightfield to mark. // chf - (in/out) compact heightfield to mark.
void rcMarkConvexPolyArea(const float* verts, const int nverts, void rcMarkConvexPolyArea(rcBuildContext* ctx, const float* verts, const int nverts,
const float hmin, const float hmax, unsigned char areaId, const float hmin, const float hmax, unsigned char areaId,
rcCompactHeightfield& chf); rcCompactHeightfield& chf);
@ -548,7 +596,7 @@ void rcMarkConvexPolyArea(const float* verts, const int nverts,
// Params: // Params:
// chf - (in/out) compact heightfield representing the open space. // chf - (in/out) compact heightfield representing the open space.
// Returns false if operation ran out of memory. // Returns false if operation ran out of memory.
bool rcBuildDistanceField(rcCompactHeightfield& chf); bool rcBuildDistanceField(rcBuildContext* ctx, rcCompactHeightfield& chf);
// Divides the walkable heighfied into simple regions using watershed partitioning. // Divides the walkable heighfied into simple regions using watershed partitioning.
// Each region has only one contour and no overlaps. // Each region has only one contour and no overlaps.
@ -563,7 +611,7 @@ bool rcBuildDistanceField(rcCompactHeightfield& chf);
// minRegionSize - (in) the smallest allowed regions size. // minRegionSize - (in) the smallest allowed regions size.
// maxMergeRegionSize - (in) the largest allowed regions size which can be merged. // maxMergeRegionSize - (in) the largest allowed regions size which can be merged.
// Returns false if operation ran out of memory. // Returns false if operation ran out of memory.
bool rcBuildRegions(rcCompactHeightfield& chf, bool rcBuildRegions(rcBuildContext* ctx, rcCompactHeightfield& chf,
const int borderSize, const int minRegionSize, const int mergeRegionSize); const int borderSize, const int minRegionSize, const int mergeRegionSize);
// Divides the walkable heighfied into simple regions using simple monotone partitioning. // Divides the walkable heighfied into simple regions using simple monotone partitioning.
@ -579,7 +627,7 @@ bool rcBuildRegions(rcCompactHeightfield& chf,
// minRegionSize - (in) the smallest allowed regions size. // minRegionSize - (in) the smallest allowed regions size.
// maxMergeRegionSize - (in) the largest allowed regions size which can be merged. // maxMergeRegionSize - (in) the largest allowed regions size which can be merged.
// Returns false if operation ran out of memory. // Returns false if operation ran out of memory.
bool rcBuildRegionsMonotone(rcCompactHeightfield& chf, bool rcBuildRegionsMonotone(rcBuildContext* ctx, rcCompactHeightfield& chf,
const int borderSize, const int minRegionSize, const int mergeRegionSize); const int borderSize, const int minRegionSize, const int mergeRegionSize);
// Builds simplified contours from the regions outlines. // Builds simplified contours from the regions outlines.
@ -590,7 +638,7 @@ bool rcBuildRegionsMonotone(rcCompactHeightfield& chf,
// cset - (out) Resulting contour set. // cset - (out) Resulting contour set.
// flags - (in) build flags, see rcBuildContoursFlags. // flags - (in) build flags, see rcBuildContoursFlags.
// Returns false if operation ran out of memory. // Returns false if operation ran out of memory.
bool rcBuildContours(rcCompactHeightfield& chf, bool rcBuildContours(rcBuildContext* ctx, rcCompactHeightfield& chf,
const float maxError, const int maxEdgeLen, const float maxError, const int maxEdgeLen,
rcContourSet& cset, const int flags = RC_CONTOUR_TESS_WALL_EDGES); rcContourSet& cset, const int flags = RC_CONTOUR_TESS_WALL_EDGES);
@ -600,9 +648,9 @@ bool rcBuildContours(rcCompactHeightfield& chf,
// nvp - (in) maximum number of vertices per polygon. // nvp - (in) maximum number of vertices per polygon.
// mesh - (out) poly mesh. // mesh - (out) poly mesh.
// Returns false if operation ran out of memory. // Returns false if operation ran out of memory.
bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh); bool rcBuildPolyMesh(rcBuildContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& mesh);
bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh); bool rcMergePolyMeshes(rcBuildContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh);
// Builds detail triangle mesh for each polygon in the poly mesh. // Builds detail triangle mesh for each polygon in the poly mesh.
// Params: // Params:
@ -612,11 +660,11 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
// sampleMaxError - (in) maximum allowed distance between simplified detail mesh and height sample. // sampleMaxError - (in) maximum allowed distance between simplified detail mesh and height sample.
// pmdtl - (out) detail mesh. // pmdtl - (out) detail mesh.
// Returns false if operation ran out of memory. // Returns false if operation ran out of memory.
bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& chf, bool rcBuildPolyMeshDetail(rcBuildContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf,
const float sampleDist, const float sampleMaxError, const float sampleDist, const float sampleMaxError,
rcPolyMeshDetail& dmesh); rcPolyMeshDetail& dmesh);
bool rcMergePolyMeshDetails(rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh); bool rcMergePolyMeshDetails(rcBuildContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh);
#endif // RECAST_H #endif // RECAST_H

View File

@ -15,17 +15,15 @@
// misrepresented as being the original software. // misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution. // 3. This notice may not be removed or altered from any source distribution.
// //
#ifndef RECAST_TIMER_H
#define RECAST_TIMER_H
#ifdef __GNUC__ #ifndef RECASTASSERT_H
#include <stdint.h> #define RECASTASSERT_H
typedef int64_t rcTimeVal;
#ifdef NDEBUG
# define rcAssert(x)
#else #else
typedef __int64 rcTimeVal; # include <assert.h>
# define rcAssert assert
#endif #endif
rcTimeVal rcGetPerformanceTimer(); #endif // RECASTASSERT_H
int rcGetDeltaTimeUsec(rcTimeVal start, rcTimeVal end);
#endif // RECAST_TIMER_H

View File

@ -1,82 +0,0 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef RECAST_LOG_H
#define RECAST_LOG_H
enum rcLogCategory
{
RC_LOG_PROGRESS = 1,
RC_LOG_WARNING,
RC_LOG_ERROR,
};
class rcLog
{
public:
rcLog();
~rcLog();
void log(rcLogCategory category, const char* format, ...);
inline void clear() { m_messageCount = 0; m_textPoolSize = 0; }
inline int getMessageCount() const { return m_messageCount; }
inline char getMessageType(int i) const { return *m_messages[i]; }
inline const char* getMessageText(int i) const { return m_messages[i]+1; }
private:
static const int MAX_MESSAGES = 1000;
const char* m_messages[MAX_MESSAGES];
int m_messageCount;
static const int TEXT_POOL_SIZE = 8000;
char m_textPool[TEXT_POOL_SIZE];
int m_textPoolSize;
};
struct rcBuildTimes
{
int rasterizeTriangles;
int buildCompact;
int buildContours;
int buildContoursTrace;
int buildContoursSimplify;
int filterBorder;
int filterWalkable;
int filterMarkReachable;
int filterMedian;
int buildPolymesh;
int erodeArea;
int buildDistanceField;
int buildDistanceFieldDist;
int buildDistanceFieldBlur;
int buildRegions;
int buildRegionsReg;
int buildRegionsExp;
int buildRegionsFlood;
int buildRegionsFilter;
int buildDetailMesh;
int mergePolyMesh;
int mergePolyMeshDetail;
};
void rcSetLog(rcLog* log);
rcLog* rcGetLog();
void rcSetBuildTimes(rcBuildTimes* btimes);
rcBuildTimes* rcGetBuildTimes();
#endif // RECAST_LOG_H

View File

@ -23,9 +23,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "Recast.h" #include "Recast.h"
#include "RecastLog.h"
#include "RecastTimer.h"
#include "RecastAlloc.h" #include "RecastAlloc.h"
#include "RecastAssert.h"
float rcSqrt(float x) float rcSqrt(float x)
{ {
@ -144,10 +143,12 @@ void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int*
*h = (int)((bmax[2] - bmin[2])/cs+0.5f); *h = (int)((bmax[2] - bmin[2])/cs+0.5f);
} }
bool rcCreateHeightfield(rcHeightfield& hf, int width, int height, bool rcCreateHeightfield(rcBuildContext* ctx, rcHeightfield& hf, int width, int height,
const float* bmin, const float* bmax, const float* bmin, const float* bmax,
float cs, float ch) float cs, float ch)
{ {
rcAssert(ctx);
hf.width = width; hf.width = width;
hf.height = height; hf.height = height;
rcVcopy(hf.bmin, bmin); rcVcopy(hf.bmin, bmin);
@ -170,11 +171,13 @@ static void calcTriNormal(const float* v0, const float* v1, const float* v2, flo
rcVnormalize(norm); rcVnormalize(norm);
} }
void rcMarkWalkableTriangles(const float walkableSlopeAngle, void rcMarkWalkableTriangles(rcBuildContext* ctx, const float walkableSlopeAngle,
const float* verts, int /*nv*/, const float* verts, int /*nv*/,
const int* tris, int nt, const int* tris, int nt,
unsigned char* areas) unsigned char* areas)
{ {
rcAssert(ctx);
const float walkableThr = cosf(walkableSlopeAngle/180.0f*(float)M_PI); const float walkableThr = cosf(walkableSlopeAngle/180.0f*(float)M_PI);
float norm[3]; float norm[3];
@ -189,11 +192,13 @@ void rcMarkWalkableTriangles(const float walkableSlopeAngle,
} }
} }
void rcClearUnwalkableTriangles(const float walkableSlopeAngle, void rcClearUnwalkableTriangles(rcBuildContext* ctx, const float walkableSlopeAngle,
const float* verts, int /*nv*/, const float* verts, int /*nv*/,
const int* tris, int nt, const int* tris, int nt,
unsigned char* areas) unsigned char* areas)
{ {
rcAssert(ctx);
const float walkableThr = cosf(walkableSlopeAngle/180.0f*(float)M_PI); const float walkableThr = cosf(walkableSlopeAngle/180.0f*(float)M_PI);
float norm[3]; float norm[3];
@ -208,8 +213,10 @@ void rcClearUnwalkableTriangles(const float walkableSlopeAngle,
} }
} }
int rcGetHeightFieldSpanCount(rcHeightfield& hf) int rcGetHeightFieldSpanCount(rcBuildContext* ctx, rcHeightfield& hf)
{ {
rcAssert(ctx);
const int w = hf.width; const int w = hf.width;
const int h = hf.height; const int h = hf.height;
int spanCount = 0; int spanCount = 0;
@ -227,14 +234,16 @@ int rcGetHeightFieldSpanCount(rcHeightfield& hf)
return spanCount; return spanCount;
} }
bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb, bool rcBuildCompactHeightfield(rcBuildContext* ctx, const int walkableHeight, const int walkableClimb,
rcHeightfield& hf, rcCompactHeightfield& chf) rcHeightfield& hf, rcCompactHeightfield& chf)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
const int w = hf.width; const int w = hf.width;
const int h = hf.height; const int h = hf.height;
const int spanCount = rcGetHeightFieldSpanCount(hf); const int spanCount = rcGetHeightFieldSpanCount(ctx, hf);
// Fill in header. // Fill in header.
chf.width = w; chf.width = w;
@ -251,24 +260,21 @@ bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb
chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*w*h, RC_ALLOC_PERM); chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*w*h, RC_ALLOC_PERM);
if (!chf.cells) if (!chf.cells)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", w*h);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", w*h);
return false; return false;
} }
memset(chf.cells, 0, sizeof(rcCompactCell)*w*h); memset(chf.cells, 0, sizeof(rcCompactCell)*w*h);
chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*spanCount, RC_ALLOC_PERM); chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*spanCount, RC_ALLOC_PERM);
if (!chf.spans) if (!chf.spans)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount);
return false; return false;
} }
memset(chf.spans, 0, sizeof(rcCompactSpan)*spanCount); memset(chf.spans, 0, sizeof(rcCompactSpan)*spanCount);
chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*spanCount, RC_ALLOC_PERM); chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*spanCount, RC_ALLOC_PERM);
if (!chf.areas) if (!chf.areas)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount);
return false; return false;
} }
memset(chf.areas, RC_NULL_AREA, sizeof(unsigned char)*spanCount); memset(chf.areas, RC_NULL_AREA, sizeof(unsigned char)*spanCount);
@ -357,14 +363,13 @@ bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb
if (tooHighNeighbour > MAX_LAYERS) if (tooHighNeighbour > MAX_LAYERS)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heighfield has too many layers %d (max: %d)",
rcGetLog()->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heighfield has too many layers %d (max: %d)", tooHighNeighbour, MAX_LAYERS); tooHighNeighbour, MAX_LAYERS);
} }
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
if (rcGetBuildTimes()) ctx->reportBuildTime(RC_TIME_BUILD_COMPACTHEIGHFIELD, ctx->getDeltaTimeUsec(startTime, endTime));
rcGetBuildTimes()->buildCompact += rcGetDeltaTimeUsec(startTime, endTime);
return true; return true;
} }

View File

@ -23,21 +23,25 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "Recast.h" #include "Recast.h"
#include "RecastLog.h"
#include "RecastTimer.h"
#include "RecastAlloc.h" #include "RecastAlloc.h"
#include "RecastAssert.h"
bool rcErodeWalkableArea(int radius, rcCompactHeightfield& chf) bool rcErodeWalkableArea(rcBuildContext* ctx, int radius, rcCompactHeightfield& chf)
{ {
rcAssert(ctx);
const int w = chf.width; const int w = chf.width;
const int h = chf.height; const int h = chf.height;
rcTimeVal startTime = rcGetPerformanceTimer(); rcTimeVal startTime = ctx->getTime();
unsigned char* dist = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP); unsigned char* dist = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP);
if (!dist) if (!dist)
{
ctx->log(RC_LOG_ERROR, "erodeWalkableArea: Out of memory 'dist' (%d).", chf.spanCount);
return false; return false;
}
// Init distance. // Init distance.
memset(dist, 0xff, sizeof(unsigned char)*chf.spanCount); memset(dist, 0xff, sizeof(unsigned char)*chf.spanCount);
@ -192,12 +196,9 @@ bool rcErodeWalkableArea(int radius, rcCompactHeightfield& chf)
rcFree(dist); rcFree(dist);
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
if (rcGetBuildTimes()) ctx->reportBuildTime(RC_TIME_ERODE_AREA, ctx->getDeltaTimeUsec(startTime, endTime));
{
rcGetBuildTimes()->erodeArea += rcGetDeltaTimeUsec(startTime, endTime);
}
return true; return true;
} }
@ -215,16 +216,21 @@ static void insertSort(unsigned char* a, const int n)
} }
bool rcMedianFilterWalkableArea(rcCompactHeightfield& chf) bool rcMedianFilterWalkableArea(rcBuildContext* ctx, rcCompactHeightfield& chf)
{ {
rcAssert(ctx);
const int w = chf.width; const int w = chf.width;
const int h = chf.height; const int h = chf.height;
rcTimeVal startTime = rcGetPerformanceTimer(); rcTimeVal startTime = ctx->getTime();
unsigned char* areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP); unsigned char* areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP);
if (!areas) if (!areas)
{
ctx->log(RC_LOG_ERROR, "medianFilterWalkableArea: Out of memory 'areas' (%d).", chf.spanCount);
return false; return false;
}
// Init distance. // Init distance.
memset(areas, 0xff, sizeof(unsigned char)*chf.spanCount); memset(areas, 0xff, sizeof(unsigned char)*chf.spanCount);
@ -279,19 +285,20 @@ bool rcMedianFilterWalkableArea(rcCompactHeightfield& chf)
rcFree(areas); rcFree(areas);
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
if (rcGetBuildTimes()) ctx->reportBuildTime(RC_TIME_MEDIAN_AREA, ctx->getDeltaTimeUsec(startTime, endTime));
{
rcGetBuildTimes()->filterMedian += rcGetDeltaTimeUsec(startTime, endTime);
}
return true; return true;
} }
void rcMarkBoxArea(const float* bmin, const float* bmax, unsigned char areaId, void rcMarkBoxArea(rcBuildContext* ctx, const float* bmin, const float* bmax, unsigned char areaId,
rcCompactHeightfield& chf) rcCompactHeightfield& chf)
{ {
rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
int minx = (int)((bmin[0]-chf.bmin[0])/chf.cs); int minx = (int)((bmin[0]-chf.bmin[0])/chf.cs);
int miny = (int)((bmin[1]-chf.bmin[1])/chf.ch); int miny = (int)((bmin[1]-chf.bmin[1])/chf.ch);
int minz = (int)((bmin[2]-chf.bmin[2])/chf.cs); int minz = (int)((bmin[2]-chf.bmin[2])/chf.cs);
@ -325,6 +332,11 @@ void rcMarkBoxArea(const float* bmin, const float* bmax, unsigned char areaId,
} }
} }
} }
rcTimeVal endTime = ctx->getTime();
ctx->reportBuildTime(RC_TIME_MARK_BOX_AREA, ctx->getDeltaTimeUsec(startTime, endTime));
} }
@ -342,10 +354,14 @@ static int pointInPoly(int nvert, const float* verts, const float* p)
return c; return c;
} }
void rcMarkConvexPolyArea(const float* verts, const int nverts, void rcMarkConvexPolyArea(rcBuildContext* ctx, const float* verts, const int nverts,
const float hmin, const float hmax, unsigned char areaId, const float hmin, const float hmax, unsigned char areaId,
rcCompactHeightfield& chf) rcCompactHeightfield& chf)
{ {
rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
float bmin[3], bmax[3]; float bmin[3], bmax[3];
rcVcopy(bmin, verts); rcVcopy(bmin, verts);
rcVcopy(bmax, verts); rcVcopy(bmax, verts);
@ -403,4 +419,7 @@ void rcMarkConvexPolyArea(const float* verts, const int nverts,
} }
} }
rcTimeVal endTime = ctx->getTime();
ctx->reportBuildTime(RC_TIME_MARK_CONVEXPOLY_AREA, ctx->getDeltaTimeUsec(startTime, endTime));
} }

View File

@ -21,9 +21,8 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "Recast.h" #include "Recast.h"
#include "RecastLog.h"
#include "RecastTimer.h"
#include "RecastAlloc.h" #include "RecastAlloc.h"
#include "RecastAssert.h"
static int getCornerHeight(int x, int y, int i, int dir, static int getCornerHeight(int x, int y, int i, int dir,
@ -593,14 +592,16 @@ static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib)
return true; return true;
} }
bool rcBuildContours(rcCompactHeightfield& chf, bool rcBuildContours(rcBuildContext* ctx, rcCompactHeightfield& chf,
const float maxError, const int maxEdgeLen, const float maxError, const int maxEdgeLen,
rcContourSet& cset, const int buildFlags) rcContourSet& cset, const int buildFlags)
{ {
rcAssert(ctx);
const int w = chf.width; const int w = chf.width;
const int h = chf.height; const int h = chf.height;
rcTimeVal startTime = rcGetPerformanceTimer(); rcTimeVal startTime = ctx->getTime();
rcVcopy(cset.bmin, chf.bmin); rcVcopy(cset.bmin, chf.bmin);
rcVcopy(cset.bmax, chf.bmax); rcVcopy(cset.bmax, chf.bmax);
@ -616,12 +617,11 @@ bool rcBuildContours(rcCompactHeightfield& chf,
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) if (!flags)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'flags' (%d).", chf.spanCount);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'flags' (%d).", chf.spanCount);
return false; return false;
} }
rcTimeVal traceStartTime = rcGetPerformanceTimer(); rcTimeVal traceStartTime = ctx->getTime();
// Mark boundaries. // Mark boundaries.
@ -657,9 +657,9 @@ bool rcBuildContours(rcCompactHeightfield& chf,
} }
} }
rcTimeVal traceEndTime = rcGetPerformanceTimer(); rcTimeVal traceEndTime = ctx->getTime();
rcTimeVal simplifyStartTime = rcGetPerformanceTimer(); rcTimeVal simplifyStartTime = ctx->getTime();
rcIntArray verts(256); rcIntArray verts(256);
rcIntArray simplified(64); rcIntArray simplified(64);
@ -708,8 +708,7 @@ bool rcBuildContours(rcCompactHeightfield& chf,
rcFree(cset.conts); rcFree(cset.conts);
cset.conts = newConts; cset.conts = newConts;
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "rcBuildContours: Expanding max contours from %d to %d.", oldMax, maxContours);
rcGetLog()->log(RC_LOG_WARNING, "rcBuildContours: Expanding max contours from %d to %d.", oldMax, maxContours);
} }
rcContour* cont = &cset.conts[cset.nconts++]; rcContour* cont = &cset.conts[cset.nconts++];
@ -718,8 +717,7 @@ bool rcBuildContours(rcCompactHeightfield& chf,
cont->verts = (int*)rcAlloc(sizeof(int)*cont->nverts*4, RC_ALLOC_PERM); cont->verts = (int*)rcAlloc(sizeof(int)*cont->nverts*4, RC_ALLOC_PERM);
if (!cont->verts) if (!cont->verts)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'verts' (%d).", cont->nverts);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'verts' (%d).", cont->nverts);
return false; return false;
} }
memcpy(cont->verts, &simplified[0], sizeof(int)*cont->nverts*4); memcpy(cont->verts, &simplified[0], sizeof(int)*cont->nverts*4);
@ -728,8 +726,7 @@ bool rcBuildContours(rcCompactHeightfield& chf,
cont->rverts = (int*)rcAlloc(sizeof(int)*cont->nrverts*4, RC_ALLOC_PERM); cont->rverts = (int*)rcAlloc(sizeof(int)*cont->nrverts*4, RC_ALLOC_PERM);
if (!cont->rverts) if (!cont->rverts)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'rverts' (%d).", cont->nrverts);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'rverts' (%d).", cont->nrverts);
return false; return false;
} }
memcpy(cont->rverts, &verts[0], sizeof(int)*cont->nrverts*4); memcpy(cont->rverts, &verts[0], sizeof(int)*cont->nrverts*4);
@ -778,8 +775,7 @@ bool rcBuildContours(rcCompactHeightfield& chf,
} }
if (mergeIdx == -1) if (mergeIdx == -1)
{ {
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "rcBuildContours: Could not find merge target for bad contour %d.", i);
rcGetLog()->log(RC_LOG_WARNING, "rcBuildContours: Could not find merge target for bad contour %d.", i);
} }
else else
{ {
@ -789,37 +785,25 @@ bool rcBuildContours(rcCompactHeightfield& chf,
getClosestIndices(mcont.verts, mcont.nverts, cont.verts, cont.nverts, ia, ib); getClosestIndices(mcont.verts, mcont.nverts, cont.verts, cont.nverts, ia, ib);
if (ia == -1 || ib == -1) if (ia == -1 || ib == -1)
{ {
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "rcBuildContours: Failed to find merge points for %d and %d.", i, mergeIdx);
rcGetLog()->log(RC_LOG_WARNING, "rcBuildContours: Failed to find merge points for %d and %d.", i, mergeIdx);
continue; continue;
} }
if (!mergeContours(mcont, cont, ia, ib)) if (!mergeContours(mcont, cont, ia, ib))
{ {
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "rcBuildContours: Failed to merge contours %d and %d.", i, mergeIdx);
rcGetLog()->log(RC_LOG_WARNING, "rcBuildContours: Failed to merge contours %d and %d.", i, mergeIdx);
continue; continue;
} }
} }
} }
} }
rcTimeVal simplifyEndTime = rcGetPerformanceTimer(); rcTimeVal simplifyEndTime = ctx->getTime();
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
// if (rcGetLog()) ctx->reportBuildTime(RC_TIME_BUILD_CONTOURS, ctx->getDeltaTimeUsec(startTime, endTime));
// { ctx->reportBuildTime(RC_TIME_BUILD_CONTOURS_TRACE, ctx->getDeltaTimeUsec(traceStartTime, traceEndTime));
// rcGetLog()->log(RC_LOG_PROGRESS, "Create contours: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f); ctx->reportBuildTime(RC_TIME_BUILD_CONTOURS_SIMPLIFY, ctx->getDeltaTimeUsec(simplifyStartTime, simplifyEndTime));
// rcGetLog()->log(RC_LOG_PROGRESS, " - boundary: %.3f ms", rcGetDeltaTimeUsec(boundaryStartTime, boundaryEndTime)/1000.0f);
// rcGetLog()->log(RC_LOG_PROGRESS, " - contour: %.3f ms", rcGetDeltaTimeUsec(contourStartTime, contourEndTime)/1000.0f);
// }
if (rcGetBuildTimes())
{
rcGetBuildTimes()->buildContours += rcGetDeltaTimeUsec(startTime, endTime);
rcGetBuildTimes()->buildContoursTrace += rcGetDeltaTimeUsec(traceStartTime, traceEndTime);
rcGetBuildTimes()->buildContoursSimplify += rcGetDeltaTimeUsec(simplifyStartTime, simplifyEndTime);
}
return true; return true;
} }

View File

@ -20,13 +20,15 @@
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include "Recast.h" #include "Recast.h"
#include "RecastLog.h" #include "RecastAssert.h"
#include "RecastTimer.h"
// TODO: Missuses ledge flag, must be called before rcFilterLedgeSpans! void rcFilterLowHangingWalkableObstacles(rcBuildContext* ctx, const int walkableClimb, rcHeightfield& solid)
void rcFilterLowHangingWalkableObstacles(const int walkableClimb, rcHeightfield& solid)
{ {
rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
const int w = solid.width; const int w = solid.width;
const int h = solid.height; const int h = solid.height;
@ -51,39 +53,20 @@ void rcFilterLowHangingWalkableObstacles(const int walkableClimb, rcHeightfield&
// past multiple non-walkable objects. // past multiple non-walkable objects.
previousWalkable = walkable; previousWalkable = walkable;
} }
/* rcSpan* ps = 0;
for (rcSpan* s = solid.spans[x + y*w]; s; ps = s, s = s->next)
{
const bool walkable = s->flags != RC_NULL_AREA;
const bool previousWalkable = ps && ps->flags != RC_NULL_AREA;
// If current span is not walkable, but there is walkable
// span just below it, mark the span above it walkable too.
// Missuse the edge flag so that walkable flag cannot propagate
// past multiple non-walkable objects.
if (!walkable && previousWalkable)
{
if (rcAbs((int)s->smax - (int)ps->smax) <= walkableClimb)
s->flags |= 1;
}
}
// Transfer "fake ledges" to walkables.
for (rcSpan* s = solid.spans[x + y*w]; s; ps = s, s = s->next)
{
if (s->flags & RC_LEDGE)
s->flags |= RC_WALKABLE;
s->flags &= ~RC_LEDGE;
}*/
}
} }
} }
void rcFilterLedgeSpans(const int walkableHeight, rcTimeVal endTime = ctx->getTime();
const int walkableClimb,
ctx->reportBuildTime(RC_TIME_FILTER_LOW_OBSTACLES, ctx->getDeltaTimeUsec(startTime, endTime));
}
void rcFilterLedgeSpans(rcBuildContext* ctx, const int walkableHeight, const int walkableClimb,
rcHeightfield& solid) rcHeightfield& solid)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
const int w = solid.width; const int w = solid.width;
const int h = solid.height; const int h = solid.height;
@ -165,17 +148,16 @@ void rcFilterLedgeSpans(const int walkableHeight,
} }
} }
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
// if (rcGetLog())
// rcGetLog()->log(RC_LOG_PROGRESS, "Filter border: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f); ctx->reportBuildTime(RC_TIME_FILTER_BORDER, ctx->getDeltaTimeUsec(startTime, endTime));
if (rcGetBuildTimes())
rcGetBuildTimes()->filterBorder += rcGetDeltaTimeUsec(startTime, endTime);
} }
void rcFilterWalkableLowHeightSpans(int walkableHeight, void rcFilterWalkableLowHeightSpans(rcBuildContext* ctx, int walkableHeight, rcHeightfield& solid)
rcHeightfield& solid)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
const int w = solid.width; const int w = solid.width;
const int h = solid.height; const int h = solid.height;
@ -197,10 +179,7 @@ void rcFilterWalkableLowHeightSpans(int walkableHeight,
} }
} }
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
// if (rcGetLog()) ctx->reportBuildTime(RC_TIME_FILTER_WALKABLE, ctx->getDeltaTimeUsec(startTime, endTime));
// rcGetLog()->log(RC_LOG_PROGRESS, "Filter walkable: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
if (rcGetBuildTimes())
rcGetBuildTimes()->filterWalkable += rcGetDeltaTimeUsec(startTime, endTime);
} }

View File

@ -1,77 +0,0 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#include "RecastLog.h"
#include <stdio.h>
#include <stdarg.h>
static rcLog* g_log = 0;
static rcBuildTimes* g_btimes = 0;
rcLog::rcLog() :
m_messageCount(0),
m_textPoolSize(0)
{
}
rcLog::~rcLog()
{
if (g_log == this)
g_log = 0;
}
void rcLog::log(rcLogCategory category, const char* format, ...)
{
if (m_messageCount >= MAX_MESSAGES)
return;
char* dst = &m_textPool[m_textPoolSize];
int n = TEXT_POOL_SIZE - m_textPoolSize;
if (n < 2)
return;
// Store category
*dst = (char)category;
n--;
// Store message
va_list ap;
va_start(ap, format);
int ret = vsnprintf(dst+1, n-1, format, ap);
va_end(ap);
if (ret > 0)
m_textPoolSize += ret+2;
m_messages[m_messageCount++] = dst;
}
void rcSetLog(rcLog* log)
{
g_log = log;
}
rcLog* rcGetLog()
{
return g_log;
}
void rcSetBuildTimes(rcBuildTimes* btimes)
{
g_btimes = btimes;
}
rcBuildTimes* rcGetBuildTimes()
{
return g_btimes;
}

View File

@ -21,9 +21,8 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "Recast.h" #include "Recast.h"
#include "RecastLog.h"
#include "RecastTimer.h"
#include "RecastAlloc.h" #include "RecastAlloc.h"
#include "RecastAssert.h"
struct rcEdge struct rcEdge
{ {
@ -287,7 +286,7 @@ static bool diagonal(int i, int j, int n, const int* verts, int* indices)
return inCone(i, j, n, verts, indices) && diagonalie(i, j, n, verts, indices); return inCone(i, j, n, verts, indices) && diagonalie(i, j, n, verts, indices);
} }
int triangulate(int n, const int* verts, int* indices, int* tris) static int triangulate(int n, const int* verts, int* indices, int* tris)
{ {
int ntris = 0; int ntris = 0;
int* dst = tris; int* dst = tris;
@ -328,8 +327,6 @@ int triangulate(int n, const int* verts, int* indices, int* tris)
if (mini == -1) if (mini == -1)
{ {
// Should not happen. // Should not happen.
if (rcGetLog())
rcGetLog()->log(RC_LOG_WARNING, "triangulate: Failed to triangulate polygon.");
/* printf("mini == -1 ntris=%d n=%d\n", ntris, n); /* printf("mini == -1 ntris=%d n=%d\n", ntris, n);
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
{ {
@ -486,7 +483,7 @@ static void pushBack(int v, int* arr, int& an)
an++; an++;
} }
static bool canRemoveVertex(rcPolyMesh& mesh, const unsigned short rem) static bool canRemoveVertex(rcBuildContext* ctx, rcPolyMesh& mesh, const unsigned short rem)
{ {
const int nvp = mesh.nvp; const int nvp = mesh.nvp;
@ -529,8 +526,7 @@ static bool canRemoveVertex(rcPolyMesh& mesh, const unsigned short rem)
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) if (!edges)
{ {
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "canRemoveVertex: Out of memory 'edges' (%d).", maxEdges*3);
rcGetLog()->log(RC_LOG_WARNING, "canRemoveVertex: Out of memory 'edges' (%d).", maxEdges*3);
return false; return false;
} }
@ -589,7 +585,7 @@ static bool canRemoveVertex(rcPolyMesh& mesh, const unsigned short rem)
return true; return true;
} }
static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int maxTris) static bool removeVertex(rcBuildContext* ctx, rcPolyMesh& mesh, const unsigned short rem, const int maxTris)
{ {
const int nvp = mesh.nvp; const int nvp = mesh.nvp;
@ -610,8 +606,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
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) if (!edges)
{ {
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'edges' (%d).", numRemovedVerts*nvp*4);
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'edges' (%d).", numRemovedVerts*nvp*4);
return false; return false;
} }
@ -619,8 +614,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
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) if (!hole)
{ {
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hole' (%d).", numRemovedVerts*nvp);
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hole' (%d).", numRemovedVerts*nvp);
return false; return false;
} }
@ -628,8 +622,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
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) if (!hreg)
{ {
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hreg' (%d).", numRemovedVerts*nvp);
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hreg' (%d).", numRemovedVerts*nvp);
return false; return false;
} }
@ -637,8 +630,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
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) if (!harea)
{ {
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'harea' (%d).", numRemovedVerts*nvp);
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'harea' (%d).", numRemovedVerts*nvp);
return false; return false;
} }
@ -754,24 +746,21 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
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) if (!tris)
{ {
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tris' (%d).", nhole*3);
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tris' (%d).", nhole*3);
return false; 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) if (!tverts)
{ {
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tverts' (%d).", nhole*4);
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tverts' (%d).", nhole*4);
return false; 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 (!tverts) if (!tverts)
{ {
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'thole' (%d).", nhole);
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'thole' (%d).", nhole);
return false; return false;
} }
@ -791,30 +780,26 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
if (ntris < 0) if (ntris < 0)
{ {
ntris = -ntris; ntris = -ntris;
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "removeVertex: triangulate() returned bad results.");
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: triangulate() returned bad results.");
} }
// Merge the hole triangles back to polygons. // 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) if (!polys)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'polys' (%d).", (ntris+1)*nvp);
rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Out of memory 'polys' (%d).", (ntris+1)*nvp);
return false; 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) if (!pregs)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pregs' (%d).", ntris);
rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pregs' (%d).", ntris);
return false; 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 (!pregs) if (!pregs)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pareas' (%d).", ntris);
rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pareas' (%d).", ntris);
return false; return false;
} }
@ -899,8 +884,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
mesh.npolys++; mesh.npolys++;
if (mesh.npolys > maxTris) if (mesh.npolys > maxTris)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "removeVertex: Too many polygons %d (max:%d).", mesh.npolys, maxTris);
rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Too many polygons %d (max:%d).", mesh.npolys, maxTris);
return false; return false;
} }
} }
@ -909,9 +893,11 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
} }
bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh) bool rcBuildPolyMesh(rcBuildContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& mesh)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
rcVcopy(mesh.bmin, cset.bmin); rcVcopy(mesh.bmin, cset.bmin);
rcVcopy(mesh.bmax, cset.bmax); rcVcopy(mesh.bmax, cset.bmax);
@ -932,16 +918,14 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
if (maxVertices >= 0xfffe) if (maxVertices >= 0xfffe)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many vertices %d.", maxVertices);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many vertices %d.", maxVertices);
return false; 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) if (!vflags)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices);
return false; return false;
} }
memset(vflags, 0, maxVertices); memset(vflags, 0, maxVertices);
@ -949,29 +933,25 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
mesh.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVertices*3, RC_ALLOC_PERM); mesh.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVertices*3, RC_ALLOC_PERM);
if (!mesh.verts) if (!mesh.verts)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices);
return false; return false;
} }
mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris*nvp*2*2, RC_ALLOC_PERM); mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris*nvp*2*2, RC_ALLOC_PERM);
if (!mesh.polys) if (!mesh.polys)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.polys' (%d).", maxTris*nvp*2);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.polys' (%d).", maxTris*nvp*2);
return false; return false;
} }
mesh.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris, RC_ALLOC_PERM); mesh.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris, RC_ALLOC_PERM);
if (!mesh.regs) if (!mesh.regs)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.regs' (%d).", maxTris);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.regs' (%d).", maxTris);
return false; return false;
} }
mesh.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris, RC_ALLOC_PERM); mesh.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris, RC_ALLOC_PERM);
if (!mesh.areas) if (!mesh.areas)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.areas' (%d).", maxTris);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.areas' (%d).", maxTris);
return false; return false;
} }
@ -988,8 +968,7 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
rcScopedDelete<int> nextVert = (int*)rcAlloc(sizeof(int)*maxVertices, RC_ALLOC_TEMP); rcScopedDelete<int> nextVert = (int*)rcAlloc(sizeof(int)*maxVertices, RC_ALLOC_TEMP);
if (!nextVert) if (!nextVert)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'nextVert' (%d).", maxVertices);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'nextVert' (%d).", maxVertices);
return false; return false;
} }
memset(nextVert, 0, sizeof(int)*maxVertices); memset(nextVert, 0, sizeof(int)*maxVertices);
@ -997,8 +976,7 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
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) if (!firstVert)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT);
return false; return false;
} }
for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i) for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i)
@ -1007,22 +985,19 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
rcScopedDelete<int> indices = (int*)rcAlloc(sizeof(int)*maxVertsPerCont, RC_ALLOC_TEMP); rcScopedDelete<int> indices = (int*)rcAlloc(sizeof(int)*maxVertsPerCont, RC_ALLOC_TEMP);
if (!indices) if (!indices)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'indices' (%d).", maxVertsPerCont);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'indices' (%d).", maxVertsPerCont);
return false; 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) if (!tris)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'tris' (%d).", maxVertsPerCont*3);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'tris' (%d).", maxVertsPerCont*3);
return false; 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) if (!polys)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'polys' (%d).", maxVertsPerCont*nvp);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'polys' (%d).", maxVertsPerCont*nvp);
return false; return false;
} }
unsigned short* tmpPoly = &polys[maxVertsPerCont*nvp]; unsigned short* tmpPoly = &polys[maxVertsPerCont*nvp];
@ -1053,8 +1028,7 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
printf("\t\t%d,%d,%d,%d,\n", v[0], v[1], v[2], v[3]); printf("\t\t%d,%d,%d,%d,\n", v[0], v[1], v[2], v[3]);
} }
printf("\t};\n\tconst int nverts = sizeof(verts)/(sizeof(int)*4);\n");*/ printf("\t};\n\tconst int nverts = sizeof(verts)/(sizeof(int)*4);\n");*/
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "rcBuildPolyMesh: Bad triangulation Contour %d.", i);
rcGetLog()->log(RC_LOG_WARNING, "rcBuildPolyMesh: Bad triangulation Contour %d.", i);
ntris = -ntris; ntris = -ntris;
} }
@ -1145,8 +1119,7 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
mesh.npolys++; mesh.npolys++;
if (mesh.npolys > maxTris) if (mesh.npolys > maxTris)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many polygons %d (max:%d).", mesh.npolys, maxTris);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many polygons %d (max:%d).", mesh.npolys, maxTris);
return false; return false;
} }
} }
@ -1158,13 +1131,12 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
{ {
if (vflags[i]) if (vflags[i])
{ {
if (!canRemoveVertex(mesh, (unsigned short)i)) if (!canRemoveVertex(ctx, mesh, (unsigned short)i))
continue; continue;
if (!removeVertex(mesh, (unsigned short)i, maxTris)) if (!removeVertex(ctx, mesh, (unsigned short)i, maxTris))
{ {
// Failed to remove vertex // Failed to remove vertex
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Failed to remove edge vertex %d.", i);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Failed to remove edge vertex %d.", i);
return false; return false;
} }
// Remove vertex // Remove vertex
@ -1178,8 +1150,7 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
// Calculate adjacency. // Calculate adjacency.
if (!buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, nvp)) if (!buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, nvp))
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Adjacency failed.");
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Adjacency failed.");
return false; return false;
} }
@ -1187,28 +1158,26 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*mesh.npolys, RC_ALLOC_PERM); mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*mesh.npolys, RC_ALLOC_PERM);
if (!mesh.flags) if (!mesh.flags)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.flags' (%d).", mesh.npolys);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.flags' (%d).", mesh.npolys);
return false; return false;
} }
memset(mesh.flags, 0, sizeof(unsigned short) * mesh.npolys); memset(mesh.flags, 0, sizeof(unsigned short) * mesh.npolys);
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
// if (rcGetLog()) ctx->reportBuildTime(RC_TIME_BUILD_POLYMESH, ctx->getDeltaTimeUsec(startTime, endTime));
// rcGetLog()->log(RC_LOG_PROGRESS, "Build polymesh: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
if (rcGetBuildTimes())
rcGetBuildTimes()->buildPolymesh += rcGetDeltaTimeUsec(startTime, endTime);
return true; return true;
} }
bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh) bool rcMergePolyMeshes(rcBuildContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
{ {
rcAssert(ctx);
if (!nmeshes || !meshes) if (!nmeshes || !meshes)
return true; return true;
rcTimeVal startTime = rcGetPerformanceTimer(); rcTimeVal startTime = ctx->getTime();
mesh.nvp = meshes[0]->nvp; mesh.nvp = meshes[0]->nvp;
mesh.cs = meshes[0]->cs; mesh.cs = meshes[0]->cs;
@ -1232,8 +1201,7 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
mesh.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVerts*3, RC_ALLOC_PERM); mesh.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVerts*3, RC_ALLOC_PERM);
if (!mesh.verts) if (!mesh.verts)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.verts' (%d).", maxVerts*3);
rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.verts' (%d).", maxVerts*3);
return false; return false;
} }
@ -1241,8 +1209,7 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys*2*mesh.nvp, RC_ALLOC_PERM); mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys*2*mesh.nvp, RC_ALLOC_PERM);
if (!mesh.polys) if (!mesh.polys)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.polys' (%d).", maxPolys*2*mesh.nvp);
rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.polys' (%d).", maxPolys*2*mesh.nvp);
return false; return false;
} }
memset(mesh.polys, 0xff, sizeof(unsigned short)*maxPolys*2*mesh.nvp); memset(mesh.polys, 0xff, sizeof(unsigned short)*maxPolys*2*mesh.nvp);
@ -1250,8 +1217,7 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
mesh.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys, RC_ALLOC_PERM); mesh.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys, RC_ALLOC_PERM);
if (!mesh.regs) if (!mesh.regs)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.regs' (%d).", maxPolys);
rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.regs' (%d).", maxPolys);
return false; return false;
} }
memset(mesh.regs, 0, sizeof(unsigned short)*maxPolys); memset(mesh.regs, 0, sizeof(unsigned short)*maxPolys);
@ -1259,8 +1225,7 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
mesh.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxPolys, RC_ALLOC_PERM); mesh.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxPolys, RC_ALLOC_PERM);
if (!mesh.areas) if (!mesh.areas)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.areas' (%d).", maxPolys);
rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.areas' (%d).", maxPolys);
return false; return false;
} }
memset(mesh.areas, 0, sizeof(unsigned char)*maxPolys); memset(mesh.areas, 0, sizeof(unsigned char)*maxPolys);
@ -1268,8 +1233,7 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys, RC_ALLOC_PERM); mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys, RC_ALLOC_PERM);
if (!mesh.flags) if (!mesh.flags)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.flags' (%d).", maxPolys);
rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.flags' (%d).", maxPolys);
return false; return false;
} }
memset(mesh.flags, 0, sizeof(unsigned short)*maxPolys); memset(mesh.flags, 0, sizeof(unsigned short)*maxPolys);
@ -1277,8 +1241,7 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
rcScopedDelete<int> nextVert = (int*)rcAlloc(sizeof(int)*maxVerts, RC_ALLOC_TEMP); rcScopedDelete<int> nextVert = (int*)rcAlloc(sizeof(int)*maxVerts, RC_ALLOC_TEMP);
if (!nextVert) if (!nextVert)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'nextVert' (%d).", maxVerts);
rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'nextVert' (%d).", maxVerts);
return false; return false;
} }
memset(nextVert, 0, sizeof(int)*maxVerts); memset(nextVert, 0, sizeof(int)*maxVerts);
@ -1286,8 +1249,7 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
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) if (!firstVert)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT);
rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT);
return false; return false;
} }
for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i) for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i)
@ -1296,8 +1258,7 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
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) if (!vremap)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'vremap' (%d).", maxVertsPerMesh);
rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'vremap' (%d).", maxVertsPerMesh);
return false; return false;
} }
memset(nextVert, 0, sizeof(int)*maxVerts); memset(nextVert, 0, sizeof(int)*maxVerts);
@ -1335,16 +1296,14 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
// Calculate adjacency. // Calculate adjacency.
if (!buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, mesh.nvp)) if (!buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, mesh.nvp))
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Adjacency failed.");
rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Adjacency failed.");
return false; return false;
} }
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
if (rcGetBuildTimes()) ctx->reportBuildTime(RC_TIME_MERGE_POLYMESH, ctx->getDeltaTimeUsec(startTime, endTime));
rcGetBuildTimes()->mergePolyMesh += rcGetDeltaTimeUsec(startTime, endTime);
return true; return true;
} }

View File

@ -23,9 +23,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "Recast.h" #include "Recast.h"
#include "RecastLog.h"
#include "RecastTimer.h"
#include "RecastAlloc.h" #include "RecastAlloc.h"
#include "RecastAssert.h"
static const unsigned RC_UNSET_HEIGHT = 0xffff; static const unsigned RC_UNSET_HEIGHT = 0xffff;
@ -256,12 +255,11 @@ static int findEdge(const int* edges, int nedges, int s, int t)
return UNDEF; return UNDEF;
} }
static int addEdge(int* edges, int& nedges, const int maxEdges, int s, int t, int l, int r) static int addEdge(rcBuildContext* ctx, int* edges, int& nedges, const int maxEdges, int s, int t, int l, int r)
{ {
if (nedges >= maxEdges) if (nedges >= maxEdges)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "addEdge: Too many edges (%d/%d).", nedges, maxEdges);
rcGetLog()->log(RC_LOG_ERROR, "addEdge: Too many edges (%d/%d).", nedges, maxEdges);
return UNDEF; return UNDEF;
} }
@ -319,7 +317,7 @@ static bool overlapEdges(const float* pts, const int* edges, int nedges, int s1,
return false; return false;
} }
static void completeFacet(const float* pts, int npts, int* edges, int& nedges, const int maxEdges, int& nfaces, int e) static void completeFacet(rcBuildContext* ctx, const float* pts, int npts, int* edges, int& nedges, const int maxEdges, int& nfaces, int e)
{ {
static const float EPS = 1e-5f; static const float EPS = 1e-5f;
@ -396,14 +394,14 @@ static void completeFacet(const float* pts, int npts, int* edges, int& nedges, c
// Add new edge or update face info of old edge. // Add new edge or update face info of old edge.
e = findEdge(edges, nedges, pt, s); e = findEdge(edges, nedges, pt, s);
if (e == UNDEF) if (e == UNDEF)
addEdge(edges, nedges, maxEdges, pt, s, nfaces, UNDEF); addEdge(ctx, edges, nedges, maxEdges, pt, s, nfaces, UNDEF);
else else
updateLeftFace(&edges[e*4], pt, s, nfaces); updateLeftFace(&edges[e*4], pt, s, nfaces);
// Add new edge or update face info of old edge. // Add new edge or update face info of old edge.
e = findEdge(edges, nedges, t, pt); e = findEdge(edges, nedges, t, pt);
if (e == UNDEF) if (e == UNDEF)
addEdge(edges, nedges, maxEdges, t, pt, nfaces, UNDEF); addEdge(ctx, edges, nedges, maxEdges, t, pt, nfaces, UNDEF);
else else
updateLeftFace(&edges[e*4], t, pt, nfaces); updateLeftFace(&edges[e*4], t, pt, nfaces);
@ -415,7 +413,7 @@ static void completeFacet(const float* pts, int npts, int* edges, int& nedges, c
} }
} }
static void delaunayHull(const int npts, const float* pts, static void delaunayHull(rcBuildContext* ctx, const int npts, const float* pts,
const int nhull, const int* hull, const int nhull, const int* hull,
rcIntArray& tris, rcIntArray& edges) rcIntArray& tris, rcIntArray& edges)
{ {
@ -425,15 +423,15 @@ static void delaunayHull(const int npts, const float* pts,
edges.resize(maxEdges*4); edges.resize(maxEdges*4);
for (int i = 0, j = nhull-1; i < nhull; j=i++) for (int i = 0, j = nhull-1; i < nhull; j=i++)
addEdge(&edges[0], nedges, maxEdges, hull[j],hull[i], HULL, UNDEF); addEdge(ctx, &edges[0], nedges, maxEdges, hull[j],hull[i], HULL, UNDEF);
int currentEdge = 0; int currentEdge = 0;
while (currentEdge < nedges) while (currentEdge < nedges)
{ {
if (edges[currentEdge*4+2] == UNDEF) if (edges[currentEdge*4+2] == UNDEF)
completeFacet(pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge); completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge);
if (edges[currentEdge*4+3] == UNDEF) if (edges[currentEdge*4+3] == UNDEF)
completeFacet(pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge); completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge);
currentEdge++; currentEdge++;
} }
@ -480,8 +478,7 @@ static void delaunayHull(const int npts, const float* pts,
int* t = &tris[i*4]; int* t = &tris[i*4];
if (t[0] == -1 || t[1] == -1 || t[2] == -1) if (t[0] == -1 || t[1] == -1 || t[2] == -1)
{ {
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "delaunayHull: Removing dangling face %d [%d,%d,%d].", i, t[0],t[1],t[2]);
rcGetLog()->log(RC_LOG_WARNING, "delaunayHull: Removing dangling face %d [%d,%d,%d].", i, t[0],t[1],t[2]);
t[0] = tris[tris.size()-4]; t[0] = tris[tris.size()-4];
t[1] = tris[tris.size()-3]; t[1] = tris[tris.size()-3];
t[2] = tris[tris.size()-2]; t[2] = tris[tris.size()-2];
@ -494,7 +491,7 @@ static void delaunayHull(const int npts, const float* pts,
static bool buildPolyDetail(const float* in, const int nin, static bool buildPolyDetail(rcBuildContext* ctx, const float* in, const int nin,
const float sampleDist, const float sampleMaxError, const float sampleDist, const float sampleMaxError,
const rcCompactHeightfield& chf, const rcHeightPatch& hp, const rcCompactHeightfield& chf, const rcHeightPatch& hp,
float* verts, int& nverts, rcIntArray& tris, float* verts, int& nverts, rcIntArray& tris,
@ -625,13 +622,12 @@ static bool buildPolyDetail(const float* in, const int nin,
edges.resize(0); edges.resize(0);
tris.resize(0); tris.resize(0);
delaunayHull(nverts, verts, nhull, hull, tris, edges); delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges);
if (tris.size() == 0) if (tris.size() == 0)
{ {
// Could not triangulate the poly, make sure there is some valid data there. // Could not triangulate the poly, make sure there is some valid data there.
if (rcGetLog()) ctx->log(RC_LOG_WARNING, "buildPolyDetail: Could not triangulate polygon, adding default data.");
rcGetLog()->log(RC_LOG_WARNING, "buildPolyDetail: Could not triangulate polygon, adding default data.");
for (int i = 2; i < nverts; ++i) for (int i = 2; i < nverts; ++i)
{ {
tris.push(0); tris.push(0);
@ -709,7 +705,7 @@ static bool buildPolyDetail(const float* in, const int nin,
// TODO: Incremental add instead of full rebuild. // TODO: Incremental add instead of full rebuild.
edges.resize(0); edges.resize(0);
tris.resize(0); tris.resize(0);
delaunayHull(nverts, verts, nhull, hull, tris, edges); delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges);
if (nverts >= MAX_VERTS) if (nverts >= MAX_VERTS)
break; break;
@ -918,11 +914,13 @@ static unsigned char getTriFlags(const float* va, const float* vb, const float*
bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& chf, bool rcBuildPolyMeshDetail(rcBuildContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf,
const float sampleDist, const float sampleMaxError, const float sampleDist, const float sampleMaxError,
rcPolyMeshDetail& dmesh) rcPolyMeshDetail& dmesh)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
if (mesh.nverts == 0 || mesh.npolys == 0) if (mesh.nverts == 0 || mesh.npolys == 0)
return true; return true;
@ -944,15 +942,13 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c
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) if (!bounds)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'bounds' (%d).", mesh.npolys*4);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'bounds' (%d).", mesh.npolys*4);
return false; 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) if (!poly)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'poly' (%d).", nvp*3);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'poly' (%d).", nvp*3);
return false; return false;
} }
@ -990,8 +986,7 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c
hp.data = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxhw*maxhh, RC_ALLOC_TEMP); hp.data = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxhw*maxhh, RC_ALLOC_TEMP);
if (!hp.data) if (!hp.data)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'hp.data' (%d).", maxhw*maxhh);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'hp.data' (%d).", maxhw*maxhh);
return false; return false;
} }
@ -1001,8 +996,7 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c
dmesh.meshes = (unsigned short*)rcAlloc(sizeof(unsigned short)*dmesh.nmeshes*4, RC_ALLOC_PERM); dmesh.meshes = (unsigned short*)rcAlloc(sizeof(unsigned short)*dmesh.nmeshes*4, RC_ALLOC_PERM);
if (!dmesh.meshes) if (!dmesh.meshes)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.meshes' (%d).", dmesh.nmeshes*4);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.meshes' (%d).", dmesh.nmeshes*4);
return false; return false;
} }
@ -1013,16 +1007,14 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c
dmesh.verts = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM); dmesh.verts = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM);
if (!dmesh.verts) if (!dmesh.verts)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", vcap*3);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", vcap*3);
return false; return false;
} }
dmesh.ntris = 0; dmesh.ntris = 0;
dmesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char*)*tcap*4, RC_ALLOC_PERM); dmesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char*)*tcap*4, RC_ALLOC_PERM);
if (!dmesh.tris) if (!dmesh.tris)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", tcap*4);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", tcap*4);
return false; return false;
} }
@ -1051,7 +1043,7 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c
// Build detail mesh. // Build detail mesh.
int nverts = 0; int nverts = 0;
if (!buildPolyDetail(poly, npoly, if (!buildPolyDetail(ctx, poly, npoly,
sampleDist, sampleMaxError, sampleDist, sampleMaxError,
chf, hp, verts, nverts, tris, chf, hp, verts, nverts, tris,
edges, samples)) edges, samples))
@ -1091,8 +1083,7 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c
float* newv = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM); float* newv = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM);
if (!newv) if (!newv)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newv' (%d).", vcap*3);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newv' (%d).", vcap*3);
return false; return false;
} }
if (dmesh.nverts) if (dmesh.nverts)
@ -1116,8 +1107,7 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c
unsigned char* newt = (unsigned char*)rcAlloc(sizeof(unsigned char)*tcap*4, RC_ALLOC_PERM); unsigned char* newt = (unsigned char*)rcAlloc(sizeof(unsigned char)*tcap*4, RC_ALLOC_PERM);
if (!newt) if (!newt)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newt' (%d).", tcap*4);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newt' (%d).", tcap*4);
return false; return false;
} }
if (dmesh.ntris) if (dmesh.ntris)
@ -1136,17 +1126,18 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c
} }
} }
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
if (rcGetBuildTimes()) ctx->reportBuildTime(RC_TIME_BUILD_POLYMESHDETAIL, ctx->getDeltaTimeUsec(startTime, endTime));
rcGetBuildTimes()->buildDetailMesh += rcGetDeltaTimeUsec(startTime, endTime);
return true; return true;
} }
bool rcMergePolyMeshDetails(rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh) bool rcMergePolyMeshDetails(rcBuildContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
int maxVerts = 0; int maxVerts = 0;
int maxTris = 0; int maxTris = 0;
@ -1164,8 +1155,7 @@ bool rcMergePolyMeshDetails(rcPolyMeshDetail** meshes, const int nmeshes, rcPoly
mesh.meshes = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxMeshes*4, RC_ALLOC_PERM); mesh.meshes = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxMeshes*4, RC_ALLOC_PERM);
if (!mesh.meshes) if (!mesh.meshes)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'pmdtl.meshes' (%d).", maxMeshes*4);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'pmdtl.meshes' (%d).", maxMeshes*4);
return false; return false;
} }
@ -1173,8 +1163,7 @@ bool rcMergePolyMeshDetails(rcPolyMeshDetail** meshes, const int nmeshes, rcPoly
mesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris*4, RC_ALLOC_PERM); mesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris*4, RC_ALLOC_PERM);
if (!mesh.tris) if (!mesh.tris)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", maxTris*4);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", maxTris*4);
return false; return false;
} }
@ -1182,8 +1171,7 @@ bool rcMergePolyMeshDetails(rcPolyMeshDetail** meshes, const int nmeshes, rcPoly
mesh.verts = (float*)rcAlloc(sizeof(float)*maxVerts*3, RC_ALLOC_PERM); mesh.verts = (float*)rcAlloc(sizeof(float)*maxVerts*3, RC_ALLOC_PERM);
if (!mesh.verts) if (!mesh.verts)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", maxVerts*3);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", maxVerts*3);
return false; return false;
} }
@ -1218,10 +1206,9 @@ bool rcMergePolyMeshDetails(rcPolyMeshDetail** meshes, const int nmeshes, rcPoly
} }
} }
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
if (rcGetBuildTimes()) ctx->reportBuildTime(RC_TIME_MERGE_POLYMESHDETAIL, ctx->getDeltaTimeUsec(startTime, endTime));
rcGetBuildTimes()->mergePolyMeshDetail += rcGetDeltaTimeUsec(startTime, endTime);
return true; return true;
} }

View File

@ -20,9 +20,8 @@
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include "Recast.h" #include "Recast.h"
#include "RecastTimer.h"
#include "RecastLog.h"
#include "RecastAlloc.h" #include "RecastAlloc.h"
#include "RecastAssert.h"
inline bool overlapBounds(const float* amin, const float* amax, const float* bmin, const float* bmax) inline bool overlapBounds(const float* amin, const float* amax, const float* bmin, const float* bmax)
{ {
@ -83,10 +82,11 @@ static void freeSpan(rcHeightfield& hf, rcSpan* ptr)
hf.freelist = ptr; hf.freelist = ptr;
} }
void rcAddSpan(rcHeightfield& hf, const int x, const int y, static void addSpan(rcHeightfield& hf, const int x, const int y,
const unsigned short smin, const unsigned short smax, const unsigned short smin, const unsigned short smax,
const unsigned char area, const int flagMergeThr) const unsigned char area, const int flagMergeThr)
{ {
int idx = x + y*hf.width; int idx = x + y*hf.width;
rcSpan* s = allocSpan(hf); rcSpan* s = allocSpan(hf);
@ -154,6 +154,14 @@ void rcAddSpan(rcHeightfield& hf, const int x, const int y,
} }
} }
void rcAddSpan(rcBuildContext* 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);
}
static int clipPoly(const float* in, int n, float* out, float pnx, float pnz, float pd) static int clipPoly(const float* in, int n, float* out, float pnx, float pnz, float pd)
{ {
float d[12]; float d[12];
@ -263,32 +271,35 @@ 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 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); unsigned short ismax = (unsigned short)rcClamp((int)ceilf(smax * ich), (int)ismin+1, RC_SPAN_MAX_HEIGHT);
rcAddSpan(hf, x, y, ismin, ismax, area, flagMergeThr); addSpan(hf, x, y, ismin, ismax, area, flagMergeThr);
} }
} }
} }
void rcRasterizeTriangle(const float* v0, const float* v1, const float* v2, void rcRasterizeTriangle(rcBuildContext* ctx, const float* v0, const float* v1, const float* v2,
const unsigned char area, rcHeightfield& solid, const unsigned char area, rcHeightfield& solid,
const int flagMergeThr) const int flagMergeThr)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
const float ics = 1.0f/solid.cs; const float ics = 1.0f/solid.cs;
const float ich = 1.0f/solid.ch; const float ich = 1.0f/solid.ch;
rasterizeTri(v0, v1, v2, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr); rasterizeTri(v0, v1, v2, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
if (rcGetBuildTimes()) ctx->reportBuildTime(RC_TIME_RASTERIZE_TRIANGLES, ctx->getDeltaTimeUsec(startTime, endTime));
rcGetBuildTimes()->rasterizeTriangles += rcGetDeltaTimeUsec(startTime, endTime);
} }
void rcRasterizeTriangles(const float* verts, const int /*nv*/, void rcRasterizeTriangles(rcBuildContext* ctx, const float* verts, const int /*nv*/,
const int* tris, const unsigned char* areas, const int nt, const int* tris, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr) rcHeightfield& solid, const int flagMergeThr)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
const float ics = 1.0f/solid.cs; const float ics = 1.0f/solid.cs;
const float ich = 1.0f/solid.ch; const float ich = 1.0f/solid.ch;
@ -302,17 +313,18 @@ void rcRasterizeTriangles(const float* verts, const int /*nv*/,
rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr); rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
} }
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
if (rcGetBuildTimes()) ctx->reportBuildTime(RC_TIME_RASTERIZE_TRIANGLES, ctx->getDeltaTimeUsec(startTime, endTime));
rcGetBuildTimes()->rasterizeTriangles += rcGetDeltaTimeUsec(startTime, endTime);
} }
void rcRasterizeTriangles(const float* verts, const int /*nv*/, void rcRasterizeTriangles(rcBuildContext* ctx, const float* verts, const int /*nv*/,
const unsigned short* tris, const unsigned char* areas, const int nt, const unsigned short* tris, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr) rcHeightfield& solid, const int flagMergeThr)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
const float ics = 1.0f/solid.cs; const float ics = 1.0f/solid.cs;
const float ich = 1.0f/solid.ch; const float ich = 1.0f/solid.ch;
@ -326,16 +338,17 @@ void rcRasterizeTriangles(const float* verts, const int /*nv*/,
rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr); rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
} }
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
if (rcGetBuildTimes()) ctx->reportBuildTime(RC_TIME_RASTERIZE_TRIANGLES, ctx->getDeltaTimeUsec(startTime, endTime));
rcGetBuildTimes()->rasterizeTriangles += rcGetDeltaTimeUsec(startTime, endTime);
} }
void rcRasterizeTriangles(const float* verts, const unsigned char* areas, const int nt, void rcRasterizeTriangles(rcBuildContext* ctx, const float* verts, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr) rcHeightfield& solid, const int flagMergeThr)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
const float ics = 1.0f/solid.cs; const float ics = 1.0f/solid.cs;
const float ich = 1.0f/solid.ch; const float ich = 1.0f/solid.ch;
@ -349,8 +362,7 @@ void rcRasterizeTriangles(const float* verts, const unsigned char* areas, const
rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr); rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
} }
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
if (rcGetBuildTimes()) ctx->reportBuildTime(RC_TIME_RASTERIZE_TRIANGLES, ctx->getDeltaTimeUsec(startTime, endTime));
rcGetBuildTimes()->rasterizeTriangles += rcGetDeltaTimeUsec(startTime, endTime);
} }

View File

@ -23,9 +23,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "Recast.h" #include "Recast.h"
#include "RecastLog.h"
#include "RecastTimer.h"
#include "RecastAlloc.h" #include "RecastAlloc.h"
#include "RecastAssert.h"
#include <new> #include <new>
@ -688,7 +687,7 @@ static void walkContour(int x, int y, int i, int dir,
} }
} }
static bool filterSmallRegions(int minRegionSize, int mergeRegionSize, static bool filterSmallRegions(rcBuildContext* ctx, int minRegionSize, int mergeRegionSize,
unsigned short& maxRegionId, unsigned short& maxRegionId,
rcCompactHeightfield& chf, rcCompactHeightfield& chf,
unsigned short* srcReg) unsigned short* srcReg)
@ -700,8 +699,7 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize,
rcRegion* regions = (rcRegion*)rcAlloc(sizeof(rcRegion)*nreg, RC_ALLOC_TEMP); rcRegion* regions = (rcRegion*)rcAlloc(sizeof(rcRegion)*nreg, RC_ALLOC_TEMP);
if (!regions) if (!regions)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "filterSmallRegions: Out of memory 'regions' (%d).", nreg);
rcGetLog()->log(RC_LOG_ERROR, "filterSmallRegions: Out of memory 'regions' (%d).", nreg);
return false; return false;
} }
@ -888,9 +886,11 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize,
} }
bool rcBuildDistanceField(rcCompactHeightfield& chf) bool rcBuildDistanceField(rcBuildContext* ctx, rcCompactHeightfield& chf)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
if (chf.dist) if (chf.dist)
{ {
@ -901,29 +901,27 @@ bool rcBuildDistanceField(rcCompactHeightfield& chf)
unsigned short* src = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP); unsigned short* src = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
if (!src) if (!src)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'src' (%d).", chf.spanCount);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'src' (%d).", chf.spanCount);
return false; return false;
} }
unsigned short* dst = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP); unsigned short* dst = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
if (!dst) if (!dst)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'dst' (%d).", chf.spanCount);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'dst' (%d).", chf.spanCount);
rcFree(src); rcFree(src);
return false; return false;
} }
unsigned short maxDist = 0; unsigned short maxDist = 0;
rcTimeVal distStartTime = rcGetPerformanceTimer(); rcTimeVal distStartTime = ctx->getTime();
calculateDistanceField(chf, src, maxDist); calculateDistanceField(chf, src, maxDist);
chf.maxDistance = maxDist; chf.maxDistance = maxDist;
rcTimeVal distEndTime = rcGetPerformanceTimer(); rcTimeVal distEndTime = ctx->getTime();
rcTimeVal blurStartTime = rcGetPerformanceTimer(); rcTimeVal blurStartTime = ctx->getTime();
// Blur // Blur
if (boxBlur(chf, 1, src, dst) != src) if (boxBlur(chf, 1, src, dst) != src)
@ -932,24 +930,15 @@ bool rcBuildDistanceField(rcCompactHeightfield& chf)
// Store distance. // Store distance.
chf.dist = src; chf.dist = src;
rcTimeVal blurEndTime = rcGetPerformanceTimer(); rcTimeVal blurEndTime = ctx->getTime();
rcFree(dst); rcFree(dst);
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
/* if (rcGetLog()) ctx->reportBuildTime(RC_TIME_BUILD_DISTANCEFIELD, ctx->getDeltaTimeUsec(startTime, endTime));
{ ctx->reportBuildTime(RC_TIME_BUILD_DISTANCEFIELD_DIST, ctx->getDeltaTimeUsec(distStartTime, distEndTime));
rcGetLog()->log(RC_LOG_PROGRESS, "Build distance field: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f); ctx->reportBuildTime(RC_TIME_BUILD_DISTANCEFIELD_BLUR, ctx->getDeltaTimeUsec(blurStartTime, blurEndTime));
rcGetLog()->log(RC_LOG_PROGRESS, " - dist: %.3f ms", rcGetDeltaTimeUsec(distStartTime, distEndTime)/1000.0f);
rcGetLog()->log(RC_LOG_PROGRESS, " - blur: %.3f ms", rcGetDeltaTimeUsec(blurStartTime, blurEndTime)/1000.0f);
}*/
if (rcGetBuildTimes())
{
rcGetBuildTimes()->buildDistanceField += rcGetDeltaTimeUsec(startTime, endTime);
rcGetBuildTimes()->buildDistanceFieldDist += rcGetDeltaTimeUsec(distStartTime, distEndTime);
rcGetBuildTimes()->buildDistanceFieldBlur += rcGetDeltaTimeUsec(blurStartTime, blurEndTime);
}
return true; return true;
} }
@ -984,10 +973,12 @@ struct rcSweepSpan
unsigned short nei; // neighbour id unsigned short nei; // neighbour id
}; };
bool rcBuildRegionsMonotone(rcCompactHeightfield& chf, bool rcBuildRegionsMonotone(rcBuildContext* ctx, rcCompactHeightfield& chf,
const int borderSize, const int minRegionSize, const int mergeRegionSize) const int borderSize, const int minRegionSize, const int mergeRegionSize)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
const int w = chf.width; const int w = chf.width;
const int h = chf.height; const int h = chf.height;
@ -996,8 +987,7 @@ bool rcBuildRegionsMonotone(rcCompactHeightfield& chf,
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) if (!srcReg)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount);
return false; return false;
} }
memset(srcReg,0,sizeof(unsigned short)*chf.spanCount); memset(srcReg,0,sizeof(unsigned short)*chf.spanCount);
@ -1006,8 +996,7 @@ bool rcBuildRegionsMonotone(rcCompactHeightfield& chf,
rcScopedDelete<rcSweepSpan> sweeps = (rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP); rcScopedDelete<rcSweepSpan> sweeps = (rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP);
if (!sweeps) if (!sweeps)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps);
return false; return false;
} }
@ -1112,34 +1101,33 @@ bool rcBuildRegionsMonotone(rcCompactHeightfield& chf,
} }
} }
rcTimeVal filterStartTime = rcGetPerformanceTimer(); rcTimeVal filterStartTime = ctx->getTime();
// Filter out small regions. // Filter out small regions.
chf.maxRegions = id; chf.maxRegions = id;
if (!filterSmallRegions(minRegionSize, mergeRegionSize, chf.maxRegions, chf, srcReg)) if (!filterSmallRegions(ctx, minRegionSize, mergeRegionSize, chf.maxRegions, chf, srcReg))
return false; return false;
rcTimeVal filterEndTime = rcGetPerformanceTimer(); rcTimeVal filterEndTime = ctx->getTime();
// Store the result out. // Store the result out.
for (int i = 0; i < chf.spanCount; ++i) for (int i = 0; i < chf.spanCount; ++i)
chf.spans[i].reg = srcReg[i]; chf.spans[i].reg = srcReg[i];
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
if (rcGetBuildTimes()) ctx->reportBuildTime(RC_TIME_BUILD_REGIONS, ctx->getDeltaTimeUsec(startTime, endTime));
{ ctx->reportBuildTime(RC_TIME_BUILD_REGIONS_FILTER, ctx->getDeltaTimeUsec(filterStartTime, filterEndTime));
rcGetBuildTimes()->buildRegions += rcGetDeltaTimeUsec(startTime, endTime);
rcGetBuildTimes()->buildRegionsFilter += rcGetDeltaTimeUsec(filterStartTime, filterEndTime);
}
return true; return true;
} }
bool rcBuildRegions(rcCompactHeightfield& chf, bool rcBuildRegions(rcBuildContext* ctx, rcCompactHeightfield& chf,
const int borderSize, const int minRegionSize, const int mergeRegionSize) const int borderSize, const int minRegionSize, const int mergeRegionSize)
{ {
rcTimeVal startTime = rcGetPerformanceTimer(); rcAssert(ctx);
rcTimeVal startTime = ctx->getTime();
const int w = chf.width; const int w = chf.width;
const int h = chf.height; const int h = chf.height;
@ -1147,12 +1135,11 @@ bool rcBuildRegions(rcCompactHeightfield& chf,
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) if (!buf)
{ {
if (rcGetLog()) ctx->log(RC_LOG_ERROR, "rcBuildRegions: Out of memory 'tmp' (%d).", chf.spanCount*4);
rcGetLog()->log(RC_LOG_ERROR, "rcBuildRegions: Out of memory 'tmp' (%d).", chf.spanCount*4);
return false; return false;
} }
rcTimeVal regStartTime = rcGetPerformanceTimer(); rcTimeVal regStartTime = ctx->getTime();
rcIntArray stack(1024); rcIntArray stack(1024);
rcIntArray visited(1024); rcIntArray visited(1024);
@ -1187,7 +1174,7 @@ bool rcBuildRegions(rcCompactHeightfield& chf,
{ {
level = level >= 2 ? level-2 : 0; level = level >= 2 ? level-2 : 0;
rcTimeVal expStartTime = rcGetPerformanceTimer(); rcTimeVal expStartTime = ctx->getTime();
// Expand current regions until no empty connected cells found. // Expand current regions until no empty connected cells found.
if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg) if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg)
@ -1196,9 +1183,9 @@ bool rcBuildRegions(rcCompactHeightfield& chf,
rcSwap(srcDist, dstDist); rcSwap(srcDist, dstDist);
} }
expTime += rcGetPerformanceTimer() - expStartTime; expTime += ctx->getTime() - expStartTime;
rcTimeVal floodStartTime = rcGetPerformanceTimer(); rcTimeVal floodStartTime = ctx->getTime();
// Mark new regions with IDs. // Mark new regions with IDs.
for (int y = 0; y < h; ++y) for (int y = 0; y < h; ++y)
@ -1217,7 +1204,7 @@ bool rcBuildRegions(rcCompactHeightfield& chf,
} }
} }
floodTime += rcGetPerformanceTimer() - floodStartTime; floodTime += ctx->getTime() - floodStartTime;
} }
@ -1228,40 +1215,28 @@ bool rcBuildRegions(rcCompactHeightfield& chf,
rcSwap(srcDist, dstDist); rcSwap(srcDist, dstDist);
} }
rcTimeVal regEndTime = rcGetPerformanceTimer(); rcTimeVal regEndTime = ctx->getTime();
rcTimeVal filterStartTime = rcGetPerformanceTimer(); rcTimeVal filterStartTime = ctx->getTime();
// Filter out small regions. // Filter out small regions.
chf.maxRegions = regionId; chf.maxRegions = regionId;
if (!filterSmallRegions(minRegionSize, mergeRegionSize, chf.maxRegions, chf, srcReg)) if (!filterSmallRegions(ctx, minRegionSize, mergeRegionSize, chf.maxRegions, chf, srcReg))
return false; return false;
rcTimeVal filterEndTime = rcGetPerformanceTimer(); rcTimeVal filterEndTime = ctx->getTime();
// Write the result out. // Write the result out.
for (int i = 0; i < chf.spanCount; ++i) for (int i = 0; i < chf.spanCount; ++i)
chf.spans[i].reg = srcReg[i]; chf.spans[i].reg = srcReg[i];
rcTimeVal endTime = rcGetPerformanceTimer(); rcTimeVal endTime = ctx->getTime();
/* if (rcGetLog()) ctx->reportBuildTime(RC_TIME_BUILD_REGIONS, ctx->getDeltaTimeUsec(startTime, endTime));
{ ctx->reportBuildTime(RC_TIME_BUILD_REGIONS_WATERSHED, ctx->getDeltaTimeUsec(regStartTime, regEndTime));
rcGetLog()->log(RC_LOG_PROGRESS, "Build regions: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f); ctx->reportBuildTime(RC_TIME_BUILD_REGIONS_EXPAND, ctx->getDeltaTimeUsec(0, expTime));
rcGetLog()->log(RC_LOG_PROGRESS, " - reg: %.3f ms", rcGetDeltaTimeUsec(regStartTime, regEndTime)/1000.0f); ctx->reportBuildTime(RC_TIME_BUILD_REGIONS_FLOOD, ctx->getDeltaTimeUsec(0, floodTime));
rcGetLog()->log(RC_LOG_PROGRESS, " - exp: %.3f ms", rcGetDeltaTimeUsec(0, expTime)/1000.0f); ctx->reportBuildTime(RC_TIME_BUILD_REGIONS_FILTER, ctx->getDeltaTimeUsec(filterStartTime, filterEndTime));
rcGetLog()->log(RC_LOG_PROGRESS, " - flood: %.3f ms", rcGetDeltaTimeUsec(0, floodTime)/1000.0f);
rcGetLog()->log(RC_LOG_PROGRESS, " - filter: %.3f ms", rcGetDeltaTimeUsec(filterStartTime, filterEndTime)/1000.0f);
}
*/
if (rcGetBuildTimes())
{
rcGetBuildTimes()->buildRegions += rcGetDeltaTimeUsec(startTime, endTime);
rcGetBuildTimes()->buildRegionsReg += rcGetDeltaTimeUsec(regStartTime, regEndTime);
rcGetBuildTimes()->buildRegionsExp += rcGetDeltaTimeUsec(0, expTime);
rcGetBuildTimes()->buildRegionsFlood += rcGetDeltaTimeUsec(0, floodTime);
rcGetBuildTimes()->buildRegionsFilter += rcGetDeltaTimeUsec(filterStartTime, filterEndTime);
}
return true; return true;
} }

View File

@ -1,60 +0,0 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#include "RecastTimer.h"
#if defined(WIN32)
// Win32
#include <windows.h>
rcTimeVal rcGetPerformanceTimer()
{
__int64 count;
QueryPerformanceCounter((LARGE_INTEGER*)&count);
return count;
}
int rcGetDeltaTimeUsec(rcTimeVal start, rcTimeVal end)
{
static __int64 freq = 0;
if (freq == 0)
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
__int64 elapsed = end - start;
return (int)(elapsed*1000000 / freq);
}
#else
// Linux, BSD, OSX
#include <sys/time.h>
rcTimeVal rcGetPerformanceTimer()
{
timeval now;
gettimeofday(&now, 0);
return (rcTimeVal)now.tv_sec*1000000L + (rcTimeVal)now.tv_usec;
}
int rcGetDeltaTimeUsec(rcTimeVal start, rcTimeVal end)
{
return (int)(end - start);
}
#endif