- (too) large refactoring of the generation and demo code to support tiled preprocessing

- added rcFixupAdjacentContours which adjust adjacent contour sets so that that they share all vertices (still buggy!)
- changed the demo stucture to handle tiled navmesh generation process (still ugly)
- the performance results are put into a struct instead of logged immediatelly
- added ChunkyTriMesh class which allows to partiotion a trimesh to smaller pieces using AABB tree
This commit is contained in:
Mikko Mononen 2009-05-17 13:31:09 +00:00
parent dac9bc0f64
commit c56ebb7e77
19 changed files with 5479 additions and 284 deletions

View File

@ -61,8 +61,8 @@ static int compareItemZ(const void* va, const void* vb)
return 0;
}
void calcExtends(BVItem* items, int nitems, int imin, int imax,
unsigned short* bmin, unsigned short* bmax)
static void calcExtends(BVItem* items, int nitems, int imin, int imax,
unsigned short* bmin, unsigned short* bmax)
{
bmin[0] = items[imin].bmin[0];
bmin[1] = items[imin].bmin[1];
@ -160,21 +160,10 @@ void subdivide(BVItem* items, int nitems, int imin, int imax, int& curNode, dtBV
}
}
/*struct rcPolyMesh
{
inline rcPolyMesh() : verts(0), polys(0), nverts(0), npolys(0), nvp(3) {}
inline ~rcPolyMesh() { delete [] verts; delete [] polys; }
unsigned short* verts;
unsigned short* polys;
int nverts;
int npolys;
int nvp;
};*/
int createBVTree(const unsigned short* verts, const int nverts,
const unsigned short* polys, const int npolys, const int nvp,
float cs, float ch,
int nnodes, dtBVNode* nodes)
static int createBVTree(const unsigned short* verts, const int nverts,
const unsigned short* polys, const int npolys, const int nvp,
float cs, float ch,
int nnodes, dtBVNode* nodes)
{
// Build tree
BVItem* items = new BVItem[npolys];
@ -224,6 +213,11 @@ bool dtCreateNavMeshData(const unsigned short* verts, const int nverts,
{
if (nvp != DT_VERTS_PER_POLYGON)
return false;
if (!nverts)
return false;
if (!npolys)
return false;
// Calculate data size
const int headerSize = sizeof(dtStatNavMeshHeader);

View File

@ -22,6 +22,8 @@
struct rcConfig
{
int width, height; // Dimensions of the rasterized heighfield
int tileSize; // Size if a tile.
int borderSize; // Non-navigable Border around the heightfield.
float cs, ch; // Grid cell size and height.
float bmin[3], bmax[3]; // Grid bounds.
float walkableSlopeAngle; // Maximum walkble slope angle in degrees.
@ -43,6 +45,8 @@ struct rcSpan
rcSpan* next;
};
static const int RC_SPANS_PER_POOL = 2048;
struct rcSpanPool
{
rcSpanPool* next;
@ -93,8 +97,7 @@ struct rcCompactHeightfield
int walkableHeight, walkableClimb;
unsigned short maxDistance;
unsigned short maxRegions;
float minx, miny, minz;
float maxx, maxy, maxz;
float bmin[3], bmax[3];
float cs, ch;
rcCompactCell* cells;
rcCompactSpan* spans;
@ -102,13 +105,12 @@ struct rcCompactHeightfield
struct rcContour
{
inline rcContour() : verts(0), nverts(0), rverts(0), nrverts(0), cx(0), cy(0), cz(0) { }
inline rcContour() : verts(0), nverts(0), rverts(0), nrverts(0) { }
inline ~rcContour() { delete [] verts; delete [] rverts; }
int* verts;
int nverts;
int* rverts;
int nrverts;
int cx,cy,cz;
unsigned short reg;
};
@ -129,6 +131,8 @@ struct rcPolyMesh
int nverts;
int npolys;
int nvp;
float bmin[3], bmax[3];
float cs, ch;
};
class rcIntArray
@ -257,7 +261,7 @@ void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax);
// cs - (in) grid cell size
// w - (out) grid width
// h - (out) grid height
void rcCalcGridSize(float* bmin, float* bmax, float cs, int* w, int* h);
void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h);
// Creates and initializes new heightfield.
// Params:
@ -270,12 +274,14 @@ bool rcCreateHeightfield(rcHeightfield& hf, int width, int height);
// the maximun walkable slope angle.
// Params:
// walkableSlopeAngle - (in) maximun slope angle in degrees.
// verts - (in) array of vertices
// nv - (in) vertex count
// tris - (in) array of triangle vertex indices
// norms - (in) array of triangle normals
// nt - (in) triangle count
// flags - (out) array of triangle flags
void rcMarkWalkableTriangles(const float walkableSlopeAngle,
const int* tris, const float* norms, int nt,
const float* verts, int nv,
const int* tris, int nt,
unsigned char* flags);
// Rasterizes the triangles into heightfield spans.
@ -356,7 +362,7 @@ bool rcBuildDistanceField(rcCompactHeightfield& chf);
// maxMergeRegionSize - (in) the largest allowed regions size which can be merged.
// Returns false if operation ran out of memory.
bool rcBuildRegions(rcCompactHeightfield& chf,
int walkableRadius, int minRegionSize, int mergeRegionSize);
int walkableRadius, int borderSize, int minRegionSize, int mergeRegionSize);
// Builds simplified contours from the regions outlines.
// Params:
@ -369,14 +375,36 @@ bool rcBuildContours(rcCompactHeightfield& chf,
float maxError, int maxEdgeLen,
rcContourSet& cset);
// Ensures that connected contour sets A and B share the same vertices at the shared edges.
// Params:
// cseta - (in) contour set A.
// csetb - (in) contour set B.
// edge - (in) which edge to conform: 1) B is left of A 2) B is top of A
// borderSize - (in) the border which was used when the contours were generated.
// tileSize - (in) the tile size which was used when the contours were generated.
// orig - (in) origin of the contour set A.
// cs - (in) grid cell size
// ch - (in) grid cell height
bool rcFixupAdjacentContours(rcContourSet* cseta, rcContourSet* csetb, int edge, int edgePos);
// Translates the cordinates of the contour set.
// Params:
// cset - (in) contour set to translate.
// dx - (in) delta X.
// dy - (in) delta Y.
// dz - (in) delta Z.
void rcTranslateContours(rcContourSet* cset, int dx, int dy, int dz);
// Builds connected convex polygon mesh from contour polygons.
// Params:
// cset - (in) contour set.
// mesh - (out) poly mesh.
// nvp - (int) maximum number of vertices per polygon.
// Returns false if operation ran out of memory.
bool rcBuildPolyMesh(rcContourSet& cset, rcPolyMesh& mesh, int nvp);
bool rcBuildPolyMesh(rcContourSet& cset,
const float* bmin, const float* bmax,
const float cs, const float ch, int nvp,
rcPolyMesh& mesh);
bool rcBuildNavMesh(const rcConfig& cfg,
const float* verts, const int nverts,

View File

@ -48,7 +48,7 @@ void rcDebugDrawCompactHeightfieldDistance(const struct rcCompactHeightfield& ch
void rcDebugDrawRawContours(const struct rcContourSet& cset, const float* orig, float cs, float ch);
void rcDebugDrawContours(const struct rcContourSet& cset, const float* orig, float cs, float ch);
void rcDebugDrawPolyMesh(const struct rcPolyMesh& mesh, const float* orig, float cs, float ch);
void rcDebugDrawPolyMesh(const struct rcPolyMesh& mesh);
void rcDebugDrawCylinderWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, const float* col);
void rcDebugDrawBoxWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, const float* col);

View File

@ -47,7 +47,32 @@ private:
int m_textPoolSize;
};
struct rcBuildTimes
{
int rasterizeTriangles;
int buildCompact;
int buildContours;
int buildContoursTrace;
int buildContoursSimplify;
int filterBorder;
int filterWalkable;
int filterMarkReachable;
int buildPolymesh;
int buildDistanceField;
int buildDistanceFieldDist;
int buildDistanceFieldBlur;
int buildRegions;
int buildRegionsReg;
int buildRegionsExp;
int buildRegionsFlood;
int buildRegionsFilter;
int fixupContours;
};
void rcSetLog(rcLog* log);
rcLog* rcGetLog();
void rcSetBuildTimes(rcBuildTimes* btimes);
rcBuildTimes* rcGetBuildTimes();
#endif // RECAST_LOG_H

View File

