Recast: adjustments for tile cache

Tile cache still doesn't generate properly, these fixes are the start.
This commit is contained in:
Kawe Mazidjatari 2024-07-12 12:52:30 +02:00
parent 06ba52d4e6
commit 5d34723773

View File

@ -230,7 +230,7 @@ dtStatus dtBuildTileCacheRegions(dtTileCacheAlloc* alloc,
const unsigned char nr = layer.regs[yidx]; const unsigned char nr = layer.regs[yidx];
if (nr != 0xff) if (nr != 0xff)
{ {
// Set neighbour when first valid neighbour is encoutered. // Set neighbour when first valid neighbour is encountered.
if (sweeps[sid].ns == 0) if (sweeps[sid].ns == 0)
sweeps[sid].nei = nr; sweeps[sid].nei = nr;
@ -242,7 +242,7 @@ dtStatus dtBuildTileCacheRegions(dtTileCacheAlloc* alloc,
} }
else else
{ {
// This is hit if there is nore than one neighbour. // This is hit if there is more than one neighbour.
// Invalidate the neighbour. // Invalidate the neighbour.
sweeps[sid].nei = 0xff; sweeps[sid].nei = 0xff;
} }
@ -393,14 +393,14 @@ static bool appendVertex(dtTempContour& cont, const int x, const int y, const in
{ {
if (pa[0] == pb[0] && (int)pb[0] == x) if (pa[0] == pb[0] && (int)pb[0] == x)
{ {
// The verts are aligned aling x-axis, update y. // The verts are aligned along x-axis, update y.
pb[1] = (unsigned char)y; pb[1] = (unsigned char)y;
pb[0] = (unsigned char)x; pb[2] = (unsigned char)z;
return true; return true;
} }
else if (pa[1] == pb[1] && (int)pb[1] == y) else if (pa[1] == pb[1] && (int)pb[1] == y)
{ {
// The verts are aligned aling y-axis, update x. // The verts are aligned along y-axis, update x.
pb[0] = (unsigned char)x; pb[0] = (unsigned char)x;
pb[1] = (unsigned char)y; pb[1] = (unsigned char)y;
return true; return true;
@ -497,7 +497,7 @@ static bool walkContour(dtTileCacheLayer& layer, int x, int y, dtTempContour& co
} }
// Try to merge with previous vertex. // Try to merge with previous vertex.
if (!appendVertex(cont, px, (int)layer.heights[x+y*w], py,rn)) if (!appendVertex(cont, px, py, (int)layer.heights[x+y*w],rn))
return false; return false;
ndir = (dir+1) & 0x3; // Rotate CW ndir = (dir+1) & 0x3; // Rotate CW
@ -789,7 +789,6 @@ dtStatus dtBuildTileCacheContours(dtTileCacheAlloc* alloc,
// Note: If you hit here often, try increasing 'maxTempVerts'. // Note: If you hit here often, try increasing 'maxTempVerts'.
return DT_FAILURE | DT_BUFFER_TOO_SMALL; return DT_FAILURE | DT_BUFFER_TOO_SMALL;
} }
simplifyContour(temp, maxError); simplifyContour(temp, maxError);
// Store contour. // Store contour.
@ -850,7 +849,7 @@ static unsigned short addVertex(unsigned short x, unsigned short y, unsigned sho
while (i != DT_TILECACHE_NULL_IDX) while (i != DT_TILECACHE_NULL_IDX)
{ {
const unsigned short* v = &verts[i*3]; const unsigned short* v = &verts[i*3];
if (v[0] == x && v[1] == y && (dtAbs(v[1] - z) <= 2)) if (v[0] == x && v[1] == y && (dtAbs(v[2] - z) <= 2))
return i; return i;
i = nextVert[i]; // next i = nextVert[i]; // next
} }
@ -982,10 +981,10 @@ static bool buildMeshAdjacency(dtTileCacheAlloc* alloc,
{ {
// Find matching vertical edge // Find matching vertical edge
const unsigned short x = (unsigned short)va[0]; const unsigned short x = (unsigned short)va[0];
unsigned short ymin = (unsigned short)va[1]; unsigned short zmin = (unsigned short)va[2];
unsigned short ymax = (unsigned short)vb[1]; unsigned short zmax = (unsigned short)vb[2];
if (ymin > ymax) if (zmin > zmax)
dtSwap(ymin, ymax); dtSwap(zmin, zmax);
for (int m = 0; m < edgeCount; ++m) for (int m = 0; m < edgeCount; ++m)
{ {
@ -997,11 +996,11 @@ static bool buildMeshAdjacency(dtTileCacheAlloc* alloc,
const unsigned short* evb = &verts[e.vert[1]*3]; const unsigned short* evb = &verts[e.vert[1]*3];
if (eva[0] == x && evb[0] == x) if (eva[0] == x && evb[0] == x)
{ {
unsigned short eymin = eva[1]; unsigned short ezmin = eva[2];
unsigned short eymax = evb[1]; unsigned short ezmax = evb[2];
if (eymin > eymax) if (ezmin > ezmax)
dtSwap(eymin, eymax); dtSwap(ezmin, ezmax);
if (overlapRangeExl(ymin,ymax, eymin, eymax)) if (overlapRangeExl(zmin,zmax, ezmin, ezmax))
{ {
// Reuse the other polyedge to store dir. // Reuse the other polyedge to store dir.
e.polyEdge[1] = dir; e.polyEdge[1] = dir;
@ -1094,6 +1093,16 @@ inline bool leftOn(const unsigned char* a, const unsigned char* b, const unsigne
{ {
return area2(a, b, c) <= 0; return area2(a, b, c) <= 0;
} }
#define REVERSE_DIRECTION 1
inline bool right(const unsigned char* a, const unsigned char* b, const unsigned char* c)
{
return area2(a, b, c) > 0;
}
inline bool rightOn(const unsigned char* a, const unsigned char* b, const unsigned char* c)
{
return area2(a, b, c) >= 0;
}
inline bool collinear(const unsigned char* a, const unsigned char* b, const unsigned char* c) inline bool collinear(const unsigned char* a, const unsigned char* b, const unsigned char* c)
{ {
@ -1110,8 +1119,11 @@ static bool intersectProp(const unsigned char* a, const unsigned char* b,
if (collinear(a,b,c) || collinear(a,b,d) || if (collinear(a,b,c) || collinear(a,b,d) ||
collinear(c,d,a) || collinear(c,d,b)) collinear(c,d,a) || collinear(c,d,b))
return false; return false;
#if REVERSE_DIRECTION
return xorb(right(a,b,c), right(a,b,d)) && xorb(right(c,d,a), right(c,d,b));
#else
return xorb(left(a,b,c), left(a,b,d)) && xorb(left(c,d,a), left(c,d,b)); return xorb(left(a,b,c), left(a,b,d)) && xorb(left(c,d,a), left(c,d,b));
#endif
} }
// Returns T if (a,b,c) are collinear and point c lies // Returns T if (a,b,c) are collinear and point c lies
@ -1144,7 +1156,13 @@ static bool vequal(const unsigned char* a, const unsigned char* b)
{ {
return a[0] == b[0] && a[1] == b[1]; return a[0] == b[0] && a[1] == b[1];
} }
#if REVERSE_DIRECTION
#define STEP_DIR prev
#define REV_STEP_DIR next
#else
#define STEP_DIR next
#define REV_STEP_DIR prev
#endif
// Returns T if (v_i, v_j) is a proper internal *or* external // Returns T if (v_i, v_j) is a proper internal *or* external
// diagonal of P, *ignoring edges incident to v_i and v_j*. // diagonal of P, *ignoring edges incident to v_i and v_j*.
static bool diagonalie(int i, int j, int n, const unsigned char* verts, const unsigned short* indices) static bool diagonalie(int i, int j, int n, const unsigned char* verts, const unsigned short* indices)
@ -1155,7 +1173,7 @@ static bool diagonalie(int i, int j, int n, const unsigned char* verts, const un
// For each edge (k,k+1) of P // For each edge (k,k+1) of P
for (int k = 0; k < n; k++) for (int k = 0; k < n; k++)
{ {
int k1 = next(k, n); int k1 = STEP_DIR(k, n);
// Skip edges incident to i or j // Skip edges incident to i or j
if (!((k == i) || (k1 == i) || (k == j) || (k1 == j))) if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
{ {
@ -1178,15 +1196,23 @@ static bool inCone(int i, int j, int n, const unsigned char* verts, const unsign
{ {
const unsigned char* pi = &verts[(indices[i] & 0x7fff) * 4]; const unsigned char* pi = &verts[(indices[i] & 0x7fff) * 4];
const unsigned char* pj = &verts[(indices[j] & 0x7fff) * 4]; const unsigned char* pj = &verts[(indices[j] & 0x7fff) * 4];
const unsigned char* pi1 = &verts[(indices[next(i, n)] & 0x7fff) * 4]; const unsigned char* pi1 = &verts[(indices[STEP_DIR(i, n)] & 0x7fff) * 4];
const unsigned char* pin1 = &verts[(indices[prev(i, n)] & 0x7fff) * 4]; const unsigned char* pin1 = &verts[(indices[REV_STEP_DIR(i, n)] & 0x7fff) * 4];
#if REVERSE_DIRECTION
// If P[i] is a convex vertex [ i+1 right or on (i-1,i) ].
if (rightOn(pin1, pi, pi1))
return right(pi, pj, pin1) && right(pj, pi, pi1);
// Assume (i-1,i,i+1) not collinear.
// else P[i] is reflex.
return !(rightOn(pi, pj, pi1) && rightOn(pj, pi, pin1));
#else
// If P[i] is a convex vertex [ i+1 left or on (i-1,i) ]. // If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
if (leftOn(pin1, pi, pi1)) if (leftOn(pin1, pi, pi1))
return left(pi, pj, pin1) && left(pj, pi, pi1); return left(pi, pj, pin1) && left(pj, pi, pi1);
// Assume (i-1,i,i+1) not collinear. // Assume (i-1,i,i+1) not collinear.
// else P[i] is reflex. // else P[i] is reflex.
return !(leftOn(pi, pj, pi1) && leftOn(pj, pi, pin1)); return !(leftOn(pi, pj, pi1) && leftOn(pj, pi, pin1));
#endif
} }
// Returns T if (v_i, v_j) is a proper internal // Returns T if (v_i, v_j) is a proper internal
@ -1204,8 +1230,8 @@ static int triangulate(int n, const unsigned char* verts, unsigned short* indice
// The last bit of the index is used to indicate if the vertex can be removed. // The last bit of the index is used to indicate if the vertex can be removed.
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
{ {
int i1 = next(i, n); int i1 = STEP_DIR(i, n);
int i2 = next(i1, n); int i2 = STEP_DIR(i1, n);
if (diagonal(i, i2, n, verts, indices)) if (diagonal(i, i2, n, verts, indices))
indices[i1] |= 0x8000; indices[i1] |= 0x8000;
} }
@ -1216,11 +1242,11 @@ static int triangulate(int n, const unsigned char* verts, unsigned short* indice
int mini = -1; int mini = -1;
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
{ {
int i1 = next(i, n); int i1 = STEP_DIR(i, n);
if (indices[i1] & 0x8000) if (indices[i1] & 0x8000)
{ {
const unsigned char* p0 = &verts[(indices[i] & 0x7fff) * 4]; const unsigned char* p0 = &verts[(indices[i] & 0x7fff) * 4];
const unsigned char* p2 = &verts[(indices[next(i1, n)] & 0x7fff) * 4]; const unsigned char* p2 = &verts[(indices[STEP_DIR(i1, n)] & 0x7fff) * 4];
const int dx = (int)p2[0] - (int)p0[0]; const int dx = (int)p2[0] - (int)p0[0];
const int dy = (int)p2[1] - (int)p0[1]; const int dy = (int)p2[1] - (int)p0[1];
@ -1246,8 +1272,8 @@ static int triangulate(int n, const unsigned char* verts, unsigned short* indice
} }
int i = mini; int i = mini;
int i1 = next(i, n); int i1 = STEP_DIR(i, n);
int i2 = next(i1, n); int i2 = STEP_DIR(i1, n);
*dst++ = indices[i] & 0x7fff; *dst++ = indices[i] & 0x7fff;
*dst++ = indices[i1] & 0x7fff; *dst++ = indices[i1] & 0x7fff;
@ -1260,24 +1286,30 @@ static int triangulate(int n, const unsigned char* verts, unsigned short* indice
indices[k] = indices[k+1]; indices[k] = indices[k+1];
if (i1 >= n) i1 = 0; if (i1 >= n) i1 = 0;
i = prev(i1,n); i = REV_STEP_DIR(i1,n);
// Update diagonal flags. // Update diagonal flags.
if (diagonal(prev(i, n), i1, n, verts, indices)) if (diagonal(REV_STEP_DIR(i, n), i1, n, verts, indices))
indices[i] |= 0x8000; indices[i] |= 0x8000;
else else
indices[i] &= 0x7fff; indices[i] &= 0x7fff;
if (diagonal(i, next(i1, n), n, verts, indices)) if (diagonal(i, STEP_DIR(i1, n), n, verts, indices))
indices[i1] |= 0x8000; indices[i1] |= 0x8000;
else else
indices[i1] &= 0x7fff; indices[i1] &= 0x7fff;
} }
// Append the remaining triangle. // Append the remaining triangle.
#if REVERSE_DIRECTION
*dst++ = indices[2] & 0x7fff;
*dst++ = indices[1] & 0x7fff;
*dst++ = indices[0] & 0x7fff;
#else
*dst++ = indices[0] & 0x7fff; *dst++ = indices[0] & 0x7fff;
*dst++ = indices[1] & 0x7fff; *dst++ = indices[1] & 0x7fff;
*dst++ = indices[2] & 0x7fff; *dst++ = indices[2] & 0x7fff;
ntris++; ntris++;
#endif
return ntris; return ntris;
} }
@ -1296,6 +1328,11 @@ inline bool uleft(const unsigned short* a, const unsigned short* b, const unsign
return ((int)b[0] - (int)a[0]) * ((int)c[1] - (int)a[1]) - return ((int)b[0] - (int)a[0]) * ((int)c[1] - (int)a[1]) -
((int)c[0] - (int)a[0]) * ((int)b[1] - (int)a[1]) < 0; ((int)c[0] - (int)a[0]) * ((int)b[1] - (int)a[1]) < 0;
} }
inline bool uright(const unsigned short* a, const unsigned short* b, const unsigned short* c)
{
return ((int)b[0] - (int)a[0]) * ((int)c[1] - (int)a[1]) -
((int)c[0] - (int)a[0]) * ((int)b[1] - (int)a[1]) > 0;
}
static int getPolyMergeValue(unsigned short* pa, unsigned short* pb, static int getPolyMergeValue(unsigned short* pa, unsigned short* pb,
const unsigned short* verts, int& ea, int& eb) const unsigned short* verts, int& ea, int& eb)
@ -1342,15 +1379,23 @@ static int getPolyMergeValue(unsigned short* pa, unsigned short* pb,
va = pa[(ea+na-1) % na]; va = pa[(ea+na-1) % na];
vb = pa[ea]; vb = pa[ea];
vc = pb[(eb+2) % nb]; vc = pb[(eb+2) % nb];
#if REVERSE_DIRECTION
if (!uright(&verts[va*3], &verts[vb*3], &verts[vc*3]))
return -1;
#else
if (!uleft(&verts[va*3], &verts[vb*3], &verts[vc*3])) if (!uleft(&verts[va*3], &verts[vb*3], &verts[vc*3]))
return -1; return -1;
#endif
va = pb[(eb+nb-1) % nb]; va = pb[(eb+nb-1) % nb];
vb = pb[eb]; vb = pb[eb];
vc = pa[(ea+2) % na]; vc = pa[(ea+2) % na];
#if REVERSE_DIRECTION
if (!uright(&verts[va*3], &verts[vb*3], &verts[vc*3]))
return -1;
#else
if (!uleft(&verts[va*3], &verts[vb*3], &verts[vc*3])) if (!uleft(&verts[va*3], &verts[vb*3], &verts[vc*3]))
return -1; return -1;
#endif
va = pa[ea]; va = pa[ea];
vb = pa[(ea+1)%na]; vb = pa[(ea+1)%na];
@ -1459,12 +1504,21 @@ static bool canRemoveVertex(dtTileCachePolyMesh& mesh, const unsigned short rem)
for (int m = 0; m < nedges; ++m) for (int m = 0; m < nedges; ++m)
{ {
unsigned short* e = &edges[m*3]; unsigned short* e = &edges[m*3];
#if REVERSE_DIRECTION
if (e[2] == b)
{
// Exists, increment vertex share count.
e[1]++;
exists = true;
}
#else
if (e[1] == b) if (e[1] == b)
{ {
// Exists, increment vertex share count. // Exists, increment vertex share count.
e[2]++; e[2]++;
exists = true; exists = true;
} }
#endif
} }
// Add new edge. // Add new edge.
if (!exists) if (!exists)
@ -1780,7 +1834,7 @@ dtStatus dtBuildTileCachePolyMesh(dtTileCacheAlloc* alloc,
if (!mesh.flags) if (!mesh.flags)
return DT_FAILURE | DT_OUT_OF_MEMORY; return DT_FAILURE | DT_OUT_OF_MEMORY;
// Just allocate and clean the mesh flags array. The user is resposible for filling it. // Just allocate and clean the mesh flags array. The user is responsible for filling it.
memset(mesh.flags, 0, sizeof(unsigned short) * maxTris); memset(mesh.flags, 0, sizeof(unsigned short) * maxTris);
mesh.nverts = 0; mesh.nverts = 0;
@ -2051,13 +2105,13 @@ dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float c
float cx = (center[0] - orig[0])*ics; float cx = (center[0] - orig[0])*ics;
float cy = (center[1] - orig[1])*ics; float cy = (center[1] - orig[1])*ics;
float maxr = 1.41f*dtMax(halfExtents[0], halfExtents[2]); float maxr = 1.41f*dtMax(halfExtents[0], halfExtents[1]);
int minx = (int)floorf(cx - maxr*ics); int minx = (int)floorf(cx - maxr*ics);
int maxx = (int)floorf(cx + maxr*ics); int maxx = (int)floorf(cx + maxr*ics);
int miny = (int)floorf(cy - maxr*ics); int miny = (int)floorf(cy - maxr*ics);
int maxy = (int)floorf(cy + maxr*ics); int maxy = (int)floorf(cy + maxr*ics);
int minz = (int)floorf((center[1]-halfExtents[1]-orig[1])*ich); int minz = (int)floorf((center[2]-halfExtents[2]-orig[2])*ich);
int maxz = (int)floorf((center[1]+halfExtents[1]-orig[1])*ich); int maxz = (int)floorf((center[2]+halfExtents[2]-orig[2])*ich);
if (maxx < 0) return DT_SUCCESS; if (maxx < 0) return DT_SUCCESS;
if (minx >= w) return DT_SUCCESS; if (minx >= w) return DT_SUCCESS;
@ -2148,7 +2202,7 @@ dtStatus dtBuildTileCacheLayer(dtTileCacheCompressor* comp,
void dtFreeTileCacheLayer(dtTileCacheAlloc* alloc, dtTileCacheLayer* layer) void dtFreeTileCacheLayer(dtTileCacheAlloc* alloc, dtTileCacheLayer* layer)
{ {
rdAssert(alloc); rdAssert(alloc);
// The layer is allocated as one conitguous blob of data. // The layer is allocated as one contiguous blob of data.
alloc->free(layer); alloc->free(layer);
} }