Merge branch 'master' of https://github.com/memononen/recastnavigation
This commit is contained in:
commit
86328ced48
@ -63,6 +63,8 @@ struct dtTileCacheParams
|
||||
|
||||
struct dtTileCacheMeshProcess
|
||||
{
|
||||
virtual ~dtTileCacheMeshProcess() { }
|
||||
|
||||
virtual void process(struct dtNavMeshCreateParams* params,
|
||||
unsigned char* polyAreas, unsigned short* polyFlags) = 0;
|
||||
};
|
||||
|
@ -78,6 +78,8 @@ struct dtTileCachePolyMesh
|
||||
|
||||
struct dtTileCacheAlloc
|
||||
{
|
||||
virtual ~dtTileCacheAlloc() { }
|
||||
|
||||
virtual void reset()
|
||||
{
|
||||
}
|
||||
@ -95,6 +97,8 @@ struct dtTileCacheAlloc
|
||||
|
||||
struct dtTileCacheCompressor
|
||||
{
|
||||
virtual ~dtTileCacheCompressor() { }
|
||||
|
||||
virtual int maxCompressedSize(const int bufferSize) = 0;
|
||||
virtual dtStatus compress(const unsigned char* buffer, const int bufferSize,
|
||||
unsigned char* compressed, const int maxCompressedSize, int* compressedSize) = 0;
|
||||
|
@ -37,7 +37,7 @@ static int getCornerHeight(int x, int y, int i, int dir,
|
||||
unsigned int regs[4] = {0,0,0,0};
|
||||
|
||||
// Combine region and area codes in order to prevent
|
||||
// border vertices which are in between two areas to be removed.
|
||||
// border vertices which are in between two areas to be removed.
|
||||
regs[0] = chf.spans[i].reg | (chf.areas[i] << 16);
|
||||
|
||||
if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
|
||||
@ -188,27 +188,6 @@ static float distancePtSeg(const int x, const int z,
|
||||
const int px, const int pz,
|
||||
const int qx, const int qz)
|
||||
{
|
||||
/* float pqx = (float)(qx - px);
|
||||
float pqy = (float)(qy - py);
|
||||
float pqz = (float)(qz - pz);
|
||||
float dx = (float)(x - px);
|
||||
float dy = (float)(y - py);
|
||||
float dz = (float)(z - pz);
|
||||
float d = pqx*pqx + pqy*pqy + pqz*pqz;
|
||||
float t = pqx*dx + pqy*dy + pqz*dz;
|
||||
if (d > 0)
|
||||
t /= d;
|
||||
if (t < 0)
|
||||
t = 0;
|
||||
else if (t > 1)
|
||||
t = 1;
|
||||
|
||||
dx = px + t*pqx - x;
|
||||
dy = py + t*pqy - y;
|
||||
dz = pz + t*pqz - z;
|
||||
|
||||
return dx*dx + dy*dy + dz*dz;*/
|
||||
|
||||
float pqx = (float)(qx - px);
|
||||
float pqz = (float)(qz - pz);
|
||||
float dx = (float)(x - px);
|
||||
@ -258,13 +237,13 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
|
||||
simplified.push(points[i*4+2]);
|
||||
simplified.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (simplified.size() == 0)
|
||||
{
|
||||
// If there is no connections at all,
|
||||
// create some initial points for the simplification process.
|
||||
// create some initial points for the simplification process.
|
||||
// Find lower-left and upper-right vertices of the contour.
|
||||
int llx = points[0];
|
||||
int lly = points[1];
|
||||
@ -315,7 +294,7 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
|
||||
int ax = simplified[i*4+0];
|
||||
int az = simplified[i*4+2];
|
||||
int ai = simplified[i*4+3];
|
||||
|
||||
|
||||
int bx = simplified[ii*4+0];
|
||||
int bz = simplified[ii*4+2];
|
||||
int bi = simplified[ii*4+3];
|
||||
@ -324,7 +303,7 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
|
||||
float maxd = 0;
|
||||
int maxi = -1;
|
||||
int ci, cinc, endi;
|
||||
|
||||
|
||||
// Traverse the segment in lexilogical order so that the
|
||||
// max deviation is calculated similarly when traversing
|
||||
// opposite segments.
|
||||
@ -400,11 +379,11 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
|
||||
const int bx = simplified[ii*4+0];
|
||||
const int bz = simplified[ii*4+2];
|
||||
const int bi = simplified[ii*4+3];
|
||||
|
||||
|
||||
// Find maximum deviation from the segment.
|
||||
int maxi = -1;
|
||||
int ci = (ai+1) % pn;
|
||||
|
||||
|
||||
// Tessellate only outer edges or edges between areas.
|
||||
bool tess = false;
|
||||
// Wall edges.
|
||||
@ -576,7 +555,7 @@ static bool intersectSegCountour(const int* d0, const int* d1, int i, int n, con
|
||||
const int* p1 = &verts[k1 * 4];
|
||||
if (vequal(d0, p0) || vequal(d1, p0) || vequal(d0, p1) || vequal(d1, p1))
|
||||
continue;
|
||||
|
||||
|
||||
if (intersect(d0, d1, p0, p1))
|
||||
return true;
|
||||
}
|
||||
@ -630,9 +609,9 @@ static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib)
|
||||
int* verts = (int*)rcAlloc(sizeof(int)*maxVerts*4, RC_ALLOC_PERM);
|
||||
if (!verts)
|
||||
return false;
|
||||
|
||||
|
||||
int nv = 0;
|
||||
|
||||
|
||||
// Copy contour A.
|
||||
for (int i = 0; i <= ca.nverts; ++i)
|
||||
{
|
||||
@ -660,7 +639,7 @@ static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib)
|
||||
rcFree(ca.verts);
|
||||
ca.verts = verts;
|
||||
ca.nverts = nv;
|
||||
|
||||
|
||||
rcFree(cb.verts);
|
||||
cb.verts = 0;
|
||||
cb.nverts = 0;
|
||||
@ -747,7 +726,7 @@ static void mergeRegionHoles(rcContext* ctx, rcContourRegion& region)
|
||||
findLeftMostVertex(region.holes[i].contour, ®ion.holes[i].minx, ®ion.holes[i].minz, ®ion.holes[i].leftmost);
|
||||
|
||||
qsort(region.holes, region.nholes, sizeof(rcContourHole), compareHoles);
|
||||
|
||||
|
||||
int maxVerts = region.outline->nverts;
|
||||
for (int i = 0; i < region.nholes; i++)
|
||||
maxVerts += region.holes[i].contour->nverts;
|
||||
@ -758,9 +737,9 @@ static void mergeRegionHoles(rcContext* ctx, rcContourRegion& region)
|
||||
ctx->log(RC_LOG_WARNING, "mergeRegionHoles: Failed to allocated diags %d.", maxVerts);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
rcContour* outline = region.outline;
|
||||
|
||||
|
||||
// Merge holes into the outline one by one.
|
||||
for (int i = 0; i < region.nholes; i++)
|
||||
{
|
||||
@ -793,7 +772,7 @@ static void mergeRegionHoles(rcContext* ctx, rcContourRegion& region)
|
||||
}
|
||||
// Sort potential diagonals by distance, we want to make the connection as short as possible.
|
||||
qsort(diags, ndiags, sizeof(rcPotentialDiagonal), compareDiagDist);
|
||||
|
||||
|
||||
// Find a diagonal that is not intersecting the outline not the remaining holes.
|
||||
index = -1;
|
||||
for (int j = 0; j < ndiags; j++)
|
||||
@ -834,13 +813,13 @@ static void mergeRegionHoles(rcContext* ctx, rcContourRegion& region)
|
||||
/// The raw contours will match the region outlines exactly. The @p maxError and @p maxEdgeLen
|
||||
/// parameters control how closely the simplified contours will match the raw contours.
|
||||
///
|
||||
/// Simplified contours are generated such that the vertices for portals between areas match up.
|
||||
/// Simplified contours are generated such that the vertices for portals between areas match up.
|
||||
/// (They are considered mandatory vertices.)
|
||||
///
|
||||
/// Setting @p maxEdgeLength to zero will disabled the edge length feature.
|
||||
///
|
||||
///
|
||||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||
///
|
||||
///
|
||||
/// @see rcAllocContourSet, rcCompactHeightfield, rcContourSet, rcConfig
|
||||
bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
const float maxError, const int maxEdgeLen,
|
||||
@ -943,17 +922,17 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
|
||||
verts.resize(0);
|
||||
simplified.resize(0);
|
||||
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
|
||||
walkContour(x, y, i, chf, flags, verts);
|
||||
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
|
||||
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
|
||||
simplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags);
|
||||
removeDegenerateSegments(simplified);
|
||||
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
|
||||
|
||||
|
||||
|
||||
// Store region->contour remap info.
|
||||
// Create contour.
|
||||
if (simplified.size()/4 >= 3)
|
||||
@ -974,10 +953,10 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
}
|
||||
rcFree(cset.conts);
|
||||
cset.conts = newConts;
|
||||
|
||||
|
||||
ctx->log(RC_LOG_WARNING, "rcBuildContours: Expanding max contours from %d to %d.", oldMax, maxContours);
|
||||
}
|
||||
|
||||
|
||||
rcContour* cont = &cset.conts[cset.nconts++];
|
||||
|
||||
cont->nverts = simplified.size()/4;
|
||||
@ -1024,7 +1003,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Merge holes if needed.
|
||||
if (cset.nconts > 0)
|
||||
{
|
||||
@ -1057,7 +1036,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
return false;
|
||||
}
|
||||
memset(regions, 0, sizeof(rcContourRegion)*nregions);
|
||||
|
||||
|
||||
rcScopedDelete<rcContourHole> holes = (rcContourHole*)rcAlloc(sizeof(rcContourHole)*cset.nconts, RC_ALLOC_TEMP);
|
||||
if (!holes)
|
||||
{
|
||||
@ -1065,7 +1044,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
return false;
|
||||
}
|
||||
memset(holes, 0, sizeof(rcContourHole)*cset.nconts);
|
||||
|
||||
|
||||
for (int i = 0; i < cset.nconts; ++i)
|
||||
{
|
||||
rcContour& cont = cset.conts[i];
|
||||
@ -1102,8 +1081,20 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
|
||||
// Finally merge each regions holes into the outline.
|
||||
for (int i = 0; i < nregions; i++)
|
||||
{
|
||||
if (regions[i].nholes > 0)
|
||||
mergeRegionHoles(ctx, regions[i]);
|
||||
rcContourRegion& reg = regions[i];
|
||||
if (!reg.nholes) continue;
|
||||
|
||||
if (reg.outline)
|
||||
{
|
||||
mergeRegionHoles(ctx, reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The region does not have an outline.
|
||||
// This can happen if the contour becaomes selfoverlapping because of
|
||||
// too aggressive simplification settings.
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildContours: Bad outline for region %d, contour simplification is likely too aggressive.", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1537,7 +1537,7 @@ bool rcCopyPolyMesh(rcContext* ctx, const rcPolyMesh& src, rcPolyMesh& dst)
|
||||
ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.flags' (%d).", src.npolys);
|
||||
return false;
|
||||
}
|
||||
memcpy(dst.flags, src.flags, sizeof(unsigned char)*src.npolys);
|
||||
memcpy(dst.flags, src.flags, sizeof(unsigned short)*src.npolys);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ inline float vdist2(const float* p, const float* q)
|
||||
}
|
||||
|
||||
inline float vcross2(const float* p1, const float* p2, const float* p3)
|
||||
{
|
||||
{
|
||||
const float u1 = p2[0] - p1[0];
|
||||
const float v1 = p2[2] - p1[2];
|
||||
const float u2 = p3[0] - p1[0];
|
||||
@ -68,21 +68,27 @@ static bool circumCircle(const float* p1, const float* p2, const float* p3,
|
||||
float* c, float& r)
|
||||
{
|
||||
static const float EPS = 1e-6f;
|
||||
// Calculate the circle relative to p1, to avoid some precision issues.
|
||||
const float v1[3] = {0,0,0};
|
||||
float v2[3], v3[3];
|
||||
rcVsub(v2, p2,p1);
|
||||
rcVsub(v3, p3,p1);
|
||||
|
||||
const float cp = vcross2(p1, p2, p3);
|
||||
const float cp = vcross2(v1, v2, v3);
|
||||
if (fabsf(cp) > EPS)
|
||||
{
|
||||
const float p1Sq = vdot2(p1,p1);
|
||||
const float p2Sq = vdot2(p2,p2);
|
||||
const float p3Sq = vdot2(p3,p3);
|
||||
c[0] = (p1Sq*(p2[2]-p3[2]) + p2Sq*(p3[2]-p1[2]) + p3Sq*(p1[2]-p2[2])) / (2*cp);
|
||||
c[2] = (p1Sq*(p3[0]-p2[0]) + p2Sq*(p1[0]-p3[0]) + p3Sq*(p2[0]-p1[0])) / (2*cp);
|
||||
r = vdist2(c, p1);
|
||||
const float v1Sq = vdot2(v1,v1);
|
||||
const float v2Sq = vdot2(v2,v2);
|
||||
const float v3Sq = vdot2(v3,v3);
|
||||
c[0] = (v1Sq*(v2[2]-v3[2]) + v2Sq*(v3[2]-v1[2]) + v3Sq*(v1[2]-v2[2])) / (2*cp);
|
||||
c[1] = 0;
|
||||
c[2] = (v1Sq*(v3[0]-v2[0]) + v2Sq*(v1[0]-v3[0]) + v3Sq*(v2[0]-v1[0])) / (2*cp);
|
||||
r = vdist2(c, v1);
|
||||
rcVadd(c, c, p1);
|
||||
return true;
|
||||
}
|
||||
|
||||
c[0] = p1[0];
|
||||
c[2] = p1[2];
|
||||
|
||||
rcVcopy(c, p1);
|
||||
r = 0;
|
||||
return false;
|
||||
}
|
||||
@ -93,7 +99,7 @@ static float distPtTri(const float* p, const float* a, const float* b, const flo
|
||||
rcVsub(v0, c,a);
|
||||
rcVsub(v1, b,a);
|
||||
rcVsub(v2, p,a);
|
||||
|
||||
|
||||
const float dot00 = vdot2(v0, v0);
|
||||
const float dot01 = vdot2(v0, v1);
|
||||
const float dot02 = vdot2(v0, v2);
|
||||
@ -178,7 +184,7 @@ static float distToTriMesh(const float* p, const float* verts, const int /*nvert
|
||||
|
||||
static float distToPoly(int nvert, const float* verts, const float* p)
|
||||
{
|
||||
|
||||
|
||||
float dmin = FLT_MAX;
|
||||
int i, j, c = 0;
|
||||
for (i = 0, j = nvert-1; i < nvert; j = i++)
|
||||
@ -216,22 +222,13 @@ static unsigned short getHeight(const float fx, const float fy, const float fz,
|
||||
if (nx < 0 || nz < 0 || nx >= hp.width || nz >= hp.height) continue;
|
||||
const unsigned short nh = hp.data[nx+nz*hp.width];
|
||||
if (nh == RC_UNSET_HEIGHT) continue;
|
||||
|
||||
|
||||
const float d = fabsf(nh*ch - fy);
|
||||
if (d < dmin)
|
||||
{
|
||||
h = nh;
|
||||
dmin = d;
|
||||
}
|
||||
|
||||
/* const float dx = (nx+0.5f)*cs - fx;
|
||||
const float dz = (nz+0.5f)*cs - fz;
|
||||
const float d = dx*dx+dz*dz;
|
||||
if (d < dmin)
|
||||
{
|
||||
h = nh;
|
||||
dmin = d;
|
||||
} */
|
||||
}
|
||||
}
|
||||
return h;
|
||||
@ -263,7 +260,7 @@ static int addEdge(rcContext* ctx, int* edges, int& nedges, const int maxEdges,
|
||||
return UNDEF;
|
||||
}
|
||||
|
||||
// Add edge if not already in the triangulation.
|
||||
// Add edge if not already in the triangulation.
|
||||
int e = findEdge(edges, nedges, s, t);
|
||||
if (e == UNDEF)
|
||||
{
|
||||
@ -286,7 +283,7 @@ static void updateLeftFace(int* e, int s, int t, int f)
|
||||
e[2] = f;
|
||||
else if (e[1] == s && e[0] == t && e[3] == UNDEF)
|
||||
e[3] = f;
|
||||
}
|
||||
}
|
||||
|
||||
static int overlapSegSeg2d(const float* a, const float* b, const float* c, const float* d)
|
||||
{
|
||||
@ -298,7 +295,7 @@ static int overlapSegSeg2d(const float* a, const float* b, const float* c, const
|
||||
float a4 = a3 + a2 - a1;
|
||||
if (a3 * a4 < 0.0f)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -320,7 +317,7 @@ static bool overlapEdges(const float* pts, const int* edges, int nedges, int s1,
|
||||
static void completeFacet(rcContext* ctx, const float* pts, int npts, int* edges, int& nedges, const int maxEdges, int& nfaces, int e)
|
||||
{
|
||||
static const float EPS = 1e-5f;
|
||||
|
||||
|
||||
int* edge = &edges[e*4];
|
||||
|
||||
// Cache s and t.
|
||||
@ -337,11 +334,11 @@ static void completeFacet(rcContext* ctx, const float* pts, int npts, int* edges
|
||||
}
|
||||
else
|
||||
{
|
||||
// Edge already completed.
|
||||
// Edge already completed.
|
||||
return;
|
||||
}
|
||||
|
||||
// Find best point on left of edge.
|
||||
// Find best point on left of edge.
|
||||
int pt = npts;
|
||||
float c[3] = {0,0,0};
|
||||
float r = -1;
|
||||
@ -385,20 +382,20 @@ static void completeFacet(rcContext* ctx, const float* pts, int npts, int* edges
|
||||
}
|
||||
}
|
||||
|
||||
// Add new triangle or update edge info if s-t is on hull.
|
||||
// Add new triangle or update edge info if s-t is on hull.
|
||||
if (pt < npts)
|
||||
{
|
||||
// Update face information of edge being completed.
|
||||
// Update face information of edge being completed.
|
||||
updateLeftFace(&edges[e*4], s, t, 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, pt, s);
|
||||
if (e == UNDEF)
|
||||
addEdge(ctx, edges, nedges, maxEdges, pt, s, nfaces, UNDEF);
|
||||
else
|
||||
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);
|
||||
if (e == UNDEF)
|
||||
addEdge(ctx, edges, nedges, maxEdges, t, pt, nfaces, UNDEF);
|
||||
@ -434,7 +431,7 @@ static void delaunayHull(rcContext* ctx, const int npts, const float* pts,
|
||||
completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge);
|
||||
currentEdge++;
|
||||
}
|
||||
|
||||
|
||||
// Create tris
|
||||
tris.resize(nfaces*4);
|
||||
for (int i = 0; i < nfaces*4; ++i)
|
||||
@ -523,16 +520,18 @@ inline int prev(int i, int n)
|
||||
static void triangulateHull(const int nverts, const float* verts, const int nhull, const int* hull, rcIntArray& tris)
|
||||
{
|
||||
int start = 0, left = 1, right = nhull-1;
|
||||
|
||||
// Start from shortest ear.
|
||||
float dmin = FLT_MAX;
|
||||
|
||||
// Start from an ear with shortest perimeter.
|
||||
// This tends to favor well formed triangles as starting point.
|
||||
float dmin = 0;
|
||||
for (int i = 0; i < nhull; i++)
|
||||
{
|
||||
int pi = prev(i, nhull);
|
||||
int ni = next(i, nhull);
|
||||
const float* pv = &verts[hull[pi]*3];
|
||||
const float* cv = &verts[hull[i]*3];
|
||||
const float* nv = &verts[hull[ni]*3];
|
||||
const float d = vdistSq2(pv, nv);
|
||||
const float d = vdist2(pv,cv) + vdist2(cv,nv) + vdist2(nv,pv);
|
||||
if (d < dmin)
|
||||
{
|
||||
start = i;
|
||||
@ -547,22 +546,24 @@ static void triangulateHull(const int nverts, const float* verts, const int nhul
|
||||
tris.push(hull[left]);
|
||||
tris.push(hull[right]);
|
||||
tris.push(0);
|
||||
|
||||
// Triangulate the polygon by adding the shortest diagonal
|
||||
// by moving left or right.
|
||||
|
||||
// Triangulate the polygon by moving left or right,
|
||||
// depending on which triangle has shorter perimeter.
|
||||
// This heuristic was chose emprically, since it seems
|
||||
// handle tesselated straight edges well.
|
||||
while (next(left, nhull) != right)
|
||||
{
|
||||
// Check to see if se should advance left or right.
|
||||
int nleft = next(left, nhull);
|
||||
int nright = prev(right, nhull);
|
||||
|
||||
|
||||
const float* cvleft = &verts[hull[left]*3];
|
||||
const float* nvleft = &verts[hull[nleft]*3];
|
||||
const float* cvright = &verts[hull[right]*3];
|
||||
const float* nvright = &verts[hull[nright]*3];
|
||||
|
||||
const float dleft = vdistSq2(nvleft, cvright);
|
||||
const float dright = vdistSq2(cvleft, nvright);
|
||||
const float dleft = vdist2(cvleft, nvleft) + vdist2(nvleft, cvright);
|
||||
const float dright = vdist2(cvright, nvright) + vdist2(cvleft, nvright);
|
||||
|
||||
if (dleft < dright)
|
||||
{
|
||||
tris.push(hull[left]);
|
||||
@ -605,19 +606,19 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||
float edge[(MAX_VERTS_PER_EDGE+1)*3];
|
||||
int hull[MAX_VERTS];
|
||||
int nhull = 0;
|
||||
|
||||
|
||||
nverts = 0;
|
||||
|
||||
|
||||
for (int i = 0; i < nin; ++i)
|
||||
rcVcopy(&verts[i*3], &in[i*3]);
|
||||
nverts = nin;
|
||||
|
||||
|
||||
edges.resize(0);
|
||||
tris.resize(0);
|
||||
|
||||
|
||||
const float cs = chf.cs;
|
||||
const float ics = 1.0f/cs;
|
||||
|
||||
|
||||
// Calculate minimum extents of the polygon based on input data.
|
||||
float minExtent = polyMinExtent(verts, nverts);
|
||||
|
||||
@ -726,27 +727,27 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If the polygon minimum extent is small (sliver or small triangle), do not try to add internal points.
|
||||
if (minExtent < sampleDist*2)
|
||||
{
|
||||
triangulateHull(nverts, verts, nhull, hull, tris);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Tessellate the base mesh.
|
||||
// We're using the triangulateHull instead of delaunayHull as it tends to
|
||||
// create a bit better triangulation for long thing triangles when there
|
||||
// are no internal points.
|
||||
triangulateHull(nverts, verts, nhull, hull, tris);
|
||||
|
||||
|
||||
if (tris.size() == 0)
|
||||
{
|
||||
// Could not triangulate the poly, make sure there is some valid data there.
|
||||
ctx->log(RC_LOG_WARNING, "buildPolyDetail: Could not triangulate polygon (%d verts).", nverts);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (sampleDist > 0)
|
||||
{
|
||||
// Create sample locations in a grid.
|
||||
@ -779,7 +780,7 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||
samples.push(0); // Not added
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add the samples starting from the one that has the most
|
||||
// error. The procedure stops when all samples are added
|
||||
// or when the max error is within treshold.
|
||||
@ -788,7 +789,7 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||
{
|
||||
if (nverts >= MAX_VERTS)
|
||||
break;
|
||||
|
||||
|
||||
// Find sample with most error.
|
||||
float bestpt[3] = {0,0,0};
|
||||
float bestd = 0;
|
||||
@ -826,24 +827,24 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
||||
edges.resize(0);
|
||||
tris.resize(0);
|
||||
delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const int ntris = tris.size()/4;
|
||||
if (ntris > MAX_TRIS)
|
||||
{
|
||||
tris.resize(MAX_TRIS*4);
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Shrinking triangle count from %d to max %d.", ntris, MAX_TRIS);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void getHeightDataSeedsFromVertices(const rcCompactHeightfield& chf,
|
||||
const unsigned short* poly, const int npoly,
|
||||
const unsigned short* verts, const int bs,
|
||||
rcHeightPatch& hp, rcIntArray& stack)
|
||||
const unsigned short* poly, const int npoly,
|
||||
const unsigned short* verts, const int bs,
|
||||
rcHeightPatch& hp, rcIntArray& stack)
|
||||
{
|
||||
// Floodfill the heightfield to get 2D height data,
|
||||
// starting at vertex locations as seeds.
|
||||
@ -947,7 +948,7 @@ static void getHeightDataSeedsFromVertices(const rcCompactHeightfield& chf,
|
||||
continue;
|
||||
|
||||
const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir);
|
||||
|
||||
|
||||
int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width;
|
||||
hp.data[idx] = 1;
|
||||
|
||||
@ -956,9 +957,9 @@ static void getHeightDataSeedsFromVertices(const rcCompactHeightfield& chf,
|
||||
stack.push(ai);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height);
|
||||
|
||||
|
||||
// Mark start locations.
|
||||
for (int i = 0; i < stack.size(); i += 3)
|
||||
{
|
||||
@ -968,8 +969,8 @@ static void getHeightDataSeedsFromVertices(const rcCompactHeightfield& chf,
|
||||
int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width;
|
||||
const rcCompactSpan& cs = chf.spans[ci];
|
||||
hp.data[idx] = cs.y;
|
||||
|
||||
// getHeightData seeds are given in coordinates with borders
|
||||
|
||||
// getHeightData seeds are given in coordinates with borders
|
||||
stack[i+0] += bs;
|
||||
stack[i+1] += bs;
|
||||
}
|
||||
@ -986,12 +987,12 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
||||
{
|
||||
// Note: Reads to the compact heightfield are offset by border size (bs)
|
||||
// since border size offset is already removed from the polymesh vertices.
|
||||
|
||||
|
||||
stack.resize(0);
|
||||
memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height);
|
||||
|
||||
bool empty = true;
|
||||
|
||||
|
||||
// Copy the height from the same region, and mark region borders
|
||||
// as seed points to fill the rest.
|
||||
for (int hy = 0; hy < hp.height; hy++)
|
||||
@ -1009,7 +1010,7 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
||||
// Store height
|
||||
hp.data[hx + hy*hp.width] = s.y;
|
||||
empty = false;
|
||||
|
||||
|
||||
// If any of the neighbours is not in same region,
|
||||
// add the current location as flood fill start
|
||||
bool border = false;
|
||||
@ -1038,8 +1039,8 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if the polygon does not contian any points from the current region (rare, but happens)
|
||||
// then use the cells closest to the polygon vertices as seeds to fill the height field
|
||||
if (empty)
|
||||
@ -1061,7 +1062,7 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
||||
memmove(&stack[0], &stack[RETRACT_SIZE*3], sizeof(int)*(stack.size()-RETRACT_SIZE*3));
|
||||
stack.resize(stack.size()-RETRACT_SIZE*3);
|
||||
}
|
||||
|
||||
|
||||
const rcCompactSpan& cs = chf.spans[ci];
|
||||
for (int dir = 0; dir < 4; ++dir)
|
||||
{
|
||||
@ -1080,9 +1081,9 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
||||
|
||||
const int ai = (int)chf.cells[ax + ay*chf.width].index + rcGetCon(cs, dir);
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
|
||||
|
||||
hp.data[hx + hy*hp.width] = as.y;
|
||||
|
||||
|
||||
stack.push(ax);
|
||||
stack.push(ay);
|
||||
stack.push(ai);
|
||||
@ -1097,7 +1098,7 @@ static unsigned char getEdgeFlags(const float* va, const float* vb,
|
||||
static const float thrSqr = rcSqr(0.001f);
|
||||
for (int i = 0, j = npoly-1; i < npoly; j=i++)
|
||||
{
|
||||
if (distancePtSeg2d(va, &vpoly[j*3], &vpoly[i*3]) < thrSqr &&
|
||||
if (distancePtSeg2d(va, &vpoly[j*3], &vpoly[i*3]) < thrSqr &&
|
||||
distancePtSeg2d(vb, &vpoly[j*3], &vpoly[i*3]) < thrSqr)
|
||||
return 1;
|
||||
}
|
||||
@ -1126,7 +1127,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_BUILD_POLYMESHDETAIL);
|
||||
|
||||
|
||||
if (mesh.nverts == 0 || mesh.npolys == 0)
|
||||
return true;
|
||||
|
||||
@ -1205,10 +1206,10 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.meshes' (%d).", dmesh.nmeshes*4);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int vcap = nPolyVerts+nPolyVerts/2;
|
||||
int tcap = vcap*2;
|
||||
|
||||
|
||||
dmesh.nverts = 0;
|
||||
dmesh.verts = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM);
|
||||
if (!dmesh.verts)
|
||||
@ -1217,7 +1218,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||
return false;
|
||||
}
|
||||
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)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", tcap*4);
|
||||
@ -1256,7 +1257,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Move detail verts to world space.
|
||||
for (int j = 0; j < nverts; ++j)
|
||||
{
|
||||
@ -1271,21 +1272,21 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||
poly[j*3+1] += orig[1];
|
||||
poly[j*3+2] += orig[2];
|
||||
}
|
||||
|
||||
|
||||
// Store detail submesh.
|
||||
const int ntris = tris.size()/4;
|
||||
|
||||
|
||||
dmesh.meshes[i*4+0] = (unsigned int)dmesh.nverts;
|
||||
dmesh.meshes[i*4+1] = (unsigned int)nverts;
|
||||
dmesh.meshes[i*4+2] = (unsigned int)dmesh.ntris;
|
||||
dmesh.meshes[i*4+3] = (unsigned int)ntris;
|
||||
dmesh.meshes[i*4+3] = (unsigned int)ntris;
|
||||
|
||||
// Store vertices, allocate more memory if necessary.
|
||||
if (dmesh.nverts+nverts > vcap)
|
||||
{
|
||||
while (dmesh.nverts+nverts > vcap)
|
||||
vcap += 256;
|
||||
|
||||
|
||||
float* newv = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM);
|
||||
if (!newv)
|
||||
{
|
||||
@ -1331,9 +1332,9 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
||||
dmesh.ntris++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ctx->stopTimer(RC_TIMER_BUILD_POLYMESHDETAIL);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1343,11 +1344,11 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
|
||||
rcAssert(ctx);
|
||||
|
||||
ctx->startTimer(RC_TIMER_MERGE_POLYMESHDETAIL);
|
||||
|
||||
|
||||
int maxVerts = 0;
|
||||
int maxTris = 0;
|
||||
int maxMeshes = 0;
|
||||
|
||||
|
||||
for (int i = 0; i < nmeshes; ++i)
|
||||
{
|
||||
if (!meshes[i]) continue;
|
||||
@ -1355,7 +1356,7 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
|
||||
maxTris += meshes[i]->ntris;
|
||||
maxMeshes += meshes[i]->nmeshes;
|
||||
}
|
||||
|
||||
|
||||
mesh.nmeshes = 0;
|
||||
mesh.meshes = (unsigned int*)rcAlloc(sizeof(unsigned int)*maxMeshes*4, RC_ALLOC_PERM);
|
||||
if (!mesh.meshes)
|
||||
@ -1363,7 +1364,7 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'pmdtl.meshes' (%d).", maxMeshes*4);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
mesh.ntris = 0;
|
||||
mesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris*4, RC_ALLOC_PERM);
|
||||
if (!mesh.tris)
|
||||
@ -1371,7 +1372,7 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", maxTris*4);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
mesh.nverts = 0;
|
||||
mesh.verts = (float*)rcAlloc(sizeof(float)*maxVerts*3, RC_ALLOC_PERM);
|
||||
if (!mesh.verts)
|
||||
@ -1395,7 +1396,7 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
|
||||
dst[3] = src[3];
|
||||
mesh.nmeshes++;
|
||||
}
|
||||
|
||||
|
||||
for (int k = 0; k < dm->nverts; ++k)
|
||||
{
|
||||
rcVcopy(&mesh.verts[mesh.nverts*3], &dm->verts[k*3]);
|
||||
@ -1410,7 +1411,7 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
|
||||
mesh.ntris++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ctx->stopTimer(RC_TIMER_MERGE_POLYMESHDETAIL);
|
||||
|
||||
return true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user