@ -54,7 +54,7 @@ void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax)
}
}
void rcCalcGridSize(float* bmin, float* bmax, float cs, int* w, int* h)
void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h)
{
*w = (int)((bmax[0] - bmin[0])/cs+0.5f);
*h = (int)((bmax[2] - bmin[2])/cs+0.5f);
@ -71,7 +71,7 @@ bool rcCreateHeightfield(rcHeightfield& hf, int width, int height)
return true;
}
void rcMarkWalkableTriangles(const float walkableSlopeAngle,
/*void rcMarkWalkableTriangles(const float walkableSlopeAngle,
const int* tris, const float* norms, int nt,
unsigned char* flags)
{
@ -83,6 +83,34 @@ void rcMarkWalkableTriangles(const float walkableSlopeAngle,
if (norms[i*3+1] > walkableThr)
flags[i] |= RC_WALKABLE;
}
}*/
static void calcTriNormal(const float* v0, const float* v1, const float* v2, float* norm)
{
float e0[3], e1[3];
vsub(e0, v1, v0);
vsub(e1, v2, v0);
vcross(norm, e0, e1);
vnormalize(norm);
}
void rcMarkWalkableTriangles(const float walkableSlopeAngle,
const float* verts, int nv,
const int* tris, int nt,
unsigned char* flags)
{
const float walkableThr = cosf(walkableSlopeAngle/180.0f*(float)M_PI);
float norm[3];
for (int i = 0; i < nt; ++i)
{
const int* tri = &tris[i*3];
calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
// Check if the face is walkable.
if (norm[1] > walkableThr)
flags[i] |= RC_WALKABLE;
}
}
static int getSpanCount(unsigned char flags, rcHeightfield& hf)
@ -129,12 +157,9 @@ bool rcBuildCompactHeightfield(const float* bmin, const float* bmax,
chf.walkableHeight = walkableHeight;
chf.walkableClimb = walkableClimb;
chf.maxRegions = 0;
chf.minx = bmin[0];
chf.miny = bmin[1];
chf.minz = bmin[2];
chf.maxx = bmax[0];
chf.maxy = bmax[1] + walkableHeight*ch;
chf.maxz = bmax[2];
vcopy(chf.bmin, bmin);
vcopy(chf.bmax, bmax);
chf.bmax[1] += walkableHeight*ch;
chf.cs = cs;
chf.ch = ch;
chf.cells = new rcCompactCell[w*h];
@ -226,12 +251,38 @@ bool rcBuildCompactHeightfield(const float* bmin, const float* bmax,
rcTimeVal endTime = rcGetPerformanceTimer();
if (rcGetLog())
rcGetLog()->log(RC_LOG_PROGRESS, "Build compact: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
// if (rcGetLog())
// rcGetLog()->log(RC_LOG_PROGRESS, "Build compact: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
if (rcGetBuildTimes())
rcGetBuildTimes()->buildCompact += rcGetDeltaTimeUsec(startTime, endTime);
return true;
}
static int getHeightfieldMemoryUsage(const rcHeightfield& hf)
{
int size = 0;
size += sizeof(hf);
size += hf.width * hf.height * sizeof(rcSpan*);
rcSpanPool* pool = hf.pools;
while (pool)
{
size += (sizeof(rcSpanPool) - sizeof(rcSpan)) + sizeof(rcSpan)*RC_SPANS_PER_POOL;
pool = pool->next;
}
return size;
}
static int getCompactHeightFieldMemoryusage(const rcCompactHeightfield& chf)
{
int size = 0;
size += sizeof(rcCompactHeightfield);
size += sizeof(rcCompactSpan) * chf.spanCount;
size += sizeof(rcCompactCell) * chf.width * chf.height;
return size;
}
bool rcBuildNavMesh(const rcConfig& cfg,
const float* verts, const int nverts,
const int* tris, const unsigned char* tflags, const int ntris,
@ -253,23 +304,23 @@ bool rcBuildNavMesh(const rcConfig& cfg,
rcFilterWalkableBorderSpans(cfg.walkableHeight, cfg.walkableClimb, solid);
rcFilterWalkableLowHeightSpans(cfg.walkableHeight, solid);
if (!rcMarkReachableSpans(cfg.walkableHeight, cfg.walkableClimb, solid))
/* if (!rcMarkReachableSpans(cfg.walkableHeight, cfg.walkableClimb, solid))
{
if (rcGetLog())
rcGetLog()->log(RC_LOG_ERROR, "rcBuildNavMesh: Could not build navigable heightfield.");
return false;
}
}*/
if (!rcBuildCompactHeightfield(cfg.bmin, cfg.bmax, cfg.cs, cfg.ch,
cfg.walkableHeight, cfg.walkableClimb,
RC_WALKABLE|RC_REACHABLE, solid, chf))
RC_WALKABLE/*|RC_REACHABLE*/, solid, chf))
{
if (rcGetLog())
rcGetLog()->log(RC_LOG_ERROR, "rcBuildNavMesh: Could not build compact data.");
return false;
}
if (!rcBuildDistanceField(chf))
{
if (rcGetLog())
@ -277,7 +328,7 @@ bool rcBuildNavMesh(const rcConfig& cfg,
return false;
}
if (!rcBuildRegions(chf, cfg.walkableRadius, cfg.minRegionSize, cfg.mergeRegionSize))
if (!rcBuildRegions(chf, cfg.walkableRadius, cfg.borderSize, cfg.minRegionSize, cfg.mergeRegionSize))
{
if (rcGetLog())
rcGetLog()->log(RC_LOG_ERROR, "rcBuildNavMesh: Could not build regions.");
@ -291,7 +342,8 @@ bool rcBuildNavMesh(const rcConfig& cfg,
return false;
}
if (!rcBuildPolyMesh(cset, polyMesh, cfg.maxVertsPerPoly))
if (!rcBuildPolyMesh(cset, cfg.bmin, cfg.bmax, cfg.cs, cfg.ch,
cfg.maxVertsPerPoly, polyMesh))
{
if (rcGetLog())
rcGetLog()->log(RC_LOG_ERROR, "rcBuildNavMesh: Could not triangulate contours.");

View File

@ -501,7 +501,7 @@ bool rcBuildContours(rcCompactHeightfield& chf,
return false;
}
rcTimeVal boundaryStartTime = rcGetPerformanceTimer();
rcTimeVal traceStartTime = rcGetPerformanceTimer();
// Mark boundaries.
for (int y = 0; y < h; ++y)
@ -513,7 +513,7 @@ bool rcBuildContours(rcCompactHeightfield& chf,
{
unsigned char res = 0;
const rcCompactSpan& s = chf.spans[i];
if (s.reg == 0)
if (!s.reg || (s.reg & 0x8000))
{
flags[i] = 0;
continue;
@ -537,9 +537,9 @@ bool rcBuildContours(rcCompactHeightfield& chf,
}
}
rcTimeVal boundaryEndTime = rcGetPerformanceTimer();
rcTimeVal traceEndTime = rcGetPerformanceTimer();
rcTimeVal contourStartTime = rcGetPerformanceTimer();
rcTimeVal simplifyStartTime = rcGetPerformanceTimer();
rcIntArray verts(256);
rcIntArray simplified(64);
@ -556,6 +556,9 @@ bool rcBuildContours(rcCompactHeightfield& chf,
flags[i] = 0;
continue;
}
unsigned short reg = chf.spans[i].reg;
if (!reg || (reg & 0x8000))
continue;
verts.resize(0);
simplified.resize(0);
@ -564,7 +567,6 @@ bool rcBuildContours(rcCompactHeightfield& chf,
removeDegenerateSegments(simplified);
// Store region->contour remap info.
unsigned short reg = chf.spans[i].reg;
// Create contour.
if (simplified.size()/4 >= 3)
{
@ -585,7 +587,7 @@ bool rcBuildContours(rcCompactHeightfield& chf,
cont->rverts = new int[cont->nrverts*4];
memcpy(cont->rverts, &verts[0], sizeof(int)*cont->nrverts*4);
cont->cx = cont->cy = cont->cz = 0;
/* cont->cx = cont->cy = cont->cz = 0;
for (int i = 0; i < cont->nverts; ++i)
{
cont->cx += cont->verts[i*4+0];
@ -594,7 +596,7 @@ bool rcBuildContours(rcCompactHeightfield& chf,
}
cont->cx /= cont->nverts;
cont->cy /= cont->nverts;
cont->cz /= cont->nverts;
cont->cz /= cont->nverts;*/
cont->reg = reg;
}
@ -647,19 +649,305 @@ bool rcBuildContours(rcCompactHeightfield& chf,
}
rcTimeVal contourEndTime = rcGetPerformanceTimer();
// Delete vertices.
delete [] flags;
rcTimeVal simplifyEndTime = rcGetPerformanceTimer();
rcTimeVal endTime = rcGetPerformanceTimer();
if (rcGetLog())
// if (rcGetLog())
// {
// rcGetLog()->log(RC_LOG_PROGRESS, "Create contours: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
// 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())
{
rcGetLog()->log(RC_LOG_PROGRESS, "Create contours: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
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);
rcGetBuildTimes()->buildContours += rcGetDeltaTimeUsec(startTime, endTime);
rcGetBuildTimes()->buildContoursTrace += rcGetDeltaTimeUsec(traceStartTime, traceEndTime);
rcGetBuildTimes()->buildContoursSimplify += rcGetDeltaTimeUsec(simplifyStartTime, simplifyEndTime);
}
return true;
}
struct EdgeSegment
{
int i0, i1;
int v0[3], v1[3];
};
static int findEdgeSegments(rcContourSet* cset, int x, int z, EdgeSegment* segs, const int maxSegs)
{
int n = 0;
for (int i = 0; i < cset->nconts; ++i)
{
const rcContour* c = &cset->conts[i];
const int nc = n;
for (int j = 0, k = c->nverts-1; j < c->nverts; k=j++)
{
const int* v0 = &c->verts[k*4];
const int* v1 = &c->verts[j*4];
if ((v0[0] == x && v1[0] == x) || (v0[2] == z && v1[2] == z))
{
if (n && segs[n-1].i1 == k)
{
// Merge with previous
segs[n-1].i1 = j;
}
else
{
// Add new
if (n >= maxSegs)
return n;
segs[n].i0 = k;
segs[n].i1 = j;
n++;
}
}
}
// Check if first and last should be merged.
if (n && n && segs[n-1].v1 == segs[nc].v0)
{
segs[nc].i0 = segs[n-1].i0;
n--;
}
// Copy vertices
for (int j = nc; j < n; ++j)
{
segs[j].v0[0] = c->verts[segs[j].i0*4+0];
segs[j].v0[1] = c->verts[segs[j].i0*4+1];
segs[j].v0[2] = c->verts[segs[j].i0*4+2];
segs[j].v1[0] = c->verts[segs[j].i1*4+0];
segs[j].v1[1] = c->verts[segs[j].i1*4+1];
segs[j].v1[2] = c->verts[segs[j].i1*4+2];
}
}
return n;
}
static bool pointOnEdgeSegment(const int* v0, const int* v1, int x, int z)
{
const int dx = v1[0] - v0[0];
const int dz = v1[2] - v0[2];
if (rcAbs(dx) > rcAbs(dz))
{
const int d = x - v0[0];
if (dx < 0)
return d < 0 && d > dx;
else
return d > 0 && d < dx;
}
else
{
const int d = z - v0[2];
if (dz < 0)
return d < 0 && d > dz;
else
return d > 0 && d < dz;
}
}
static bool insertPoint(rcContour* c, int idx, const int* v)
{
int* newVerts = new int[(c->nverts+1)*4];
if (!newVerts)
{
if (rcGetLog())
rcGetLog()->log(RC_LOG_ERROR, "insertPoint: Out of memory 'newVerts'.");
return false;
}
if (idx > 0)
memcpy(newVerts, c->verts, sizeof(int)*4*idx);
newVerts[idx*4+0] = v[0];
newVerts[idx*4+1] = v[1];
newVerts[idx*4+2] = v[2];
newVerts[idx*4+3] = 0;
if (c->nverts - idx > 0)
memcpy(&newVerts[(idx+1)*4], &c->verts[idx*4], sizeof(int)*4*(c->nverts - idx));
delete [] c->verts;
c->verts = newVerts;
c->nverts++;
return true;
}
inline bool ptsEqual(const int* a, const int* b)
{
return a[0] == b[0] && a[1] == b[1] && a[2] == b[2];
}
static bool conformEdge(rcContourSet* cset, int ex, int ez, const int* v0, const int* v1)
{
for (int i = 0; i < cset->nconts; ++i)
{
rcContour* c = &cset->conts[i];
const int nv = c->nverts;
for (int j = 0; j < nv; ++j)
{
const int* v = &c->verts[j*4];
if (ptsEqual(v, v0))
{
const int jn = (j+1) % nv;
const int* vn = &c->verts[jn*4];
// Check if the segment is edge segment.
if ((v[0] == ex && vn[0] == ex) || (v[2] == ez && vn[2] == ez))
{
if (ptsEqual(vn, v1))
{
// Valid!
return true;
}
else
{
// Add new vertex
if (pointOnEdgeSegment(v, vn, v1[0], v1[2]))
{
if (!insertPoint(c, jn, v1))
return false;
}
return true;
}
}
}
else if (ptsEqual(v, v1))
{
const int jp = (j+nv-1) % nv;
const int* vp = &c->verts[jp*4];
// Check if the segment is edge segment.
if ((v[0] == ex && vp[0] == ex) || (v[2] == ez && vp[2] == ez))
{
if (ptsEqual(vp, v0))
{
// Valid!
return true;
}
else
{
// Add new vertex
if (pointOnEdgeSegment(vp, v, v0[0], v0[2]))
{
if (!insertPoint(c, j, v0))
return false;
}
return true;
}
}
}
}
}
return true;
}
bool rcFixupAdjacentContours(rcContourSet* cseta, rcContourSet* csetb,
int edge, int edgePos)
{
if (!cseta || !csetb)
return true;
rcTimeVal startTime = rcGetPerformanceTimer();
if (edge == 1)
{
// x+1
// Find edge segment
static const int MAX_SEGS = 512; // TODO: Do not hardcode.
EdgeSegment sa[MAX_SEGS], sb[MAX_SEGS];
int nsa = findEdgeSegments(cseta, edgePos, -1, sa, MAX_SEGS);
int nsb = findEdgeSegments(csetb, edgePos, -1, sb, MAX_SEGS);
// Conform set A to set B
for (int i = 0; i < nsb; ++i)
{
const int* v0 = sb[i].v0;
const int* v1 = sb[i].v1;
if (!conformEdge(cseta, edgePos, -1, v1, v0))
{
return false;
}
}
// Conform set B to set A
for (int i = 0; i < nsa; ++i)
{
const int* v0 = sa[i].v0;
const int* v1 = sa[i].v1;
if (!conformEdge(csetb, edgePos, -1, v1, v0))
{
return false;
}
}
}
else if (edge == 2)
{
// y+1
// Find edge segment
static const int MAX_SEGS = 512; // TODO: Do not hardcode.
EdgeSegment sa[MAX_SEGS], sb[MAX_SEGS];
int nsa = findEdgeSegments(cseta, -1, edgePos, sa, MAX_SEGS);
int nsb = findEdgeSegments(csetb, -1, edgePos, sb, MAX_SEGS);
// Conform set A to set B
for (int i = 0; i < nsb; ++i)
{
const int* v0 = sb[i].v0;
const int* v1 = sb[i].v1;
if (!conformEdge(cseta, -1, edgePos, v1, v0))
{
return false;
}
}
// Conform set B to set A
for (int i = 0; i < nsa; ++i)
{
const int* v0 = sa[i].v0;
const int* v1 = sa[i].v1;
if (!conformEdge(csetb, -1, edgePos, v1, v0))
{
return false;
}
}
}
rcTimeVal endTime = rcGetPerformanceTimer();
if (rcGetBuildTimes())
rcGetBuildTimes()->fixupContours += rcGetDeltaTimeUsec(startTime, endTime);
return true;
}
void rcTranslateContours(rcContourSet* cset, int dx, int dy, int dz)
{
if (!cset) return;
for (int i = 0; i < cset->nconts; ++i)
{
rcContour& cont = cset->conts[i];
for (int i = 0; i < cont.nverts; ++i)
{
int* v = &cont.verts[i*4];
v[0] += dx;
v[1] += dy;
v[2] += dz;
}
for (int i = 0; i < cont.nrverts; ++i)
{
int* v = &cont.rverts[i*4];
v[0] += dx;
v[1] += dy;
v[2] += dz;
}
}
}

View File

@ -240,14 +240,14 @@ void rcDebugDrawCompactHeightfieldSolid(const rcCompactHeightfield& chf)
{
for (int x = 0; x < chf.width; ++x)
{
const float fx = chf.minx + x*cs;
const float fz = chf.minz + y*cs;
const float fx = chf.bmin[0] + x*cs;
const float fz = chf.bmin[2] + y*cs;
const rcCompactCell& c = chf.cells[x+y*chf.width];
for (unsigned i = c.index, ni = c.index+c.count; i < ni; ++i)
{
const rcCompactSpan& s = chf.spans[i];
const float fy = chf.miny + (s.y+1)*ch;
const float fy = chf.bmin[1] + (s.y+1)*ch;
glVertex3f(fx, fy, fz);
glVertex3f(fx, fy, fz+cs);
glVertex3f(fx+cs, fy, fz+cs);
@ -270,8 +270,8 @@ void rcDebugDrawCompactHeightfieldRegions(const rcCompactHeightfield& chf)
{
for (int x = 0; x < chf.width; ++x)
{
const float fx = chf.minx + x*cs;
const float fz = chf.minz + y*cs;
const float fx = chf.bmin[0] + x*cs;
const float fz = chf.bmin[2] + y*cs;
const rcCompactCell& c = chf.cells[x+y*chf.width];
for (unsigned i = c.index, ni = c.index+c.count; i < ni; ++i)
@ -284,7 +284,7 @@ void rcDebugDrawCompactHeightfieldRegions(const rcCompactHeightfield& chf)
}
else
glColor4ub(0,0,0,128);
const float fy = chf.miny + (s.y+1)*ch;
const float fy = chf.bmin[1] + (s.y+1)*ch;
glVertex3f(fx, fy, fz);
glVertex3f(fx, fy, fz+cs);
glVertex3f(fx+cs, fy, fz+cs);
@ -310,14 +310,14 @@ void rcDebugDrawCompactHeightfieldDistance(const rcCompactHeightfield& chf)
{
for (int x = 0; x < chf.width; ++x)
{
const float fx = chf.minx + x*cs;
const float fz = chf.minz + y*cs;
const float fx = chf.bmin[0] + x*cs;
const float fz = chf.bmin[2] + y*cs;
const rcCompactCell& c = chf.cells[x+y*chf.width];
for (unsigned i = c.index, ni = c.index+c.count; i < ni; ++i)
{
const rcCompactSpan& s = chf.spans[i];
const float fy = chf.miny + (s.y+1)*ch;
const float fy = chf.bmin[1] + (s.y+1)*ch;
float cd = (float)s.dist * dscale;
glColor3f(cd, cd, cd);
glVertex3f(fx, fy, fz);
@ -363,6 +363,7 @@ void rcDebugDrawContours(const rcContourSet& cset, const float* orig, float cs,
const rcContour& c = cset.conts[i];
intToCol(c.reg, col);
glColor4fv(col);
glBegin(GL_LINE_LOOP);
for (int j = 0; j < c.nverts; ++j)
{
@ -373,6 +374,7 @@ void rcDebugDrawContours(const rcContourSet& cset, const float* orig, float cs,
glVertex3f(fx,fy,fz);
}
glEnd();
glColor4ub(0,0,0,128);
glBegin(GL_POINTS);
for (int j = 0; j < c.nverts; ++j)
@ -389,9 +391,12 @@ void rcDebugDrawContours(const rcContourSet& cset, const float* orig, float cs,
glPointSize(1.0f);
}
void rcDebugDrawPolyMesh(const struct rcPolyMesh& mesh, const float* orig, float cs, float ch)
void rcDebugDrawPolyMesh(const struct rcPolyMesh& mesh)
{
const int nvp = mesh.nvp;
const float cs = mesh.cs;
const float ch = mesh.ch;
const float* orig = mesh.bmin;
glColor4ub(0,196,255,64);
glBegin(GL_TRIANGLES);
for (int i = 0; i < mesh.npolys; ++i)

View File

@ -81,8 +81,10 @@ void rcFilterWalkableBorderSpans(const int walkableHeight,
}
rcTimeVal endTime = rcGetPerformanceTimer();
if (rcGetLog())
rcGetLog()->log(RC_LOG_PROGRESS, "Filter border: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
// if (rcGetLog())
// rcGetLog()->log(RC_LOG_PROGRESS, "Filter border: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
if (rcGetBuildTimes())
rcGetBuildTimes()->filterBorder += rcGetDeltaTimeUsec(startTime, endTime);
}
void rcFilterWalkableLowHeightSpans(int walkableHeight,
@ -112,10 +114,13 @@ void rcFilterWalkableLowHeightSpans(int walkableHeight,
rcTimeVal endTime = rcGetPerformanceTimer();
if (rcGetLog())
rcGetLog()->log(RC_LOG_PROGRESS, "Filter walkable: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
// if (rcGetLog())
// rcGetLog()->log(RC_LOG_PROGRESS, "Filter walkable: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
if (rcGetBuildTimes())
rcGetBuildTimes()->filterWalkable += rcGetDeltaTimeUsec(startTime, endTime);
}
struct rcReachableSeed
{
inline void set(int ix, int iy, rcSpan* is)
@ -225,8 +230,10 @@ bool rcMarkReachableSpans(const int walkableHeight,
rcTimeVal endTime = rcGetPerformanceTimer();
if (rcGetLog())
rcGetLog()->log(RC_LOG_PROGRESS, "Mark reachable: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
// if (rcGetLog())
// rcGetLog()->log(RC_LOG_PROGRESS, "Mark reachable: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
if (rcGetBuildTimes())
rcGetBuildTimes()->filterMarkReachable += rcGetDeltaTimeUsec(startTime, endTime);
return true;
}

View File

@ -21,6 +21,7 @@
#include <stdarg.h>
static rcLog* g_log = 0;
static rcBuildTimes* g_btimes = 0;
rcLog::rcLog() :
m_messageCount(0),
@ -64,3 +65,13 @@ rcLog* rcGetLog()
{
return g_log;
}
void rcSetBuildTimes(rcBuildTimes* btimes)
{
g_btimes = btimes;
}
rcBuildTimes* rcGetBuildTimes()
{
return g_btimes;
}

View File

@ -474,9 +474,17 @@ static void mergePolys(unsigned short* pa, unsigned short* pb,
memcpy(pa, tmp, sizeof(unsigned short)*nvp);
}
bool rcBuildPolyMesh(rcContourSet& cset, rcPolyMesh& mesh, const int nvp)
bool rcBuildPolyMesh(rcContourSet& cset,
const float* bmin, const float* bmax,
const float cs, const float ch, int nvp,
rcPolyMesh& mesh)
{
rcTimeVal startTime = rcGetPerformanceTimer();
vcopy(mesh.bmin, bmin);
vcopy(mesh.bmax, bmax);
mesh.cs = cs;
mesh.ch = ch;
int maxVertices = 0;
int maxTris = 0;
@ -692,8 +700,10 @@ bool rcBuildPolyMesh(rcContourSet& cset, rcPolyMesh& mesh, const int nvp)
rcTimeVal endTime = rcGetPerformanceTimer();
if (rcGetLog())
rcGetLog()->log(RC_LOG_ERROR, "Build polymesh: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
// if (rcGetLog())
// rcGetLog()->log(RC_LOG_PROGRESS, "Build polymesh: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
if (rcGetBuildTimes())
rcGetBuildTimes()->buildPolymesh += rcGetDeltaTimeUsec(startTime, endTime);
return true;
}

View File

@ -43,13 +43,12 @@ inline bool overlapInterval(unsigned short amin, unsigned short amax,
static rcSpan* allocSpan(rcHeightfield& hf)
{
static const int SPANS_PER_POOL = 2048;
// If running out of memory, allocate new page and update the freelist.
if (!hf.freelist || !hf.freelist->next)
{
// Create new page.
// Allocate memory for the new pool.
const int size = (sizeof(rcSpanPool)-sizeof(rcSpan)) + sizeof(rcSpan)*SPANS_PER_POOL;
const int size = (sizeof(rcSpanPool)-sizeof(rcSpan)) + sizeof(rcSpan)*RC_SPANS_PER_POOL;
rcSpanPool* pool = reinterpret_cast<rcSpanPool*>(new unsigned char[size]);
if (!pool) return 0;
pool->next = 0;
@ -59,7 +58,7 @@ static rcSpan* allocSpan(rcHeightfield& hf)
// Add new items to the free list.
rcSpan* freelist = hf.freelist;
rcSpan* head = &pool->items[0];
rcSpan* it = &pool->items[SPANS_PER_POOL];
rcSpan* it = &pool->items[RC_SPANS_PER_POOL];
do
{
--it;
@ -290,6 +289,9 @@ void rcRasterizeTriangles(const float* bmin, const float* bmax, const float cs,
rcTimeVal endTime = rcGetPerformanceTimer();
if (rcGetLog())
rcGetLog()->log(RC_LOG_PROGRESS, "Rasterize: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
// if (rcGetLog())
// rcGetLog()->log(RC_LOG_PROGRESS, "Rasterize: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
if (rcGetBuildTimes())
rcGetBuildTimes()->rasterizeTriangles += rcGetDeltaTimeUsec(startTime, endTime);
}

View File

@ -379,7 +379,7 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
const int ax = x + rcGetDirOffsetX(dir);
const int ay = y + rcGetDirOffsetY(dir);
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
if (src[ai*2])
if (src[ai*2] > 0 && (src[ai*2] & 0x8000) == 0)
{
if ((int)src[ai*2+1]+2 < (int)d2)
{
@ -420,10 +420,11 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
struct rcRegion
{
inline rcRegion() : count(0), id(0) {}
inline rcRegion() : count(0), id(0), remap(false) {}
int count;
unsigned short id;
bool remap;
rcIntArray connections;
rcIntArray floors;
};
@ -741,7 +742,7 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize,
for (int i = 0; i < nreg; ++i)
{
rcRegion& reg = regions[i];
if (reg.id == 0)
if (reg.id == 0 || (reg.id & 0x8000))
continue;
if (reg.count == 0)
continue;
@ -766,7 +767,7 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize,
for (int i = 0; i < nreg; ++i)
{
rcRegion& reg = regions[i];
if (reg.id == 0)
if (reg.id == 0 || (reg.id & 0x8000))
continue;
if (reg.count == 0)
continue;
@ -782,8 +783,9 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize,
unsigned short mergeId = reg.id;
for (int j = 0; j < reg.connections.size(); ++j)
{
if (reg.connections[j] & 0x8000) continue;
rcRegion& mreg = regions[reg.connections[j]];
if (mreg.id == 0) continue;
if (mreg.id == 0 || (mreg.id & 0x8000)) continue;
if (mreg.count < smallest &&
canMergeWithRegion(reg, mreg.id) &&
canMergeWithRegion(mreg, reg.id))
@ -804,7 +806,7 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize,
// Fixup regions pointing to current region.
for (int j = 0; j < nreg; ++j)
{
if (regions[j].id == 0) continue;
if (regions[j].id == 0 || (regions[j].id & 0x8000)) continue;
// If another region was already merged into current region
// change the nid of the previous region too.
if (regions[j].id == oldId)
@ -823,28 +825,36 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize,
// Compress region Ids.
for (int i = 0; i < nreg; ++i)
{
if (regions[i].id == 0) continue;
regions[i].id |= 0x8000;
regions[i].remap = false;
if (regions[i].id == 0) continue; // Skip nil regions.
if (regions[i].id & 0x8000) continue; // Skip external regions.
regions[i].remap = true;
}
unsigned short regIdGen = 0;
for (int i = 0; i < nreg; ++i)
{
if ((regions[i].id & 0x8000) == 0)
if (!regions[i].remap)
continue;
unsigned short oldId = regions[i].id;
unsigned short newId = ++regIdGen;
for (int j = i; j < nreg; ++j)
{
if (regions[j].id == oldId)
{
regions[j].id = newId;
regions[j].remap = false;
}
}
}
maxRegionId = regIdGen;
// Remap regions.
for (int i = 0; i < chf.spanCount; ++i)
src[i*2] = regions[src[i*2]].id;
{
if ((src[i*2] & 0x8000) == 0)
src[i*2] = regions[src[i*2]].id;
}
delete [] regions;
@ -902,18 +912,44 @@ bool rcBuildDistanceField(rcCompactHeightfield& chf)
rcTimeVal endTime = rcGetPerformanceTimer();
if (rcGetLog())
/* if (rcGetLog())
{
rcGetLog()->log(RC_LOG_PROGRESS, "Build distance field: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
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;
}
static void paintRectRegion(int minx, int maxx, int miny, int maxy,
unsigned short regId, unsigned short minLevel,
rcCompactHeightfield& chf, unsigned short* src)
{
const int w = chf.width;
for (int y = miny; y < maxy; ++y)
{
for (int x = minx; x < maxx; ++x)
{
const rcCompactCell& c = chf.cells[x+y*w];
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
{
if (chf.spans[i].dist >= minLevel)
src[i*2] = regId;
}
}
}
}
bool rcBuildRegions(rcCompactHeightfield& chf,
int walkableRadius, int minRegionSize, int mergeRegionSize)
int walkableRadius, int borderSize,
int minRegionSize, int mergeRegionSize)
{
rcTimeVal startTime = rcGetPerformanceTimer();
@ -952,9 +988,13 @@ bool rcBuildRegions(rcCompactHeightfield& chf,
unsigned short minLevel = (unsigned short)walkableRadius * 2;
const int expandIters = 4 + walkableRadius * 2;
paintRectRegion(0, borderSize, 0, h, regionId|0x8000, minLevel, chf, src); regionId++;
paintRectRegion(w-borderSize, w, 0, h, regionId|0x8000, minLevel, chf, src); regionId++;
paintRectRegion(0, w, 0, borderSize, regionId|0x8000, minLevel, chf, src); regionId++;
paintRectRegion(0, w, h-borderSize, h, regionId|0x8000, minLevel, chf, src); regionId++;
rcTimeVal expTime = 0;
rcTimeVal marknewTime = 0;
rcTimeVal floodTime = 0;
while (level > minLevel)
@ -1017,16 +1057,24 @@ bool rcBuildRegions(rcCompactHeightfield& chf,
rcTimeVal endTime = rcGetPerformanceTimer();
if (rcGetLog())
/* if (rcGetLog())
{
rcGetLog()->log(RC_LOG_PROGRESS, "Build regions: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f);
rcGetLog()->log(RC_LOG_PROGRESS, " - reg: %.3f ms", rcGetDeltaTimeUsec(regStartTime, regEndTime)/1000.0f);
rcGetLog()->log(RC_LOG_PROGRESS, " - exp: %.3f ms", rcGetDeltaTimeUsec(0, expTime)/1000.0f);
rcGetLog()->log(RC_LOG_PROGRESS, " - new: %.3f ms", rcGetDeltaTimeUsec(0, marknewTime)/1000.0f);
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;
}

File diff suppressed because it is too large Load Diff

View File

@ -200,8 +200,8 @@
<array/>
<key>PerspectiveWidths</key>
<array>
<integer>810</integer>
<integer>810</integer>
<integer>1280</integer>
<integer>1280</integer>
</array>
<key>Perspectives</key>
<array>
@ -230,8 +230,6 @@
<key>Layout</key>
<array>
<dict>
<key>BecomeActive</key>
<true/>
<key>ContentConfiguration</key>
<dict>
<key>PBXBottomSmartGroupGIDs</key>
@ -257,7 +255,7 @@
<dict>
<key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
<array>
<real>185</real>
<real>228</real>
</array>
<key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
<array>
@ -270,23 +268,23 @@
<array>
<string>29B97314FDCFA39411CA2CEA</string>
<string>080E96DDFE201D6D7F000001</string>
<string>6BDD9E030F91110C00904EEF</string>
<string>6B137C7D0F7FCBE800459200</string>
<string>29B97315FDCFA39411CA2CEA</string>
<string>29B97317FDCFA39411CA2CEA</string>
<string>29B97323FDCFA39411CA2CEA</string>
<string>1058C7A0FEA54F0111CA2CBB</string>
<string>1058C7A2FEA54F0111CA2CBB</string>
<string>1C37FBAC04509CD000000102</string>
<string>1C77FABC04509CD000000102</string>
</array>
<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
<array>
<array>
<integer>2</integer>
<integer>27</integer>
<integer>1</integer>
<integer>0</integer>
</array>
</array>
<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
<string>{{0, 0}, {185, 595}}</string>
<string>{{0, 17}, {228, 660}}</string>
</dict>
<key>PBXTopSmartGroupGIDs</key>
<array/>
@ -296,30 +294,32 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {202, 613}}</string>
<string>{{0, 0}, {245, 678}}</string>
<key>GroupTreeTableConfiguration</key>
<array>
<string>MainColumn</string>
<real>185</real>
<real>228</real>
</array>
<key>RubberWindowFrame</key>
<string>55 112 1071 654 0 0 1280 778 </string>
<string>0 59 1280 719 0 0 1280 778 </string>
</dict>
<key>Module</key>
<string>PBXSmartGroupTreeModule</string>
<key>Proportion</key>
<string>202pt</string>
<string>245pt</string>
</dict>
<dict>
<key>Dock</key>
<array>
<dict>
<key>BecomeActive</key>
<true/>
<key>ContentConfiguration</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>6B8632A30F78115100E2684A</string>
<key>PBXProjectModuleLabel</key>
<string>imgui.h</string>
<string>demo.cpp</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict>
<key>Split0</key>
@ -327,14 +327,173 @@
<key>PBXProjectModuleGUID</key>
<string>6B8632A40F78115100E2684A</string>
<key>PBXProjectModuleLabel</key>
<string>imgui.h</string>
<string>demo.cpp</string>
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>6BB788140FC045A2003C24DB</string>
<key>history</key>
<array>
<string>6B8633370F7813A600E2684A</string>
<string>6B8DB3890F9798DE007FA9E1</string>
<string>6B8DB38A0F9798DE007FA9E1</string>
<string>6BB87E0B0F9DE8A300E33F12</string>
<string>6B77074C0FBD597500D21BAE</string>
<string>6B77074D0FBD597500D21BAE</string>
<string>6B7707710FBD5DB300D21BAE</string>
<string>6B7707AF0FBD66CF00D21BAE</string>
<string>6B7707EF0FBD90F100D21BAE</string>
<string>6B7707F00FBD90F100D21BAE</string>
<string>6B7707F30FBD90F100D21BAE</string>
<string>6B7708F20FBDA96300D21BAE</string>
<string>6BB787660FC03EAD003C24DB</string>
<string>6BB787670FC03EAD003C24DB</string>
<string>6BB787680FC03EAD003C24DB</string>
<string>6BB787690FC03EAD003C24DB</string>
<string>6BB7876A0FC03EAD003C24DB</string>
<string>6BB7876B0FC03EAD003C24DB</string>
<string>6BB7876C0FC03EAD003C24DB</string>
<string>6BB7876D0FC03EAD003C24DB</string>
<string>6BB7876E0FC03EAD003C24DB</string>
<string>6BB7876F0FC03EAD003C24DB</string>
<string>6BB787700FC03EAD003C24DB</string>
<string>6BB787710FC03EAD003C24DB</string>
<string>6BB787720FC03EAD003C24DB</string>
<string>6BB787730FC03EAD003C24DB</string>
<string>6BB788130FC045A2003C24DB</string>
</array>
<key>prevStack</key>
<array>
<string>6B86333B0F7813A600E2684A</string>
<string>6B1E02680F924A8500CC0038</string>
<string>6B1E02750F924A8500CC0038</string>
<string>6B1E028F0F924D5A00CC0038</string>
<string>6B1E029B0F924D8B00CC0038</string>
<string>6B1E02AE0F92530C00CC0038</string>
<string>6B1E02BB0F92547D00CC0038</string>
<string>6B1E02FC0F92563500CC0038</string>
<string>6B1E032E0F925D9100CC0038</string>
<string>6B8DB2D70F93A7A5007FA9E1</string>
<string>6B8DB38F0F9798DE007FA9E1</string>
<string>6B8DB3900F9798DE007FA9E1</string>
<string>6BB87E0E0F9DE8A300E33F12</string>
<string>6B458EA80FB4540500044EA9</string>
<string>6B77072C0FBD540400D21BAE</string>
<string>6B7707B90FBD66CF00D21BAE</string>
<string>6B7707F70FBD90F100D21BAE</string>
<string>6B7707F90FBD90F100D21BAE</string>
<string>6B7707FC0FBD90F100D21BAE</string>
<string>6B7708010FBD90F100D21BAE</string>
<string>6B7708F70FBDA96300D21BAE</string>
<string>6BB787750FC03EAD003C24DB</string>
<string>6BB787760FC03EAD003C24DB</string>
<string>6BB787770FC03EAD003C24DB</string>
<string>6BB787780FC03EAD003C24DB</string>
<string>6BB787790FC03EAD003C24DB</string>
<string>6BB7877A0FC03EAD003C24DB</string>
<string>6BB7877B0FC03EAD003C24DB</string>
<string>6BB7877C0FC03EAD003C24DB</string>
<string>6BB7877D0FC03EAD003C24DB</string>
<string>6BB7877E0FC03EAD003C24DB</string>
<string>6BB7877F0FC03EAD003C24DB</string>
<string>6BB787800FC03EAD003C24DB</string>
<string>6BB787810FC03EAD003C24DB</string>
<string>6BB787820FC03EAD003C24DB</string>
<string>6BB787830FC03EAD003C24DB</string>
<string>6BB787840FC03EAD003C24DB</string>
<string>6BB787850FC03EAD003C24DB</string>
<string>6BB787860FC03EAD003C24DB</string>
<string>6BB787870FC03EAD003C24DB</string>
<string>6BB787880FC03EAD003C24DB</string>
<string>6BB787890FC03EAD003C24DB</string>
<string>6BB7878A0FC03EAD003C24DB</string>
<string>6BB7878B0FC03EAD003C24DB</string>
<string>6BB7878C0FC03EAD003C24DB</string>
<string>6BB7878D0FC03EAD003C24DB</string>
<string>6BB7878E0FC03EAD003C24DB</string>
<string>6BB7878F0FC03EAD003C24DB</string>
<string>6BB787900FC03EAD003C24DB</string>
<string>6BB787910FC03EAD003C24DB</string>
<string>6BB787920FC03EAD003C24DB</string>
<string>6BB787930FC03EAD003C24DB</string>
<string>6BB787940FC03EAD003C24DB</string>
<string>6BB787950FC03EAD003C24DB</string>
<string>6BB787960FC03EAD003C24DB</string>
<string>6BB787970FC03EAD003C24DB</string>
<string>6BB787980FC03EAD003C24DB</string>
<string>6BB787990FC03EAD003C24DB</string>
<string>6BB7879A0FC03EAD003C24DB</string>
<string>6BB7879B0FC03EAD003C24DB</string>
<string>6BB7879C0FC03EAD003C24DB</string>
<string>6BB7879D0FC03EAD003C24DB</string>
<string>6BB7879E0FC03EAD003C24DB</string>
<string>6BB7879F0FC03EAD003C24DB</string>
<string>6BB787A00FC03EAD003C24DB</string>
<string>6BB787A10FC03EAD003C24DB</string>
<string>6BB787A20FC03EAD003C24DB</string>
<string>6BB787A30FC03EAD003C24DB</string>
<string>6BB787A40FC03EAD003C24DB</string>
<string>6BB787A50FC03EAD003C24DB</string>
<string>6BB787A60FC03EAD003C24DB</string>
<string>6BB787A70FC03EAD003C24DB</string>
<string>6BB787A80FC03EAD003C24DB</string>
<string>6BB787A90FC03EAD003C24DB</string>
<string>6BB787AA0FC03EAD003C24DB</string>
<string>6BB787AB0FC03EAD003C24DB</string>
<string>6BB787AC0FC03EAD003C24DB</string>
<string>6BB787AD0FC03EAD003C24DB</string>
<string>6BB787AE0FC03EAD003C24DB</string>
<string>6BB787AF0FC03EAD003C24DB</string>
<string>6BB787B00FC03EAD003C24DB</string>
<string>6BB787B10FC03EAD003C24DB</string>
<string>6BB787B20FC03EAD003C24DB</string>
<string>6BB787B30FC03EAD003C24DB</string>
<string>6BB787B40FC03EAD003C24DB</string>
<string>6BB787B50FC03EAD003C24DB</string>
<string>6BB787B60FC03EAD003C24DB</string>
<string>6BB787B70FC03EAD003C24DB</string>
<string>6BB787B80FC03EAD003C24DB</string>
<string>6BB787B90FC03EAD003C24DB</string>
<string>6BB787BA0FC03EAD003C24DB</string>
<string>6BB787BB0FC03EAD003C24DB</string>
<string>6BB787BC0FC03EAD003C24DB</string>
<string>6BB787BD0FC03EAD003C24DB</string>
<string>6BB787BE0FC03EAD003C24DB</string>
<string>6BB787BF0FC03EAD003C24DB</string>
<string>6BB787C00FC03EAD003C24DB</string>
<string>6BB787C10FC03EAD003C24DB</string>
<string>6BB787C20FC03EAD003C24DB</string>
<string>6BB787C30FC03EAD003C24DB</string>
<string>6BB787C40FC03EAD003C24DB</string>
<string>6BB787C50FC03EAD003C24DB</string>
<string>6BB787C60FC03EAD003C24DB</string>
<string>6BB787C70FC03EAD003C24DB</string>
<string>6BB787C80FC03EAD003C24DB</string>
<string>6BB787C90FC03EAD003C24DB</string>
<string>6BB787CA0FC03EAD003C24DB</string>
<string>6BB787CB0FC03EAD003C24DB</string>
<string>6BB787CC0FC03EAD003C24DB</string>
<string>6BB787CD0FC03EAD003C24DB</string>
<string>6BB787CE0FC03EAD003C24DB</string>
<string>6BB787CF0FC03EAD003C24DB</string>
<string>6BB787D00FC03EAD003C24DB</string>
<string>6BB787D10FC03EAD003C24DB</string>
<string>6BB787D20FC03EAD003C24DB</string>
<string>6BB787D30FC03EAD003C24DB</string>
<string>6BB787D40FC03EAD003C24DB</string>
<string>6BB787D50FC03EAD003C24DB</string>
<string>6BB787D60FC03EAD003C24DB</string>
<string>6BB787D70FC03EAD003C24DB</string>
<string>6BB787D80FC03EAD003C24DB</string>
<string>6BB787D90FC03EAD003C24DB</string>
<string>6BB787DA0FC03EAD003C24DB</string>
<string>6BB787DB0FC03EAD003C24DB</string>
<string>6BB787DC0FC03EAD003C24DB</string>
<string>6BB787DD0FC03EAD003C24DB</string>
<string>6BB787DE0FC03EAD003C24DB</string>
<string>6BB787DF0FC03EAD003C24DB</string>
<string>6BB787E00FC03EAD003C24DB</string>
<string>6BB787E10FC03EAD003C24DB</string>
</array>
</dict>
<key>SplitCount</key>
@ -348,18 +507,18 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {864, 405}}</string>
<string>{{0, 0}, {1030, 585}}</string>
<key>RubberWindowFrame</key>
<string>55 112 1071 654 0 0 1280 778 </string>
<string>0 59 1280 719 0 0 1280 778 </string>
</dict>
<key>Module</key>
<string>PBXNavigatorGroup</string>
<key>Proportion</key>
<string>405pt</string>
<string>585pt</string>
</dict>
<dict>
<key>Proportion</key>
<string>203pt</string>
<string>88pt</string>
<key>Tabs</key>
<array>
<dict>
@ -373,9 +532,7 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 27}, {864, 176}}</string>
<key>RubberWindowFrame</key>
<string>55 112 1071 654 0 0 1280 778 </string>
<string>{{10, 27}, {1030, 100}}</string>
</dict>
<key>Module</key>
<string>XCDetailModule</string>
@ -391,7 +548,7 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 31}, {603, 297}}</string>
<string>{{10, 27}, {1030, 225}}</string>
</dict>
<key>Module</key>
<string>PBXProjectFindModule</string>
@ -429,7 +586,9 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 27}, {864, 176}}</string>
<string>{{10, 27}, {1030, 61}}</string>
<key>RubberWindowFrame</key>
<string>0 59 1280 719 0 0 1280 778 </string>
</dict>
<key>Module</key>
<string>PBXBuildResultsModule</string>
@ -438,7 +597,7 @@
</dict>
</array>
<key>Proportion</key>
<string>864pt</string>
<string>1030pt</string>
</dict>
</array>
<key>Name</key>
@ -457,11 +616,11 @@
</array>
<key>TableOfContents</key>
<array>
<string>6BDD9E120F91114E00904EEF</string>
<string>6BB787E50FC03EB7003C24DB</string>
<string>1CA23ED40692098700951B8B</string>
<string>6BDD9E130F91114E00904EEF</string>
<string>6BB787E60FC03EB7003C24DB</string>
<string>6B8632A30F78115100E2684A</string>
<string>6BDD9E140F91114E00904EEF</string>
<string>6BB787E70FC03EB7003C24DB</string>
<string>1CA23EDF0692099D00951B8B</string>
<string>1CA23EE00692099D00951B8B</string>
<string>1CA23EE10692099D00951B8B</string>
@ -510,12 +669,12 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {810, 132}}</string>
<string>{{0, 0}, {1280, 199}}</string>
</dict>
<key>Module</key>
<string>PBXDebugCLIModule</string>
<key>Proportion</key>
<string>132pt</string>
<string>199pt</string>
</dict>
<dict>
<key>ContentConfiguration</key>
@ -534,8 +693,8 @@
<string>yes</string>
<key>sizes</key>
<array>
<string>{{0, 0}, {395, 150}}</string>
<string>{{395, 0}, {415, 150}}</string>
<string>{{0, 0}, {637, 130}}</string>
<string>{{637, 0}, {643, 130}}</string>
</array>
</dict>
<key>VerticalSplitView</key>
@ -550,8 +709,8 @@
<string>yes</string>
<key>sizes</key>
<array>
<string>{{0, 0}, {810, 150}}</string>
<string>{{0, 150}, {810, 159}}</string>
<string>{{0, 0}, {1280, 130}}</string>
<string>{{0, 130}, {1280, 344}}</string>
</array>
</dict>
</dict>
@ -571,7 +730,7 @@
<key>DebugSTDIOWindowFrame</key>
<string>{{200, 200}, {500, 300}}</string>
<key>Frame</key>
<string>{{0, 137}, {810, 309}}</string>
<string>{{0, 204}, {1280, 474}}</string>
<key>PBXDebugSessionStackFrameViewKey</key>
<dict>
<key>DebugVariablesTableConfiguration</key>
@ -581,16 +740,16 @@
<string>Value</string>
<real>85</real>
<string>Summary</string>
<real>185</real>
<real>413</real>
</array>
<key>Frame</key>
<string>{{395, 0}, {415, 150}}</string>
<string>{{637, 0}, {643, 130}}</string>
</dict>
</dict>
<key>Module</key>
<string>PBXDebugSessionModule</string>
<key>Proportion</key>
<string>309pt</string>
<string>474pt</string>
</dict>
</array>
<key>Name</key>
@ -608,14 +767,14 @@
</array>
<key>TableOfContents</key>
<array>
<string>6BDD9E150F91114E00904EEF</string>
<string>6BB787E80FC03EB7003C24DB</string>
<string>1CCC7628064C1048000F2A68</string>
<string>1CCC7629064C1048000F2A68</string>
<string>6BDD9E160F91114E00904EEF</string>
<string>6BDD9E170F91114E00904EEF</string>
<string>6BDD9E180F91114E00904EEF</string>
<string>6BDD9E190F91114E00904EEF</string>
<string>6BDD9E1A0F91114E00904EEF</string>
<string>6BB787E90FC03EB7003C24DB</string>
<string>6BB787EA0FC03EB7003C24DB</string>
<string>6BB787EB0FC03EB7003C24DB</string>
<string>6BB787EC0FC03EB7003C24DB</string>
<string>6BB786F40FC0091C003C24DB</string>
</array>
<key>ToolbarConfiguration</key>
<string>xcode.toolbar.config.debugV3</string>
@ -648,7 +807,7 @@
<string>/Users/memon/Code/recastnavigation/RecastDemo/Build/Xcode/Recast.xcodeproj</string>
</array>
<key>WindowString</key>
<string>55 112 1071 654 0 0 1280 778 </string>
<string>0 59 1280 719 0 0 1280 778 </string>
<key>WindowToolsV3</key>
<array>
<dict>

View File

@ -24,6 +24,7 @@
6B137C930F7FCC1100459200 /* RecastTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B137C8A0F7FCC1100459200 /* RecastTimer.cpp */; };
6B8632DA0F78122C00E2684A /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B8632D90F78122C00E2684A /* SDL.framework */; };
6B8632DC0F78123E00E2684A /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B8632DB0F78123E00E2684A /* OpenGL.framework */; };
6BB788170FC0472B003C24DB /* ChunkyTriMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6BB788160FC0472B003C24DB /* ChunkyTriMesh.cpp */; };
6BDD9E0A0F91113800904EEF /* DetourDebugDraw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6BDD9E070F91113800904EEF /* DetourDebugDraw.cpp */; };
6BDD9E0B0F91113800904EEF /* DetourStatNavMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6BDD9E080F91113800904EEF /* DetourStatNavMesh.cpp */; };
6BDD9E0C0F91113800904EEF /* DetourStatNavMeshBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6BDD9E090F91113800904EEF /* DetourStatNavMeshBuilder.cpp */; };
@ -63,6 +64,8 @@
6B137C8A0F7FCC1100459200 /* RecastTimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastTimer.cpp; path = ../../../Recast/Source/RecastTimer.cpp; sourceTree = SOURCE_ROOT; };
6B8632D90F78122C00E2684A /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = Library/Frameworks/SDL.framework; sourceTree = SDKROOT; };
6B8632DB0F78123E00E2684A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
6BB788160FC0472B003C24DB /* ChunkyTriMesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ChunkyTriMesh.cpp; path = ../../Source/ChunkyTriMesh.cpp; sourceTree = SOURCE_ROOT; };
6BB788180FC04753003C24DB /* ChunkyTriMesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ChunkyTriMesh.h; path = ../../Include/ChunkyTriMesh.h; sourceTree = SOURCE_ROOT; };
6BDD9E040F91112200904EEF /* DetourDebugDraw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DetourDebugDraw.h; path = ../../../Detour/Include/DetourDebugDraw.h; sourceTree = SOURCE_ROOT; };
6BDD9E050F91112200904EEF /* DetourStatNavMesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DetourStatNavMesh.h; path = ../../../Detour/Include/DetourStatNavMesh.h; sourceTree = SOURCE_ROOT; };
6BDD9E060F91112200904EEF /* DetourStatNavMeshBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DetourStatNavMeshBuilder.h; path = ../../../Detour/Include/DetourStatNavMeshBuilder.h; sourceTree = SOURCE_ROOT; };
@ -93,13 +96,15 @@
6BDD9E030F91110C00904EEF /* Detour */,
6B137C7D0F7FCBE800459200 /* Recast */,
6B137C790F7FCBE400459200 /* glfont.h */,
6B137C7A0F7FCBE400459200 /* imgui.h */,
6B137C7B0F7FCBE400459200 /* MeshLoaderObj.h */,
6B137C7C0F7FCBE400459200 /* SDLMain.h */,
6B137C6A0F7FCBBB00459200 /* demo.cpp */,
6B137C6B0F7FCBBB00459200 /* glfont.cpp */,
6B137C7A0F7FCBE400459200 /* imgui.h */,
6B137C6C0F7FCBBB00459200 /* imgui.cpp */,
6B137C7B0F7FCBE400459200 /* MeshLoaderObj.h */,
6B137C6D0F7FCBBB00459200 /* MeshLoaderObj.cpp */,
6BB788160FC0472B003C24DB /* ChunkyTriMesh.cpp */,
6BB788180FC04753003C24DB /* ChunkyTriMesh.h */,
6B137C6A0F7FCBBB00459200 /* demo.cpp */,
6B137C7C0F7FCBE400459200 /* SDLMain.h */,
6B137C6E0F7FCBBB00459200 /* SDLMain.m */,
);
name = Classes;
@ -277,6 +282,7 @@
6BDD9E0A0F91113800904EEF /* DetourDebugDraw.cpp in Sources */,
6BDD9E0B0F91113800904EEF /* DetourStatNavMesh.cpp in Sources */,
6BDD9E0C0F91113800904EEF /* DetourStatNavMeshBuilder.cpp in Sources */,
6BB788170FC0472B003C24DB /* ChunkyTriMesh.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -0,0 +1,49 @@
//
// Copyright (c) 2009 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 CHUNKYTRIMESH_H
#define CHUNKYTRIMESH_H
struct rcChunkyTriMeshNode
{
float bmin[2], bmax[2];
int i, n;
};
struct rcChunkyTriMesh
{
inline rcChunkyTriMesh() : nodes(0), tris(0) {};
inline ~rcChunkyTriMesh() { delete [] nodes; delete [] tris; }
rcChunkyTriMeshNode* nodes;
int nnodes;
int* tris;
int ntris;
int maxTrisPerChunk;
};
// Creates partitioned triangle mesh (AABB tree),
// where each node contains at max trisPerChunk triangles.
bool rcCreateChunkyTriMesh(const float* verts, const int* tris, int ntris,
int trisPerChunk, rcChunkyTriMesh* cm);
// Returns the chunk indices which touch the input rectable.
int rcGetChunksInRect(const rcChunkyTriMesh* cm, float bmin[2], float bmax[2], int* ids, const int maxIds);
#endif // CHUNKYTRIMESH_H

View File

@ -32,12 +32,13 @@ public:
inline const int* getTris() const { return m_tris; }
inline int getVertCount() const { return m_vertCount; }
inline int getTriCount() const { return m_triCount; }
private:
void addVertex(float x, float y, float z, int& cap);
void addTriangle(int a, int b, int c, int& cap);
float* m_verts;
int* m_tris;
float* m_normals;

View File

@ -0,0 +1,251 @@
//
// Copyright (c) 2009 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 "ChunkyTriMesh.h"
#include <stdio.h>
#include <stdlib.h>
struct BoundsItem
{
float bmin[2];
float bmax[2];
int i;
};
static int compareItemX(const void* va, const void* vb)
{
const BoundsItem* a = (const BoundsItem*)va;
const BoundsItem* b = (const BoundsItem*)vb;
if (a->bmin[0] < b->bmin[0])
return -1;
if (a->bmin[0] > b->bmin[0])
return 1;
return 0;
}
static int compareItemY(const void* va, const void* vb)
{
const BoundsItem* a = (const BoundsItem*)va;
const BoundsItem* b = (const BoundsItem*)vb;
if (a->bmin[1] < b->bmin[1])
return -1;
if (a->bmin[1] > b->bmin[1])
return 1;
return 0;
}
static void calcExtends(BoundsItem* items, int nitems, int imin, int imax,
float* bmin, float* bmax)
{
bmin[0] = items[imin].bmin[0];
bmin[1] = items[imin].bmin[1];
bmax[0] = items[imin].bmax[0];
bmax[1] = items[imin].bmax[1];
for (int i = imin+1; i < imax; ++i)
{
const BoundsItem& it = items[i];
if (it.bmin[0] < bmin[0]) bmin[0] = it.bmin[0];
if (it.bmin[1] < bmin[1]) bmin[1] = it.bmin[1];
if (it.bmax[0] > bmax[0]) bmax[0] = it.bmax[0];
if (it.bmax[1] > bmax[1]) bmax[1] = it.bmax[1];
}
}
inline int longestAxis(float x, float y)
{
int axis = 0;
unsigned short maxVal = x;
if (y > maxVal)
{
axis = 1;
maxVal = y;
}
return axis;
}
static void subdivide(BoundsItem* items, int nitems, int imin, int imax, int trisPerChunk,
int& curNode, rcChunkyTriMeshNode* nodes, const int maxNodes,
int& curTri, int* outTris, const int* inTris)
{
int inum = imax - imin;
int icur = curNode;
if (curNode > maxNodes)
return;
rcChunkyTriMeshNode& node = nodes[curNode++];
if (inum <= trisPerChunk)
{
// Leaf
calcExtends(items, nitems, imin, imax, node.bmin, node.bmax);
// Copy triangles.
node.i = curTri;
node.n = inum;
for (int i = imin; i < imax; ++i)
{
const int* src = &inTris[items[i].i*3];
int* dst = &outTris[curTri*3];
curTri++;
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
}
}
else
{
// Split
calcExtends(items, nitems, imin, imax, node.bmin, node.bmax);
int axis = longestAxis(node.bmax[0] - node.bmin[0],
node.bmax[1] - node.bmin[1]);
if (axis == 0)
{
// Sort along x-axis
qsort(items+imin, inum, sizeof(BoundsItem), compareItemX);
}
else if (axis == 1)
{
// Sort along y-axis
qsort(items+imin, inum, sizeof(BoundsItem), compareItemY);
}
int isplit = imin+inum/2;
// Left
subdivide(items, nitems, imin, isplit, trisPerChunk, curNode, nodes, maxNodes, curTri, outTris, inTris);
// Right
subdivide(items, nitems, isplit, imax, trisPerChunk, curNode, nodes, maxNodes, curTri, outTris, inTris);
int iescape = curNode - icur;
// Negative index means escape.
node.i = -iescape;
}
}
bool rcCreateChunkyTriMesh(const float* verts, const int* tris, int ntris,
int trisPerChunk, rcChunkyTriMesh* cm)
{
int nchunks = (ntris + trisPerChunk-1) / trisPerChunk;
cm->nodes = new rcChunkyTriMeshNode[nchunks*4];
if (!cm->nodes)
return false;
cm->tris = new int[ntris*3];
if (!cm->tris)
return false;
cm->ntris = ntris;
// Build tree
BoundsItem* items = new BoundsItem[ntris];
if (!items)
return false;
for (int i = 0; i < ntris; i++)
{
const int* t = &tris[i*3];
BoundsItem& it = items[i];
it.i = i;
// Calc triangle XZ bounds.
it.bmin[0] = it.bmax[0] = verts[t[0]*3+0];
it.bmin[1] = it.bmax[1] = verts[t[0]*3+2];
for (int j = 1; j < 3; ++j)
{
const float* v = &verts[t[j]*3];
if (v[0] < it.bmin[0]) it.bmin[0] = v[0];
if (v[2] < it.bmin[1]) it.bmin[1] = v[2];
if (v[0] > it.bmax[0]) it.bmax[0] = v[0];
if (v[2] > it.bmax[1]) it.bmax[1] = v[2];
}
}
int curTri = 0;
int curNode = 0;
subdivide(items, ntris, 0, ntris, trisPerChunk, curNode, cm->nodes, nchunks*4, curTri, cm->tris, tris);
delete [] items;
cm->nnodes = curNode;
// Calc max tris per node.
cm->maxTrisPerChunk = 0;
for (int i = 0; i < cm->nnodes; ++i)
{
rcChunkyTriMeshNode& node = cm->nodes[i];
const bool isLeaf = node.i >= 0;
if (!isLeaf) continue;
if (node.n > cm->maxTrisPerChunk)
cm->maxTrisPerChunk = node.n;
}
return true;
}
inline bool checkOverlapRect(const float amin[2], const float amax[2],
const float bmin[2], const float bmax[2])
{
bool overlap = true;
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
return overlap;
}
int rcGetChunksInRect(const rcChunkyTriMesh* cm,
float bmin[2], float bmax[2],
int* ids, const int maxIds)
{
// Traverse tree
int i = 0;
int n = 0;
while (i < cm->nnodes)
{
const rcChunkyTriMeshNode* node = &cm->nodes[i];
const bool overlap = checkOverlapRect(bmin, bmax, node->bmin, node->bmax);
const bool isLeafNode = node->i >= 0;
if (isLeafNode && overlap)
{
if (n < maxIds)
{
ids[n] = i;
n++;
}
}
if (overlap || isLeafNode)
i++;
else
{
const int escapeIndex = -node->i;
i += escapeIndex;
}
}
return n;
}

File diff suppressed because it is too large Load Diff