TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
RecastMesh.cpp File Reference
#include <math.h>
#include <string.h>
#include <stdio.h>
#include "Recast.h"
#include "RecastAlloc.h"
#include "RecastAssert.h"
+ Include dependency graph for RecastMesh.cpp:

Classes

struct  rcEdge
 

Macros

#define _USE_MATH_DEFINES
 

Functions

static bool buildMeshAdjacency (unsigned short *polys, const int npolys, const int nverts, const int vertsPerPoly)
 
int computeVertexHash (int x, int y, int z)
 
static unsigned short addVertex (unsigned short x, unsigned short y, unsigned short z, unsigned short *verts, int *firstVert, int *nextVert, int &nv)
 
int prev (int i, int n)
 
int next (int i, int n)
 
int area2 (const int *a, const int *b, const int *c)
 
bool xorb (bool x, bool y)
 
bool left (const int *a, const int *b, const int *c)
 
bool leftOn (const int *a, const int *b, const int *c)
 
bool collinear (const int *a, const int *b, const int *c)
 
static bool intersectProp (const int *a, const int *b, const int *c, const int *d)
 
static bool between (const int *a, const int *b, const int *c)
 
static bool intersect (const int *a, const int *b, const int *c, const int *d)
 
static bool vequal (const int *a, const int *b)
 
static bool diagonalie (int i, int j, int n, const int *verts, int *indices)
 
static bool inCone (int i, int j, int n, const int *verts, int *indices)
 
static bool diagonal (int i, int j, int n, const int *verts, int *indices)
 
static bool diagonalieLoose (int i, int j, int n, const int *verts, int *indices)
 
static bool inConeLoose (int i, int j, int n, const int *verts, int *indices)
 
static bool diagonalLoose (int i, int j, int n, const int *verts, int *indices)
 
static int triangulate (int n, const int *verts, int *indices, int *tris)
 
static int countPolyVerts (const unsigned short *p, const int nvp)
 
bool uleft (const unsigned short *a, const unsigned short *b, const unsigned short *c)
 
static int getPolyMergeValue (unsigned short *pa, unsigned short *pb, const unsigned short *verts, int &ea, int &eb, const int nvp)
 
static void mergePolys (unsigned short *pa, unsigned short *pb, int ea, int eb, unsigned short *tmp, const int nvp)
 
static void pushFront (int v, int *arr, int &an)
 
static void pushBack (int v, int *arr, int &an)
 
static bool canRemoveVertex (rcContext *ctx, rcPolyMesh &mesh, const unsigned short rem)
 
static bool removeVertex (rcContext *ctx, rcPolyMesh &mesh, const unsigned short rem, const int maxTris)
 
bool rcBuildPolyMesh (rcContext *ctx, rcContourSet &cset, const int nvp, rcPolyMesh &mesh)
 
bool rcMergePolyMeshes (rcContext *ctx, rcPolyMesh **meshes, const int nmeshes, rcPolyMesh &mesh)
 
bool rcCopyPolyMesh (rcContext *ctx, const rcPolyMesh &src, rcPolyMesh &dst)
 

Variables

static const int VERTEX_BUCKET_COUNT = (1<<12)
 

Macro Definition Documentation

#define _USE_MATH_DEFINES

Function Documentation

static unsigned short addVertex ( unsigned short  x,
unsigned short  y,
unsigned short  z,
unsigned short *  verts,
int *  firstVert,
int *  nextVert,
int &  nv 
)
static
139 {
140  int bucket = computeVertexHash(x, 0, z);
141  int i = firstVert[bucket];
142 
143  while (i != -1)
144  {
145  const unsigned short* v = &verts[i*3];
146  if (v[0] == x && (rcAbs(v[1] - y) <= 2) && v[2] == z)
147  return (unsigned short)i;
148  i = nextVert[i]; // next
149  }
150 
151  // Could not find, create new.
152  i = nv; nv++;
153  unsigned short* v = &verts[i*3];
154  v[0] = x;
155  v[1] = y;
156  v[2] = z;
157  nextVert[i] = firstVert[bucket];
158  firstVert[bucket] = i;
159 
160  return (unsigned short)i;
161 }
T rcAbs(T a)
Definition: Recast.h:577
int computeVertexHash(int x, int y, int z)
Definition: RecastMesh.cpp:128
G3D::int16 z
Definition: Vector3int16.h:46
G3D::int16 y
Definition: Vector2int16.h:38
G3D::int16 x
Definition: Vector2int16.h:37

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int area2 ( const int *  a,
const int *  b,
const int *  c 
)
inline
168 {
169  return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]);
170 }

+ Here is the caller graph for this function:

static bool between ( const int *  a,
const int *  b,
const int *  c 
)
static
214 {
215  if (!collinear(a, b, c))
216  return false;
217  // If ab not vertical, check betweenness on x; else on y.
218  if (a[0] != b[0])
219  return ((a[0] <= c[0]) && (c[0] <= b[0])) || ((a[0] >= c[0]) && (c[0] >= b[0]));
220  else
221  return ((a[2] <= c[2]) && (c[2] <= b[2])) || ((a[2] >= c[2]) && (c[2] >= b[2]));
222 }
bool collinear(const int *a, const int *b, const int *c)
Definition: RecastMesh.cpp:193

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool buildMeshAdjacency ( unsigned short *  polys,
const int  npolys,
const int  nverts,
const int  vertsPerPoly 
)
static
36 {
37  // Based on code by Eric Lengyel from:
38  // http://www.terathon.com/code/edges.php
39 
40  int maxEdgeCount = npolys*vertsPerPoly;
41  unsigned short* firstEdge = (unsigned short*)rcAlloc(sizeof(unsigned short)*(nverts + maxEdgeCount), RC_ALLOC_TEMP);
42  if (!firstEdge)
43  return false;
44  unsigned short* nextEdge = firstEdge + nverts;
45  int edgeCount = 0;
46 
47  rcEdge* edges = (rcEdge*)rcAlloc(sizeof(rcEdge)*maxEdgeCount, RC_ALLOC_TEMP);
48  if (!edges)
49  {
50  rcFree(firstEdge);
51  return false;
52  }
53 
54  for (int i = 0; i < nverts; i++)
55  firstEdge[i] = RC_MESH_NULL_IDX;
56 
57  for (int i = 0; i < npolys; ++i)
58  {
59  unsigned short* t = &polys[i*vertsPerPoly*2];
60  for (int j = 0; j < vertsPerPoly; ++j)
61  {
62  if (t[j] == RC_MESH_NULL_IDX) break;
63  unsigned short v0 = t[j];
64  unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == RC_MESH_NULL_IDX) ? t[0] : t[j+1];
65  if (v0 < v1)
66  {
67  rcEdge& edge = edges[edgeCount];
68  edge.vert[0] = v0;
69  edge.vert[1] = v1;
70  edge.poly[0] = (unsigned short)i;
71  edge.polyEdge[0] = (unsigned short)j;
72  edge.poly[1] = (unsigned short)i;
73  edge.polyEdge[1] = 0;
74  // Insert edge
75  nextEdge[edgeCount] = firstEdge[v0];
76  firstEdge[v0] = (unsigned short)edgeCount;
77  edgeCount++;
78  }
79  }
80  }
81 
82  for (int i = 0; i < npolys; ++i)
83  {
84  unsigned short* t = &polys[i*vertsPerPoly*2];
85  for (int j = 0; j < vertsPerPoly; ++j)
86  {
87  if (t[j] == RC_MESH_NULL_IDX) break;
88  unsigned short v0 = t[j];
89  unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == RC_MESH_NULL_IDX) ? t[0] : t[j+1];
90  if (v0 > v1)
91  {
92  for (unsigned short e = firstEdge[v1]; e != RC_MESH_NULL_IDX; e = nextEdge[e])
93  {
94  rcEdge& edge = edges[e];
95  if (edge.vert[1] == v0 && edge.poly[0] == edge.poly[1])
96  {
97  edge.poly[1] = (unsigned short)i;
98  edge.polyEdge[1] = (unsigned short)j;
99  break;
100  }
101  }
102  }
103  }
104  }
105 
106  // Store adjacency
107  for (int i = 0; i < edgeCount; ++i)
108  {
109  const rcEdge& e = edges[i];
110  if (e.poly[0] != e.poly[1])
111  {
112  unsigned short* p0 = &polys[e.poly[0]*vertsPerPoly*2];
113  unsigned short* p1 = &polys[e.poly[1]*vertsPerPoly*2];
114  p0[vertsPerPoly + e.polyEdge[0]] = e.poly[1];
115  p1[vertsPerPoly + e.polyEdge[1]] = e.poly[0];
116  }
117  }
118 
119  rcFree(firstEdge);
120  rcFree(edges);
121 
122  return true;
123 }
unsigned short poly[2]
Definition: RecastMesh.cpp:31
unsigned short polyEdge[2]
Definition: RecastMesh.cpp:30
void rcFree(void *ptr)
Definition: RecastAlloc.cpp:55
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
static const unsigned short RC_MESH_NULL_IDX
Definition: Recast.h:533
Definition: RecastMesh.cpp:27
unsigned short vert[2]
Definition: RecastMesh.cpp:29
Memory used temporarily within a function.
Definition: RecastAlloc.h:27

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool canRemoveVertex ( rcContext ctx,
rcPolyMesh mesh,
const unsigned short  rem 
)
static
565 {
566  const int nvp = mesh.nvp;
567 
568  // Count number of polygons to remove.
569  int numRemovedVerts = 0;
570  int numTouchedVerts = 0;
571  int numRemainingEdges = 0;
572  for (int i = 0; i < mesh.npolys; ++i)
573  {
574  unsigned short* p = &mesh.polys[i*nvp*2];
575  const int nv = countPolyVerts(p, nvp);
576  int numRemoved = 0;
577  int numVerts = 0;
578  for (int j = 0; j < nv; ++j)
579  {
580  if (p[j] == rem)
581  {
582  numTouchedVerts++;
583  numRemoved++;
584  }
585  numVerts++;
586  }
587  if (numRemoved)
588  {
589  numRemovedVerts += numRemoved;
590  numRemainingEdges += numVerts-(numRemoved+1);
591  }
592  }
593 
594  // There would be too few edges remaining to create a polygon.
595  // This can happen for example when a tip of a triangle is marked
596  // as deletion, but there are no other polys that share the vertex.
597  // In this case, the vertex should not be removed.
598  if (numRemainingEdges <= 2)
599  return false;
600 
601  // Find edges which share the removed vertex.
602  const int maxEdges = numTouchedVerts*2;
603  int nedges = 0;
604  rcScopedDelete<int> edges = (int*)rcAlloc(sizeof(int)*maxEdges*3, RC_ALLOC_TEMP);
605  if (!edges)
606  {
607  ctx->log(RC_LOG_WARNING, "canRemoveVertex: Out of memory 'edges' (%d).", maxEdges*3);
608  return false;
609  }
610 
611  for (int i = 0; i < mesh.npolys; ++i)
612  {
613  unsigned short* p = &mesh.polys[i*nvp*2];
614  const int nv = countPolyVerts(p, nvp);
615 
616  // Collect edges which touches the removed vertex.
617  for (int j = 0, k = nv-1; j < nv; k = j++)
618  {
619  if (p[j] == rem || p[k] == rem)
620  {
621  // Arrange edge so that a=rem.
622  int a = p[j], b = p[k];
623  if (b == rem)
624  rcSwap(a,b);
625 
626  // Check if the edge exists
627  bool exists = false;
628  for (int m = 0; m < nedges; ++m)
629  {
630  int* e = &edges[m*3];
631  if (e[1] == b)
632  {
633  // Exists, increment vertex share count.
634  e[2]++;
635  exists = true;
636  }
637  }
638  // Add new edge.
639  if (!exists)
640  {
641  int* e = &edges[nedges*3];
642  e[0] = a;
643  e[1] = b;
644  e[2] = 1;
645  nedges++;
646  }
647  }
648  }
649  }
650 
651  // There should be no more than 2 open edges.
652  // This catches the case that two non-adjacent polygons
653  // share the removed vertex. In that case, do not remove the vertex.
654  int numOpenEdges = 0;
655  for (int i = 0; i < nedges; ++i)
656  {
657  if (edges[i*3+2] < 2)
658  numOpenEdges++;
659  }
660  if (numOpenEdges > 2)
661  return false;
662 
663  return true;
664 }
static int countPolyVerts(const unsigned short *p, const int nvp)
Definition: RecastMesh.cpp:453
void rcSwap(T &a, T &b)
Definition: Recast.h:560
Definition: RecastAlloc.h:105
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
Memory used temporarily within a function.
Definition: RecastAlloc.h:27
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
int npolys
The number of polygons.
Definition: Recast.h:391
A warning log entry.
Definition: Recast.h:30
int nvp
The maximum number of vertices per polygon.
Definition: Recast.h:393
unsigned short * polys
Polygon and neighbor data. [Length: maxpolys * 2 * nvp].
Definition: Recast.h:386

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool collinear ( const int *  a,
const int *  b,
const int *  c 
)
inline
194 {
195  return area2(a, b, c) == 0;
196 }
int area2(const int *a, const int *b, const int *c)
Definition: RecastMesh.cpp:167

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int computeVertexHash ( int  x,
int  y,
int  z 
)
inline
129 {
130  const unsigned int h1 = 0x8da6b343; // Large multiplicative constants;
131  const unsigned int h2 = 0xd8163841; // here arbitrarily chosen primes
132  const unsigned int h3 = 0xcb1ab31f;
133  unsigned int n = h1 * x + h2 * y + h3 * z;
134  return (int)(n & (VERTEX_BUCKET_COUNT-1));
135 }
G3D::int16 z
Definition: Vector3int16.h:46
G3D::int16 y
Definition: Vector2int16.h:38
static const int VERTEX_BUCKET_COUNT
Definition: RecastMesh.cpp:126
G3D::int16 x
Definition: Vector2int16.h:37

+ Here is the caller graph for this function:

static int countPolyVerts ( const unsigned short *  p,
const int  nvp 
)
static
454 {
455  for (int i = 0; i < nvp; ++i)
456  if (p[i] == RC_MESH_NULL_IDX)
457  return i;
458  return nvp;
459 }
static const unsigned short RC_MESH_NULL_IDX
Definition: Recast.h:533

+ Here is the caller graph for this function:

static bool diagonal ( int  i,
int  j,
int  n,
const int *  verts,
int *  indices 
)
static
288 {
289  return inCone(i, j, n, verts, indices) && diagonalie(i, j, n, verts, indices);
290 }
static bool inCone(int i, int j, int n, const int *verts, int *indices)
Definition: RecastMesh.cpp:270
static bool diagonalie(int i, int j, int n, const int *verts, int *indices)
Definition: RecastMesh.cpp:243

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool diagonalie ( int  i,
int  j,
int  n,
const int *  verts,
int *  indices 
)
static
244 {
245  const int* d0 = &verts[(indices[i] & 0x0fffffff) * 4];
246  const int* d1 = &verts[(indices[j] & 0x0fffffff) * 4];
247 
248  // For each edge (k,k+1) of P
249  for (int k = 0; k < n; k++)
250  {
251  int k1 = next(k, n);
252  // Skip edges incident to i or j
253  if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
254  {
255  const int* p0 = &verts[(indices[k] & 0x0fffffff) * 4];
256  const int* p1 = &verts[(indices[k1] & 0x0fffffff) * 4];
257 
258  if (vequal(d0, p0) || vequal(d1, p0) || vequal(d0, p1) || vequal(d1, p1))
259  continue;
260 
261  if (intersect(d0, d1, p0, p1))
262  return false;
263  }
264  }
265  return true;
266 }
static bool intersect(const int *a, const int *b, const int *c, const int *d)
Definition: RecastMesh.cpp:225
int next(int i, int n)
Definition: RecastMesh.cpp:165
static bool vequal(const int *a, const int *b)
Definition: RecastMesh.cpp:236

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool diagonalieLoose ( int  i,
int  j,
int  n,
const int *  verts,
int *  indices 
)
static
294 {
295  const int* d0 = &verts[(indices[i] & 0x0fffffff) * 4];
296  const int* d1 = &verts[(indices[j] & 0x0fffffff) * 4];
297 
298  // For each edge (k,k+1) of P
299  for (int k = 0; k < n; k++)
300  {
301  int k1 = next(k, n);
302  // Skip edges incident to i or j
303  if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
304  {
305  const int* p0 = &verts[(indices[k] & 0x0fffffff) * 4];
306  const int* p1 = &verts[(indices[k1] & 0x0fffffff) * 4];
307 
308  if (vequal(d0, p0) || vequal(d1, p0) || vequal(d0, p1) || vequal(d1, p1))
309  continue;
310 
311  if (intersectProp(d0, d1, p0, p1))
312  return false;
313  }
314  }
315  return true;
316 }
static bool intersectProp(const int *a, const int *b, const int *c, const int *d)
Definition: RecastMesh.cpp:201
int next(int i, int n)
Definition: RecastMesh.cpp:165
static bool vequal(const int *a, const int *b)
Definition: RecastMesh.cpp:236

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool diagonalLoose ( int  i,
int  j,
int  n,
const int *  verts,
int *  indices 
)
static
334 {
335  return inConeLoose(i, j, n, verts, indices) && diagonalieLoose(i, j, n, verts, indices);
336 }
static bool inConeLoose(int i, int j, int n, const int *verts, int *indices)
Definition: RecastMesh.cpp:318
static bool diagonalieLoose(int i, int j, int n, const int *verts, int *indices)
Definition: RecastMesh.cpp:293

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int getPolyMergeValue ( unsigned short *  pa,
unsigned short *  pb,
const unsigned short *  verts,
int &  ea,
int &  eb,
const int  nvp 
)
static
470 {
471  const int na = countPolyVerts(pa, nvp);
472  const int nb = countPolyVerts(pb, nvp);
473 
474  // If the merged polygon would be too big, do not merge.
475  if (na+nb-2 > nvp)
476  return -1;
477 
478  // Check if the polygons share an edge.
479  ea = -1;
480  eb = -1;
481 
482  for (int i = 0; i < na; ++i)
483  {
484  unsigned short va0 = pa[i];
485  unsigned short va1 = pa[(i+1) % na];
486  if (va0 > va1)
487  rcSwap(va0, va1);
488  for (int j = 0; j < nb; ++j)
489  {
490  unsigned short vb0 = pb[j];
491  unsigned short vb1 = pb[(j+1) % nb];
492  if (vb0 > vb1)
493  rcSwap(vb0, vb1);
494  if (va0 == vb0 && va1 == vb1)
495  {
496  ea = i;
497  eb = j;
498  break;
499  }
500  }
501  }
502 
503  // No common edge, cannot merge.
504  if (ea == -1 || eb == -1)
505  return -1;
506 
507  // Check to see if the merged polygon would be convex.
508  unsigned short va, vb, vc;
509 
510  va = pa[(ea+na-1) % na];
511  vb = pa[ea];
512  vc = pb[(eb+2) % nb];
513  if (!uleft(&verts[va*3], &verts[vb*3], &verts[vc*3]))
514  return -1;
515 
516  va = pb[(eb+nb-1) % nb];
517  vb = pb[eb];
518  vc = pa[(ea+2) % na];
519  if (!uleft(&verts[va*3], &verts[vb*3], &verts[vc*3]))
520  return -1;
521 
522  va = pa[ea];
523  vb = pa[(ea+1)%na];
524 
525  int dx = (int)verts[va*3+0] - (int)verts[vb*3+0];
526  int dy = (int)verts[va*3+2] - (int)verts[vb*3+2];
527 
528  return dx*dx + dy*dy;
529 }
static int countPolyVerts(const unsigned short *p, const int nvp)
Definition: RecastMesh.cpp:453
void rcSwap(T &a, T &b)
Definition: Recast.h:560
Definition: BnetFileGenerator.h:49
bool uleft(const unsigned short *a, const unsigned short *b, const unsigned short *c)
Definition: RecastMesh.cpp:461

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool inCone ( int  i,
int  j,
int  n,
const int *  verts,
int *  indices 
)
static
271 {
272  const int* pi = &verts[(indices[i] & 0x0fffffff) * 4];
273  const int* pj = &verts[(indices[j] & 0x0fffffff) * 4];
274  const int* pi1 = &verts[(indices[next(i, n)] & 0x0fffffff) * 4];
275  const int* pin1 = &verts[(indices[prev(i, n)] & 0x0fffffff) * 4];
276 
277  // If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
278  if (leftOn(pin1, pi, pi1))
279  return left(pi, pj, pin1) && left(pj, pi, pi1);
280  // Assume (i-1,i,i+1) not collinear.
281  // else P[i] is reflex.
282  return !(leftOn(pi, pj, pi1) && leftOn(pj, pi, pin1));
283 }
double pi()
Definition: g3dmath.h:147
bool leftOn(const int *a, const int *b, const int *c)
Definition: RecastMesh.cpp:188
int next(int i, int n)
Definition: RecastMesh.cpp:165
int prev(int i, int n)
Definition: RecastMesh.cpp:164
bool left(const int *a, const int *b, const int *c)
Definition: RecastMesh.cpp:183

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool inConeLoose ( int  i,
int  j,
int  n,
const int *  verts,
int *  indices 
)
static
319 {
320  const int* pi = &verts[(indices[i] & 0x0fffffff) * 4];
321  const int* pj = &verts[(indices[j] & 0x0fffffff) * 4];
322  const int* pi1 = &verts[(indices[next(i, n)] & 0x0fffffff) * 4];
323  const int* pin1 = &verts[(indices[prev(i, n)] & 0x0fffffff) * 4];
324 
325  // If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
326  if (leftOn(pin1, pi, pi1))
327  return leftOn(pi, pj, pin1) && leftOn(pj, pi, pi1);
328  // Assume (i-1,i,i+1) not collinear.
329  // else P[i] is reflex.
330  return !(leftOn(pi, pj, pi1) && leftOn(pj, pi, pin1));
331 }
double pi()
Definition: g3dmath.h:147
bool leftOn(const int *a, const int *b, const int *c)
Definition: RecastMesh.cpp:188
int next(int i, int n)
Definition: RecastMesh.cpp:165
int prev(int i, int n)
Definition: RecastMesh.cpp:164

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool intersect ( const int *  a,
const int *  b,
const int *  c,
const int *  d 
)
static
226 {
227  if (intersectProp(a, b, c, d))
228  return true;
229  else if (between(a, b, c) || between(a, b, d) ||
230  between(c, d, a) || between(c, d, b))
231  return true;
232  else
233  return false;
234 }
static bool intersectProp(const int *a, const int *b, const int *c, const int *d)
Definition: RecastMesh.cpp:201
static bool between(const int *a, const int *b, const int *c)
Definition: RecastMesh.cpp:213

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool intersectProp ( const int *  a,
const int *  b,
const int *  c,
const int *  d 
)
static
202 {
203  // Eliminate improper cases.
204  if (collinear(a,b,c) || collinear(a,b,d) ||
205  collinear(c,d,a) || collinear(c,d,b))
206  return false;
207 
208  return xorb(left(a,b,c), left(a,b,d)) && xorb(left(c,d,a), left(c,d,b));
209 }
bool collinear(const int *a, const int *b, const int *c)
Definition: RecastMesh.cpp:193
bool xorb(bool x, bool y)
Definition: RecastMesh.cpp:176
bool left(const int *a, const int *b, const int *c)
Definition: RecastMesh.cpp:183

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool left ( const int *  a,
const int *  b,
const int *  c 
)
inline
184 {
185  return area2(a, b, c) < 0;
186 }
int area2(const int *a, const int *b, const int *c)
Definition: RecastMesh.cpp:167

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool leftOn ( const int *  a,
const int *  b,
const int *  c 
)
inline
189 {
190  return area2(a, b, c) <= 0;
191 }
int area2(const int *a, const int *b, const int *c)
Definition: RecastMesh.cpp:167

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void mergePolys ( unsigned short *  pa,
unsigned short *  pb,
int  ea,
int  eb,
unsigned short *  tmp,
const int  nvp 
)
static
533 {
534  const int na = countPolyVerts(pa, nvp);
535  const int nb = countPolyVerts(pb, nvp);
536 
537  // Merge polygons.
538  memset(tmp, 0xff, sizeof(unsigned short)*nvp);
539  int n = 0;
540  // Add pa
541  for (int i = 0; i < na-1; ++i)
542  tmp[n++] = pa[(ea+1+i) % na];
543  // Add pb
544  for (int i = 0; i < nb-1; ++i)
545  tmp[n++] = pb[(eb+1+i) % nb];
546 
547  memcpy(pa, tmp, sizeof(unsigned short)*nvp);
548 }
static int countPolyVerts(const unsigned short *p, const int nvp)
Definition: RecastMesh.cpp:453
Definition: BnetFileGenerator.h:49

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int next ( int  i,
int  n 
)
inline
165 { return i+1 < n ? i+1 : 0; }

+ Here is the caller graph for this function:

int prev ( int  i,
int  n 
)
inline
164 { return i-1 >= 0 ? i-1 : n-1; }

+ Here is the caller graph for this function:

static void pushBack ( int  v,
int *  arr,
int &  an 
)
static
559 {
560  arr[an] = v;
561  an++;
562 }

+ Here is the caller graph for this function:

static void pushFront ( int  v,
int *  arr,
int &  an 
)
static
552 {
553  an++;
554  for (int i = an-1; i > 0; --i) arr[i] = arr[i-1];
555  arr[0] = v;
556 }

+ Here is the caller graph for this function:

bool rcBuildPolyMesh ( rcContext ctx,
rcContourSet cset,
const int  nvp,
rcPolyMesh mesh 
)
Note
If the mesh data is to be used to construct a Detour navigation mesh, then the upper limit must be retricted to <= DT_VERTS_PER_POLYGON.
See also
rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig
983 {
984  rcAssert(ctx);
985 
987 
988  rcVcopy(mesh.bmin, cset.bmin);
989  rcVcopy(mesh.bmax, cset.bmax);
990  mesh.cs = cset.cs;
991  mesh.ch = cset.ch;
992  mesh.borderSize = cset.borderSize;
993 
994  int maxVertices = 0;
995  int maxTris = 0;
996  int maxVertsPerCont = 0;
997  for (int i = 0; i < cset.nconts; ++i)
998  {
999  // Skip null contours.
1000  if (cset.conts[i].nverts < 3) continue;
1001  maxVertices += cset.conts[i].nverts;
1002  maxTris += cset.conts[i].nverts - 2;
1003  maxVertsPerCont = rcMax(maxVertsPerCont, cset.conts[i].nverts);
1004  }
1005 
1006  if (maxVertices >= 0xfffe)
1007  {
1008  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many vertices %d.", maxVertices);
1009  return false;
1010  }
1011 
1012  rcScopedDelete<unsigned char> vflags = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxVertices, RC_ALLOC_TEMP);
1013  if (!vflags)
1014  {
1015  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'vflags' (%d).", maxVertices);
1016  return false;
1017  }
1018  memset(vflags, 0, maxVertices);
1019 
1020  mesh.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVertices*3, RC_ALLOC_PERM);
1021  if (!mesh.verts)
1022  {
1023  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices);
1024  return false;
1025  }
1026  mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris*nvp*2, RC_ALLOC_PERM);
1027  if (!mesh.polys)
1028  {
1029  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.polys' (%d).", maxTris*nvp*2);
1030  return false;
1031  }
1032  mesh.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris, RC_ALLOC_PERM);
1033  if (!mesh.regs)
1034  {
1035  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.regs' (%d).", maxTris);
1036  return false;
1037  }
1038  mesh.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris, RC_ALLOC_PERM);
1039  if (!mesh.areas)
1040  {
1041  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.areas' (%d).", maxTris);
1042  return false;
1043  }
1044 
1045  mesh.nverts = 0;
1046  mesh.npolys = 0;
1047  mesh.nvp = nvp;
1048  mesh.maxpolys = maxTris;
1049 
1050  memset(mesh.verts, 0, sizeof(unsigned short)*maxVertices*3);
1051  memset(mesh.polys, 0xff, sizeof(unsigned short)*maxTris*nvp*2);
1052  memset(mesh.regs, 0, sizeof(unsigned short)*maxTris);
1053  memset(mesh.areas, 0, sizeof(unsigned char)*maxTris);
1054 
1055  rcScopedDelete<int> nextVert = (int*)rcAlloc(sizeof(int)*maxVertices, RC_ALLOC_TEMP);
1056  if (!nextVert)
1057  {
1058  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'nextVert' (%d).", maxVertices);
1059  return false;
1060  }
1061  memset(nextVert, 0, sizeof(int)*maxVertices);
1062 
1063  rcScopedDelete<int> firstVert = (int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP);
1064  if (!firstVert)
1065  {
1066  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT);
1067  return false;
1068  }
1069  for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i)
1070  firstVert[i] = -1;
1071 
1072  rcScopedDelete<int> indices = (int*)rcAlloc(sizeof(int)*maxVertsPerCont, RC_ALLOC_TEMP);
1073  if (!indices)
1074  {
1075  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'indices' (%d).", maxVertsPerCont);
1076  return false;
1077  }
1078  rcScopedDelete<int> tris = (int*)rcAlloc(sizeof(int)*maxVertsPerCont*3, RC_ALLOC_TEMP);
1079  if (!tris)
1080  {
1081  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'tris' (%d).", maxVertsPerCont*3);
1082  return false;
1083  }
1084  rcScopedDelete<unsigned short> polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*(maxVertsPerCont+1)*nvp, RC_ALLOC_TEMP);
1085  if (!polys)
1086  {
1087  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'polys' (%d).", maxVertsPerCont*nvp);
1088  return false;
1089  }
1090  unsigned short* tmpPoly = &polys[maxVertsPerCont*nvp];
1091 
1092  for (int i = 0; i < cset.nconts; ++i)
1093  {
1094  rcContour& cont = cset.conts[i];
1095 
1096  // Skip null contours.
1097  if (cont.nverts < 3)
1098  continue;
1099 
1100  // Triangulate contour
1101  for (int j = 0; j < cont.nverts; ++j)
1102  indices[j] = j;
1103 
1104  int ntris = triangulate(cont.nverts, cont.verts, &indices[0], &tris[0]);
1105  if (ntris <= 0)
1106  {
1107  // Bad triangulation, should not happen.
1108 /* printf("\tconst float bmin[3] = {%ff,%ff,%ff};\n", cset.bmin[0], cset.bmin[1], cset.bmin[2]);
1109  printf("\tconst float cs = %ff;\n", cset.cs);
1110  printf("\tconst float ch = %ff;\n", cset.ch);
1111  printf("\tconst int verts[] = {\n");
1112  for (int k = 0; k < cont.nverts; ++k)
1113  {
1114  const int* v = &cont.verts[k*4];
1115  printf("\t\t%d,%d,%d,%d,\n", v[0], v[1], v[2], v[3]);
1116  }
1117  printf("\t};\n\tconst int nverts = sizeof(verts)/(sizeof(int)*4);\n");*/
1118  ctx->log(RC_LOG_WARNING, "rcBuildPolyMesh: Bad triangulation Contour %d.", i);
1119  ntris = -ntris;
1120  }
1121 
1122  // Add and merge vertices.
1123  for (int j = 0; j < cont.nverts; ++j)
1124  {
1125  const int* v = &cont.verts[j*4];
1126  indices[j] = addVertex((unsigned short)v[0], (unsigned short)v[1], (unsigned short)v[2],
1127  mesh.verts, firstVert, nextVert, mesh.nverts);
1128  if (v[3] & RC_BORDER_VERTEX)
1129  {
1130  // This vertex should be removed.
1131  vflags[indices[j]] = 1;
1132  }
1133  }
1134 
1135  // Build initial polygons.
1136  int npolys = 0;
1137  memset(polys, 0xff, maxVertsPerCont*nvp*sizeof(unsigned short));
1138  for (int j = 0; j < ntris; ++j)
1139  {
1140  int* t = &tris[j*3];
1141  if (t[0] != t[1] && t[0] != t[2] && t[1] != t[2])
1142  {
1143  polys[npolys*nvp+0] = (unsigned short)indices[t[0]];
1144  polys[npolys*nvp+1] = (unsigned short)indices[t[1]];
1145  polys[npolys*nvp+2] = (unsigned short)indices[t[2]];
1146  npolys++;
1147  }
1148  }
1149  if (!npolys)
1150  continue;
1151 
1152  // Merge polygons.
1153  if (nvp > 3)
1154  {
1155  for(;;)
1156  {
1157  // Find best polygons to merge.
1158  int bestMergeVal = 0;
1159  int bestPa = 0, bestPb = 0, bestEa = 0, bestEb = 0;
1160 
1161  for (int j = 0; j < npolys-1; ++j)
1162  {
1163  unsigned short* pj = &polys[j*nvp];
1164  for (int k = j+1; k < npolys; ++k)
1165  {
1166  unsigned short* pk = &polys[k*nvp];
1167  int ea, eb;
1168  int v = getPolyMergeValue(pj, pk, mesh.verts, ea, eb, nvp);
1169  if (v > bestMergeVal)
1170  {
1171  bestMergeVal = v;
1172  bestPa = j;
1173  bestPb = k;
1174  bestEa = ea;
1175  bestEb = eb;
1176  }
1177  }
1178  }
1179 
1180  if (bestMergeVal > 0)
1181  {
1182  // Found best, merge.
1183  unsigned short* pa = &polys[bestPa*nvp];
1184  unsigned short* pb = &polys[bestPb*nvp];
1185  mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp);
1186  unsigned short* lastPoly = &polys[(npolys-1)*nvp];
1187  if (pb != lastPoly)
1188  memcpy(pb, lastPoly, sizeof(unsigned short)*nvp);
1189  npolys--;
1190  }
1191  else
1192  {
1193  // Could not merge any polygons, stop.
1194  break;
1195  }
1196  }
1197  }
1198 
1199  // Store polygons.
1200  for (int j = 0; j < npolys; ++j)
1201  {
1202  unsigned short* p = &mesh.polys[mesh.npolys*nvp*2];
1203  unsigned short* q = &polys[j*nvp];
1204  for (int k = 0; k < nvp; ++k)
1205  p[k] = q[k];
1206  mesh.regs[mesh.npolys] = cont.reg;
1207  mesh.areas[mesh.npolys] = cont.area;
1208  mesh.npolys++;
1209  if (mesh.npolys > maxTris)
1210  {
1211  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many polygons %d (max:%d).", mesh.npolys, maxTris);
1212  return false;
1213  }
1214  }
1215  }
1216 
1217 
1218  // Remove edge vertices.
1219  for (int i = 0; i < mesh.nverts; ++i)
1220  {
1221  if (vflags[i])
1222  {
1223  if (!canRemoveVertex(ctx, mesh, (unsigned short)i))
1224  continue;
1225  if (!removeVertex(ctx, mesh, (unsigned short)i, maxTris))
1226  {
1227  // Failed to remove vertex
1228  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Failed to remove edge vertex %d.", i);
1229  return false;
1230  }
1231  // Remove vertex
1232  // Note: mesh.nverts is already decremented inside removeVertex()!
1233  // Fixup vertex flags
1234  for (int j = i; j < mesh.nverts; ++j)
1235  vflags[j] = vflags[j+1];
1236  --i;
1237  }
1238  }
1239 
1240  // Calculate adjacency.
1241  if (!buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, nvp))
1242  {
1243  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Adjacency failed.");
1244  return false;
1245  }
1246 
1247  // Find portal edges
1248  if (mesh.borderSize > 0)
1249  {
1250  const int w = cset.width;
1251  const int h = cset.height;
1252  for (int i = 0; i < mesh.npolys; ++i)
1253  {
1254  unsigned short* p = &mesh.polys[i*2*nvp];
1255  for (int j = 0; j < nvp; ++j)
1256  {
1257  if (p[j] == RC_MESH_NULL_IDX) break;
1258  // Skip connected edges.
1259  if (p[nvp+j] != RC_MESH_NULL_IDX)
1260  continue;
1261  int nj = j+1;
1262  if (nj >= nvp || p[nj] == RC_MESH_NULL_IDX) nj = 0;
1263  const unsigned short* va = &mesh.verts[p[j]*3];
1264  const unsigned short* vb = &mesh.verts[p[nj]*3];
1265 
1266  if ((int)va[0] == 0 && (int)vb[0] == 0)
1267  p[nvp+j] = 0x8000 | 0;
1268  else if ((int)va[2] == h && (int)vb[2] == h)
1269  p[nvp+j] = 0x8000 | 1;
1270  else if ((int)va[0] == w && (int)vb[0] == w)
1271  p[nvp+j] = 0x8000 | 2;
1272  else if ((int)va[2] == 0 && (int)vb[2] == 0)
1273  p[nvp+j] = 0x8000 | 3;
1274  }
1275  }
1276  }
1277 
1278  // Just allocate the mesh flags array. The user is resposible to fill it.
1279  mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*mesh.npolys, RC_ALLOC_PERM);
1280  if (!mesh.flags)
1281  {
1282  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.flags' (%d).", mesh.npolys);
1283  return false;
1284  }
1285  memset(mesh.flags, 0, sizeof(unsigned short) * mesh.npolys);
1286 
1287  if (mesh.nverts > 0xffff)
1288  {
1289  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: The resulting mesh has too many vertices %d (max %d). Data can be corrupted.", mesh.nverts, 0xffff);
1290  }
1291  if (mesh.npolys > 0xffff)
1292  {
1293  ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff);
1294  }
1295 
1297 
1298  return true;
1299 }
unsigned char * areas
The area id assigned to each polygon. [Length: maxpolys].
Definition: Recast.h:389
float bmin[3]
The minimum bounds in world space. [(x, y, z)].
Definition: Recast.h:372
#define rcAssert
Definition: RecastAssert.h:30
int nverts
The number of vertices.
Definition: Recast.h:390
static void mergePolys(unsigned short *pa, unsigned short *pb, int ea, int eb, unsigned short *tmp, const int nvp)
Definition: RecastMesh.cpp:531
int nverts
The number of vertices in the simplified contour.
Definition: Recast.h:359
unsigned short * verts
The mesh vertices. [Form: (x, y, z) * nverts].
Definition: Recast.h:385
float ch
The height of each cell. (The minimum increment along the y-axis.)
Definition: Recast.h:397
float bmax[3]
The maximum bounds in world space. [(x, y, z)].
Definition: Recast.h:395
rcContour * conts
An array of the contours in the set. [Size: nconts].
Definition: Recast.h:370
Definition: BnetFileGenerator.h:49
float cs
The size of each cell. (On the xz-plane.)
Definition: Recast.h:396
int height
The height of the set. (Along the z-axis in cell units.)
Definition: Recast.h:377
static bool canRemoveVertex(rcContext *ctx, rcPolyMesh &mesh, const unsigned short rem)
Definition: RecastMesh.cpp:564
int nconts
The number of contours in the set.
Definition: Recast.h:371
int * verts
Simplified contour vertex and connection data. [Size: 4 * nverts].
Definition: Recast.h:358
static unsigned short addVertex(unsigned short x, unsigned short y, unsigned short z, unsigned short *verts, int *firstVert, int *nextVert, int &nv)
Definition: RecastMesh.cpp:137
Represents a simple, non-overlapping contour in field space.
Definition: Recast.h:356
An error log entry.
Definition: Recast.h:31
Definition: RecastAlloc.h:105
static int triangulate(int n, const int *verts, int *indices, int *tris)
Definition: RecastMesh.cpp:339
unsigned char area
The area id of the contour.
Definition: Recast.h:363
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
static bool removeVertex(rcContext *ctx, rcPolyMesh &mesh, const unsigned short rem, const int maxTris)
Definition: RecastMesh.cpp:666
static const unsigned short RC_MESH_NULL_IDX
Definition: Recast.h:533
static const int RC_BORDER_VERTEX
Definition: Recast.h:507
float bmax[3]
The maximum bounds in world space. [(x, y, z)].
Definition: Recast.h:373
unsigned short reg
The region id of the contour.
Definition: Recast.h:362
static int getPolyMergeValue(unsigned short *pa, unsigned short *pb, const unsigned short *verts, int &ea, int &eb, const int nvp)
Definition: RecastMesh.cpp:467
void rcVcopy(float *dest, const float *v)
Definition: Recast.h:677
float cs
The size of each cell. (On the xz-plane.)
Definition: Recast.h:374
void startTimer(const rcTimerLabel label)
Definition: Recast.h:131
static bool buildMeshAdjacency(unsigned short *polys, const int npolys, const int nverts, const int vertsPerPoly)
Definition: RecastMesh.cpp:34
Memory will persist after a function call.
Definition: RecastAlloc.h:26
unsigned short * flags
The user defined flags for each polygon. [Length: maxpolys].
Definition: Recast.h:388
int width
The width of the set. (Along the x-axis in cell units.)
Definition: Recast.h:376
The time to build the polygon mesh. (See: rcBuildPolyMesh)
Definition: Recast.h:61
int borderSize
The AABB border size used to generate the source data from which the mesh was derived.
Definition: Recast.h:398
Memory used temporarily within a function.
Definition: RecastAlloc.h:27
T rcMax(T a, T b)
Definition: Recast.h:572
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
static const int VERTEX_BUCKET_COUNT
Definition: RecastMesh.cpp:126
int borderSize
The AABB border size used to generate the source data from which the contours were derived...
Definition: Recast.h:378
float ch
The height of each cell. (The minimum increment along the y-axis.)
Definition: Recast.h:375
int npolys
The number of polygons.
Definition: Recast.h:391
void stopTimer(const rcTimerLabel label)
Definition: Recast.h:135
int maxpolys
The number of allocated polygons.
Definition: Recast.h:392
unsigned short * regs
The region id assigned to each polygon. [Length: maxpolys].
Definition: Recast.h:387
A warning log entry.
Definition: Recast.h:30
float bmin[3]
The minimum bounds in world space. [(x, y, z)].
Definition: Recast.h:394
int nvp
The maximum number of vertices per polygon.
Definition: Recast.h:393
unsigned short * polys
Polygon and neighbor data. [Length: maxpolys * 2 * nvp].
Definition: Recast.h:386

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool rcCopyPolyMesh ( rcContext ctx,
const rcPolyMesh src,
rcPolyMesh dst 
)

Copies the poly mesh data from src to dst.

Parameters
[in,out]ctxThe build context to use during the operation.
[in]srcThe source mesh to copy from.
[out]dstThe resulting detail mesh. (Must be pre-allocated, must be empty mesh.)
Returns
True if the operation completed successfully.
1483 {
1484  rcAssert(ctx);
1485 
1486  // Destination must be empty.
1487  rcAssert(dst.verts == 0);
1488  rcAssert(dst.polys == 0);
1489  rcAssert(dst.regs == 0);
1490  rcAssert(dst.areas == 0);
1491  rcAssert(dst.flags == 0);
1492 
1493  dst.nverts = src.nverts;
1494  dst.npolys = src.npolys;
1495  dst.maxpolys = src.npolys;
1496  dst.nvp = src.nvp;
1497  rcVcopy(dst.bmin, src.bmin);
1498  rcVcopy(dst.bmax, src.bmax);
1499  dst.cs = src.cs;
1500  dst.ch = src.ch;
1501  dst.borderSize = src.borderSize;
1502 
1503  dst.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.nverts*3, RC_ALLOC_PERM);
1504  if (!dst.verts)
1505  {
1506  ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.verts' (%d).", src.nverts*3);
1507  return false;
1508  }
1509  memcpy(dst.verts, src.verts, sizeof(unsigned short)*src.nverts*3);
1510 
1511  dst.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys*2*src.nvp, RC_ALLOC_PERM);
1512  if (!dst.polys)
1513  {
1514  ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.polys' (%d).", src.npolys*2*src.nvp);
1515  return false;
1516  }
1517  memcpy(dst.polys, src.polys, sizeof(unsigned short)*src.npolys*2*src.nvp);
1518 
1519  dst.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys, RC_ALLOC_PERM);
1520  if (!dst.regs)
1521  {
1522  ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.regs' (%d).", src.npolys);
1523  return false;
1524  }
1525  memcpy(dst.regs, src.regs, sizeof(unsigned short)*src.npolys);
1526 
1527  dst.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*src.npolys, RC_ALLOC_PERM);
1528  if (!dst.areas)
1529  {
1530  ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.areas' (%d).", src.npolys);
1531  return false;
1532  }
1533  memcpy(dst.areas, src.areas, sizeof(unsigned char)*src.npolys);
1534 
1535  dst.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys, RC_ALLOC_PERM);
1536  if (!dst.flags)
1537  {
1538  ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.flags' (%d).", src.npolys);
1539  return false;
1540  }
1541  memcpy(dst.flags, src.flags, sizeof(unsigned short)*src.npolys);
1542 
1543  return true;
1544 }
unsigned char * areas
The area id assigned to each polygon. [Length: maxpolys].
Definition: Recast.h:389
#define rcAssert
Definition: RecastAssert.h:30
int nverts
The number of vertices.
Definition: Recast.h:390
unsigned short * verts
The mesh vertices. [Form: (x, y, z) * nverts].
Definition: Recast.h:385
float ch
The height of each cell. (The minimum increment along the y-axis.)
Definition: Recast.h:397
float bmax[3]
The maximum bounds in world space. [(x, y, z)].
Definition: Recast.h:395
float cs
The size of each cell. (On the xz-plane.)
Definition: Recast.h:396
An error log entry.
Definition: Recast.h:31
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
void rcVcopy(float *dest, const float *v)
Definition: Recast.h:677
Memory will persist after a function call.
Definition: RecastAlloc.h:26
unsigned short * flags
The user defined flags for each polygon. [Length: maxpolys].
Definition: Recast.h:388
int borderSize
The AABB border size used to generate the source data from which the mesh was derived.
Definition: Recast.h:398
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
int npolys
The number of polygons.
Definition: Recast.h:391
int maxpolys
The number of allocated polygons.
Definition: Recast.h:392
unsigned short * regs
The region id assigned to each polygon. [Length: maxpolys].
Definition: Recast.h:387
float bmin[3]
The minimum bounds in world space. [(x, y, z)].
Definition: Recast.h:394
int nvp
The maximum number of vertices per polygon.
Definition: Recast.h:393
unsigned short * polys
Polygon and neighbor data. [Length: maxpolys * 2 * nvp].
Definition: Recast.h:386

+ Here is the call graph for this function:

bool rcMergePolyMeshes ( rcContext ctx,
rcPolyMesh **  meshes,
const int  nmeshes,
rcPolyMesh mesh 
)
See also
rcAllocPolyMesh, rcPolyMesh
1303 {
1304  rcAssert(ctx);
1305 
1306  if (!nmeshes || !meshes)
1307  return true;
1308 
1310 
1311  mesh.nvp = meshes[0]->nvp;
1312  mesh.cs = meshes[0]->cs;
1313  mesh.ch = meshes[0]->ch;
1314  rcVcopy(mesh.bmin, meshes[0]->bmin);
1315  rcVcopy(mesh.bmax, meshes[0]->bmax);
1316 
1317  int maxVerts = 0;
1318  int maxPolys = 0;
1319  int maxVertsPerMesh = 0;
1320  for (int i = 0; i < nmeshes; ++i)
1321  {
1322  rcVmin(mesh.bmin, meshes[i]->bmin);
1323  rcVmax(mesh.bmax, meshes[i]->bmax);
1324  maxVertsPerMesh = rcMax(maxVertsPerMesh, meshes[i]->nverts);
1325  maxVerts += meshes[i]->nverts;
1326  maxPolys += meshes[i]->npolys;
1327  }
1328 
1329  mesh.nverts = 0;
1330  mesh.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVerts*3, RC_ALLOC_PERM);
1331  if (!mesh.verts)
1332  {
1333  ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.verts' (%d).", maxVerts*3);
1334  return false;
1335  }
1336 
1337  mesh.npolys = 0;
1338  mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys*2*mesh.nvp, RC_ALLOC_PERM);
1339  if (!mesh.polys)
1340  {
1341  ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.polys' (%d).", maxPolys*2*mesh.nvp);
1342  return false;
1343  }
1344  memset(mesh.polys, 0xff, sizeof(unsigned short)*maxPolys*2*mesh.nvp);
1345 
1346  mesh.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys, RC_ALLOC_PERM);
1347  if (!mesh.regs)
1348  {
1349  ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.regs' (%d).", maxPolys);
1350  return false;
1351  }
1352  memset(mesh.regs, 0, sizeof(unsigned short)*maxPolys);
1353 
1354  mesh.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxPolys, RC_ALLOC_PERM);
1355  if (!mesh.areas)
1356  {
1357  ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.areas' (%d).", maxPolys);
1358  return false;
1359  }
1360  memset(mesh.areas, 0, sizeof(unsigned char)*maxPolys);
1361 
1362  mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys, RC_ALLOC_PERM);
1363  if (!mesh.flags)
1364  {
1365  ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.flags' (%d).", maxPolys);
1366  return false;
1367  }
1368  memset(mesh.flags, 0, sizeof(unsigned short)*maxPolys);
1369 
1370  rcScopedDelete<int> nextVert = (int*)rcAlloc(sizeof(int)*maxVerts, RC_ALLOC_TEMP);
1371  if (!nextVert)
1372  {
1373  ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'nextVert' (%d).", maxVerts);
1374  return false;
1375  }
1376  memset(nextVert, 0, sizeof(int)*maxVerts);
1377 
1378  rcScopedDelete<int> firstVert = (int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP);
1379  if (!firstVert)
1380  {
1381  ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT);
1382  return false;
1383  }
1384  for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i)
1385  firstVert[i] = -1;
1386 
1387  rcScopedDelete<unsigned short> vremap = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVertsPerMesh, RC_ALLOC_PERM);
1388  if (!vremap)
1389  {
1390  ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'vremap' (%d).", maxVertsPerMesh);
1391  return false;
1392  }
1393  memset(vremap, 0, sizeof(unsigned short)*maxVertsPerMesh);
1394 
1395  for (int i = 0; i < nmeshes; ++i)
1396  {
1397  const rcPolyMesh* pmesh = meshes[i];
1398 
1399  const unsigned short ox = (unsigned short)floorf((pmesh->bmin[0]-mesh.bmin[0])/mesh.cs+0.5f);
1400  const unsigned short oz = (unsigned short)floorf((pmesh->bmin[2]-mesh.bmin[2])/mesh.cs+0.5f);
1401 
1402  bool isMinX = (ox == 0);
1403  bool isMinZ = (oz == 0);
1404  bool isMaxX = ((unsigned short)floorf((mesh.bmax[0] - pmesh->bmax[0]) / mesh.cs + 0.5f)) == 0;
1405  bool isMaxZ = ((unsigned short)floorf((mesh.bmax[2] - pmesh->bmax[2]) / mesh.cs + 0.5f)) == 0;
1406  bool isOnBorder = (isMinX || isMinZ || isMaxX || isMaxZ);
1407 
1408  for (int j = 0; j < pmesh->nverts; ++j)
1409  {
1410  unsigned short* v = &pmesh->verts[j*3];
1411  vremap[j] = addVertex(v[0]+ox, v[1], v[2]+oz,
1412  mesh.verts, firstVert, nextVert, mesh.nverts);
1413  }
1414 
1415  for (int j = 0; j < pmesh->npolys; ++j)
1416  {
1417  unsigned short* tgt = &mesh.polys[mesh.npolys*2*mesh.nvp];
1418  unsigned short* src = &pmesh->polys[j*2*mesh.nvp];
1419  mesh.regs[mesh.npolys] = pmesh->regs[j];
1420  mesh.areas[mesh.npolys] = pmesh->areas[j];
1421  mesh.flags[mesh.npolys] = pmesh->flags[j];
1422  mesh.npolys++;
1423  for (int k = 0; k < mesh.nvp; ++k)
1424  {
1425  if (src[k] == RC_MESH_NULL_IDX) break;
1426  tgt[k] = vremap[src[k]];
1427  }
1428 
1429  if (isOnBorder)
1430  {
1431  for (int k = mesh.nvp; k < mesh.nvp * 2; ++k)
1432  {
1433  if (src[k] & 0x8000 && src[k] != 0xffff)
1434  {
1435  unsigned short dir = src[k] & 0xf;
1436  switch (dir)
1437  {
1438  case 0: // Portal x-
1439  if (isMinX)
1440  tgt[k] = src[k];
1441  break;
1442  case 1: // Portal z+
1443  if (isMaxZ)
1444  tgt[k] = src[k];
1445  break;
1446  case 2: // Portal x+
1447  if (isMaxX)
1448  tgt[k] = src[k];
1449  break;
1450  case 3: // Portal z-
1451  if (isMinZ)
1452  tgt[k] = src[k];
1453  break;
1454  }
1455  }
1456  }
1457  }
1458  }
1459  }
1460 
1461  // Calculate adjacency.
1462  if (!buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, mesh.nvp))
1463  {
1464  ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Adjacency failed.");
1465  return false;
1466  }
1467 
1468  if (mesh.nverts > 0xffff)
1469  {
1470  ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: The resulting mesh has too many vertices %d (max %d). Data can be corrupted.", mesh.nverts, 0xffff);
1471  }
1472  if (mesh.npolys > 0xffff)
1473  {
1474  ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff);
1475  }
1476 
1478 
1479  return true;
1480 }
unsigned char * areas
The area id assigned to each polygon. [Length: maxpolys].
Definition: Recast.h:389
#define rcAssert
Definition: RecastAssert.h:30
int nverts
The number of vertices.
Definition: Recast.h:390
The time to merge polygon meshes. (See: rcMergePolyMeshes)
Definition: Recast.h:63
unsigned short * verts
The mesh vertices. [Form: (x, y, z) * nverts].
Definition: Recast.h:385
float ch
The height of each cell. (The minimum increment along the y-axis.)
Definition: Recast.h:397
float bmax[3]
The maximum bounds in world space. [(x, y, z)].
Definition: Recast.h:395
void rcVmin(float *mn, const float *v)
Definition: Recast.h:657
float cs
The size of each cell. (On the xz-plane.)
Definition: Recast.h:396
static unsigned short addVertex(unsigned short x, unsigned short y, unsigned short z, unsigned short *verts, int *firstVert, int *nextVert, int &nv)
Definition: RecastMesh.cpp:137
An error log entry.
Definition: Recast.h:31
Definition: RecastAlloc.h:105
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
static const unsigned short RC_MESH_NULL_IDX
Definition: Recast.h:533
Definition: Recast.h:383
void rcVcopy(float *dest, const float *v)
Definition: Recast.h:677
void startTimer(const rcTimerLabel label)
Definition: Recast.h:131
static bool buildMeshAdjacency(unsigned short *polys, const int npolys, const int nverts, const int vertsPerPoly)
Definition: RecastMesh.cpp:34
Memory will persist after a function call.
Definition: RecastAlloc.h:26
unsigned short * flags
The user defined flags for each polygon. [Length: maxpolys].
Definition: Recast.h:388
Memory used temporarily within a function.
Definition: RecastAlloc.h:27
T rcMax(T a, T b)
Definition: Recast.h:572
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
static const int VERTEX_BUCKET_COUNT
Definition: RecastMesh.cpp:126
int npolys
The number of polygons.
Definition: Recast.h:391
void stopTimer(const rcTimerLabel label)
Definition: Recast.h:135
unsigned short * regs
The region id assigned to each polygon. [Length: maxpolys].
Definition: Recast.h:387
float bmin[3]
The minimum bounds in world space. [(x, y, z)].
Definition: Recast.h:394
int nvp
The maximum number of vertices per polygon.
Definition: Recast.h:393
void rcVmax(float *mx, const float *v)
Definition: Recast.h:667
unsigned short * polys
Polygon and neighbor data. [Length: maxpolys * 2 * nvp].
Definition: Recast.h:386

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool removeVertex ( rcContext ctx,
rcPolyMesh mesh,
const unsigned short  rem,
const int  maxTris 
)
static
667 {
668  const int nvp = mesh.nvp;
669 
670  // Count number of polygons to remove.
671  int numRemovedVerts = 0;
672  for (int i = 0; i < mesh.npolys; ++i)
673  {
674  unsigned short* p = &mesh.polys[i*nvp*2];
675  const int nv = countPolyVerts(p, nvp);
676  for (int j = 0; j < nv; ++j)
677  {
678  if (p[j] == rem)
679  numRemovedVerts++;
680  }
681  }
682 
683  int nedges = 0;
684  rcScopedDelete<int> edges = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp*4, RC_ALLOC_TEMP);
685  if (!edges)
686  {
687  ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'edges' (%d).", numRemovedVerts*nvp*4);
688  return false;
689  }
690 
691  int nhole = 0;
692  rcScopedDelete<int> hole = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP);
693  if (!hole)
694  {
695  ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hole' (%d).", numRemovedVerts*nvp);
696  return false;
697  }
698 
699  int nhreg = 0;
700  rcScopedDelete<int> hreg = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP);
701  if (!hreg)
702  {
703  ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hreg' (%d).", numRemovedVerts*nvp);
704  return false;
705  }
706 
707  int nharea = 0;
708  rcScopedDelete<int> harea = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP);
709  if (!harea)
710  {
711  ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'harea' (%d).", numRemovedVerts*nvp);
712  return false;
713  }
714 
715  for (int i = 0; i < mesh.npolys; ++i)
716  {
717  unsigned short* p = &mesh.polys[i*nvp*2];
718  const int nv = countPolyVerts(p, nvp);
719  bool hasRem = false;
720  for (int j = 0; j < nv; ++j)
721  if (p[j] == rem) hasRem = true;
722  if (hasRem)
723  {
724  // Collect edges which does not touch the removed vertex.
725  for (int j = 0, k = nv-1; j < nv; k = j++)
726  {
727  if (p[j] != rem && p[k] != rem)
728  {
729  int* e = &edges[nedges*4];
730  e[0] = p[k];
731  e[1] = p[j];
732  e[2] = mesh.regs[i];
733  e[3] = mesh.areas[i];
734  nedges++;
735  }
736  }
737  // Remove the polygon.
738  unsigned short* p2 = &mesh.polys[(mesh.npolys-1)*nvp*2];
739  if (p != p2)
740  memcpy(p,p2,sizeof(unsigned short)*nvp);
741  memset(p+nvp,0xff,sizeof(unsigned short)*nvp);
742  mesh.regs[i] = mesh.regs[mesh.npolys-1];
743  mesh.areas[i] = mesh.areas[mesh.npolys-1];
744  mesh.npolys--;
745  --i;
746  }
747  }
748 
749  // Remove vertex.
750  for (int i = (int)rem; i < mesh.nverts - 1; ++i)
751  {
752  mesh.verts[i*3+0] = mesh.verts[(i+1)*3+0];
753  mesh.verts[i*3+1] = mesh.verts[(i+1)*3+1];
754  mesh.verts[i*3+2] = mesh.verts[(i+1)*3+2];
755  }
756  mesh.nverts--;
757 
758  // Adjust indices to match the removed vertex layout.
759  for (int i = 0; i < mesh.npolys; ++i)
760  {
761  unsigned short* p = &mesh.polys[i*nvp*2];
762  const int nv = countPolyVerts(p, nvp);
763  for (int j = 0; j < nv; ++j)
764  if (p[j] > rem) p[j]--;
765  }
766  for (int i = 0; i < nedges; ++i)
767  {
768  if (edges[i*4+0] > rem) edges[i*4+0]--;
769  if (edges[i*4+1] > rem) edges[i*4+1]--;
770  }
771 
772  if (nedges == 0)
773  return true;
774 
775  // Start with one vertex, keep appending connected
776  // segments to the start and end of the hole.
777  pushBack(edges[0], hole, nhole);
778  pushBack(edges[2], hreg, nhreg);
779  pushBack(edges[3], harea, nharea);
780 
781  while (nedges)
782  {
783  bool match = false;
784 
785  for (int i = 0; i < nedges; ++i)
786  {
787  const int ea = edges[i*4+0];
788  const int eb = edges[i*4+1];
789  const int r = edges[i*4+2];
790  const int a = edges[i*4+3];
791  bool add = false;
792  if (hole[0] == eb)
793  {
794  // The segment matches the beginning of the hole boundary.
795  pushFront(ea, hole, nhole);
796  pushFront(r, hreg, nhreg);
797  pushFront(a, harea, nharea);
798  add = true;
799  }
800  else if (hole[nhole-1] == ea)
801  {
802  // The segment matches the end of the hole boundary.
803  pushBack(eb, hole, nhole);
804  pushBack(r, hreg, nhreg);
805  pushBack(a, harea, nharea);
806  add = true;
807  }
808  if (add)
809  {
810  // The edge segment was added, remove it.
811  edges[i*4+0] = edges[(nedges-1)*4+0];
812  edges[i*4+1] = edges[(nedges-1)*4+1];
813  edges[i*4+2] = edges[(nedges-1)*4+2];
814  edges[i*4+3] = edges[(nedges-1)*4+3];
815  --nedges;
816  match = true;
817  --i;
818  }
819  }
820 
821  if (!match)
822  break;
823  }
824 
825  rcScopedDelete<int> tris = (int*)rcAlloc(sizeof(int)*nhole*3, RC_ALLOC_TEMP);
826  if (!tris)
827  {
828  ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tris' (%d).", nhole*3);
829  return false;
830  }
831 
832  rcScopedDelete<int> tverts = (int*)rcAlloc(sizeof(int)*nhole*4, RC_ALLOC_TEMP);
833  if (!tverts)
834  {
835  ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tverts' (%d).", nhole*4);
836  return false;
837  }
838 
839  rcScopedDelete<int> thole = (int*)rcAlloc(sizeof(int)*nhole, RC_ALLOC_TEMP);
840  if (!thole)
841  {
842  ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'thole' (%d).", nhole);
843  return false;
844  }
845 
846  // Generate temp vertex array for triangulation.
847  for (int i = 0; i < nhole; ++i)
848  {
849  const int pi = hole[i];
850  tverts[i*4+0] = mesh.verts[pi*3+0];
851  tverts[i*4+1] = mesh.verts[pi*3+1];
852  tverts[i*4+2] = mesh.verts[pi*3+2];
853  tverts[i*4+3] = 0;
854  thole[i] = i;
855  }
856 
857  // Triangulate the hole.
858  int ntris = triangulate(nhole, &tverts[0], &thole[0], tris);
859  if (ntris < 0)
860  {
861  ntris = -ntris;
862  ctx->log(RC_LOG_WARNING, "removeVertex: triangulate() returned bad results.");
863  }
864 
865  // Merge the hole triangles back to polygons.
866  rcScopedDelete<unsigned short> polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*(ntris+1)*nvp, RC_ALLOC_TEMP);
867  if (!polys)
868  {
869  ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'polys' (%d).", (ntris+1)*nvp);
870  return false;
871  }
872  rcScopedDelete<unsigned short> pregs = (unsigned short*)rcAlloc(sizeof(unsigned short)*ntris, RC_ALLOC_TEMP);
873  if (!pregs)
874  {
875  ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pregs' (%d).", ntris);
876  return false;
877  }
878  rcScopedDelete<unsigned char> pareas = (unsigned char*)rcAlloc(sizeof(unsigned char)*ntris, RC_ALLOC_TEMP);
879  if (!pareas)
880  {
881  ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pareas' (%d).", ntris);
882  return false;
883  }
884 
885  unsigned short* tmpPoly = &polys[ntris*nvp];
886 
887  // Build initial polygons.
888  int npolys = 0;
889  memset(polys, 0xff, ntris*nvp*sizeof(unsigned short));
890  for (int j = 0; j < ntris; ++j)
891  {
892  int* t = &tris[j*3];
893  if (t[0] != t[1] && t[0] != t[2] && t[1] != t[2])
894  {
895  polys[npolys*nvp+0] = (unsigned short)hole[t[0]];
896  polys[npolys*nvp+1] = (unsigned short)hole[t[1]];
897  polys[npolys*nvp+2] = (unsigned short)hole[t[2]];
898  pregs[npolys] = (unsigned short)hreg[t[0]];
899  pareas[npolys] = (unsigned char)harea[t[0]];
900  npolys++;
901  }
902  }
903  if (!npolys)
904  return true;
905 
906  // Merge polygons.
907  if (nvp > 3)
908  {
909  for (;;)
910  {
911  // Find best polygons to merge.
912  int bestMergeVal = 0;
913  int bestPa = 0, bestPb = 0, bestEa = 0, bestEb = 0;
914 
915  for (int j = 0; j < npolys-1; ++j)
916  {
917  unsigned short* pj = &polys[j*nvp];
918  for (int k = j+1; k < npolys; ++k)
919  {
920  unsigned short* pk = &polys[k*nvp];
921  int ea, eb;
922  int v = getPolyMergeValue(pj, pk, mesh.verts, ea, eb, nvp);
923  if (v > bestMergeVal)
924  {
925  bestMergeVal = v;
926  bestPa = j;
927  bestPb = k;
928  bestEa = ea;
929  bestEb = eb;
930  }
931  }
932  }
933 
934  if (bestMergeVal > 0)
935  {
936  // Found best, merge.
937  unsigned short* pa = &polys[bestPa*nvp];
938  unsigned short* pb = &polys[bestPb*nvp];
939  mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp);
940  unsigned short* last = &polys[(npolys-1)*nvp];
941  if (pb != last)
942  memcpy(pb, last, sizeof(unsigned short)*nvp);
943  pregs[bestPb] = pregs[npolys-1];
944  pareas[bestPb] = pareas[npolys-1];
945  npolys--;
946  }
947  else
948  {
949  // Could not merge any polygons, stop.
950  break;
951  }
952  }
953  }
954 
955  // Store polygons.
956  for (int i = 0; i < npolys; ++i)
957  {
958  if (mesh.npolys >= maxTris) break;
959  unsigned short* p = &mesh.polys[mesh.npolys*nvp*2];
960  memset(p,0xff,sizeof(unsigned short)*nvp*2);
961  for (int j = 0; j < nvp; ++j)
962  p[j] = polys[i*nvp+j];
963  mesh.regs[mesh.npolys] = pregs[i];
964  mesh.areas[mesh.npolys] = pareas[i];
965  mesh.npolys++;
966  if (mesh.npolys > maxTris)
967  {
968  ctx->log(RC_LOG_ERROR, "removeVertex: Too many polygons %d (max:%d).", mesh.npolys, maxTris);
969  return false;
970  }
971  }
972 
973  return true;
974 }
unsigned char * areas
The area id assigned to each polygon. [Length: maxpolys].
Definition: Recast.h:389
static int countPolyVerts(const unsigned short *p, const int nvp)
Definition: RecastMesh.cpp:453
int nverts
The number of vertices.
Definition: Recast.h:390
static void mergePolys(unsigned short *pa, unsigned short *pb, int ea, int eb, unsigned short *tmp, const int nvp)
Definition: RecastMesh.cpp:531
unsigned short * verts
The mesh vertices. [Form: (x, y, z) * nverts].
Definition: Recast.h:385
Definition: BnetFileGenerator.h:49
double pi()
Definition: g3dmath.h:147
An error log entry.
Definition: Recast.h:31
Definition: RecastAlloc.h:105
static int triangulate(int n, const int *verts, int *indices, int *tris)
Definition: RecastMesh.cpp:339
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
static void pushBack(int v, int *arr, int &an)
Definition: RecastMesh.cpp:558
static void pushFront(int v, int *arr, int &an)
Definition: RecastMesh.cpp:551
static int getPolyMergeValue(unsigned short *pa, unsigned short *pb, const unsigned short *verts, int &ea, int &eb, const int nvp)
Definition: RecastMesh.cpp:467
Memory used temporarily within a function.
Definition: RecastAlloc.h:27
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
int npolys
The number of polygons.
Definition: Recast.h:391
unsigned short * regs
The region id assigned to each polygon. [Length: maxpolys].
Definition: Recast.h:387
A warning log entry.
Definition: Recast.h:30
int nvp
The maximum number of vertices per polygon.
Definition: Recast.h:393
unsigned short * polys
Polygon and neighbor data. [Length: maxpolys * 2 * nvp].
Definition: Recast.h:386

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int triangulate ( int  n,
const int *  verts,
int *  indices,
int *  tris 
)
static
340 {
341  int ntris = 0;
342  int* dst = tris;
343 
344  // The last bit of the index is used to indicate if the vertex can be removed.
345  for (int i = 0; i < n; i++)
346  {
347  int i1 = next(i, n);
348  int i2 = next(i1, n);
349  if (diagonal(i, i2, n, verts, indices))
350  indices[i1] |= 0x80000000;
351  }
352 
353  while (n > 3)
354  {
355  int minLen = -1;
356  int mini = -1;
357  for (int i = 0; i < n; i++)
358  {
359  int i1 = next(i, n);
360  if (indices[i1] & 0x80000000)
361  {
362  const int* p0 = &verts[(indices[i] & 0x0fffffff) * 4];
363  const int* p2 = &verts[(indices[next(i1, n)] & 0x0fffffff) * 4];
364 
365  int dx = p2[0] - p0[0];
366  int dy = p2[2] - p0[2];
367  int len = dx*dx + dy*dy;
368 
369  if (minLen < 0 || len < minLen)
370  {
371  minLen = len;
372  mini = i;
373  }
374  }
375  }
376 
377  if (mini == -1)
378  {
379  // We might get here because the contour has overlapping segments, like this:
380  //
381  // A o-o=====o---o B
382  // / |C D| \
383  // o o o o
384  // : : : :
385  // We'll try to recover by loosing up the inCone test a bit so that a diagonal
386  // like A-B or C-D can be found and we can continue.
387  minLen = -1;
388  mini = -1;
389  for (int i = 0; i < n; i++)
390  {
391  int i1 = next(i, n);
392  int i2 = next(i1, n);
393  if (diagonalLoose(i, i2, n, verts, indices))
394  {
395  const int* p0 = &verts[(indices[i] & 0x0fffffff) * 4];
396  const int* p2 = &verts[(indices[next(i2, n)] & 0x0fffffff) * 4];
397  int dx = p2[0] - p0[0];
398  int dy = p2[2] - p0[2];
399  int len = dx*dx + dy*dy;
400 
401  if (minLen < 0 || len < minLen)
402  {
403  minLen = len;
404  mini = i;
405  }
406  }
407  }
408  if (mini == -1)
409  {
410  // The contour is messed up. This sometimes happens
411  // if the contour simplification is too aggressive.
412  return -ntris;
413  }
414  }
415 
416  int i = mini;
417  int i1 = next(i, n);
418  int i2 = next(i1, n);
419 
420  *dst++ = indices[i] & 0x0fffffff;
421  *dst++ = indices[i1] & 0x0fffffff;
422  *dst++ = indices[i2] & 0x0fffffff;
423  ntris++;
424 
425  // Removes P[i1] by copying P[i+1]...P[n-1] left one index.
426  n--;
427  for (int k = i1; k < n; k++)
428  indices[k] = indices[k+1];
429 
430  if (i1 >= n) i1 = 0;
431  i = prev(i1,n);
432  // Update diagonal flags.
433  if (diagonal(prev(i, n), i1, n, verts, indices))
434  indices[i] |= 0x80000000;
435  else
436  indices[i] &= 0x0fffffff;
437 
438  if (diagonal(i, next(i1, n), n, verts, indices))
439  indices[i1] |= 0x80000000;
440  else
441  indices[i1] &= 0x0fffffff;
442  }
443 
444  // Append the remaining triangle.
445  *dst++ = indices[0] & 0x0fffffff;
446  *dst++ = indices[1] & 0x0fffffff;
447  *dst++ = indices[2] & 0x0fffffff;
448  ntris++;
449 
450  return ntris;
451 }
static bool diagonalLoose(int i, int j, int n, const int *verts, int *indices)
Definition: RecastMesh.cpp:333
int next(int i, int n)
Definition: RecastMesh.cpp:165
int prev(int i, int n)
Definition: RecastMesh.cpp:164
static bool diagonal(int i, int j, int n, const int *verts, int *indices)
Definition: RecastMesh.cpp:287

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool uleft ( const unsigned short *  a,
const unsigned short *  b,
const unsigned short *  c 
)
inline
462 {
463  return ((int)b[0] - (int)a[0]) * ((int)c[2] - (int)a[2]) -
464  ((int)c[0] - (int)a[0]) * ((int)b[2] - (int)a[2]) < 0;
465 }

+ Here is the caller graph for this function:

static bool vequal ( const int *  a,
const int *  b 
)
static
237 {
238  return a[0] == b[0] && a[2] == b[2];
239 }

+ Here is the caller graph for this function:

bool xorb ( bool  x,
bool  y 
)
inline
177 {
178  return !x ^ !y;
179 }
G3D::int16 y
Definition: Vector2int16.h:38
G3D::int16 x
Definition: Vector2int16.h:37

+ Here is the caller graph for this function:

Variable Documentation

const int VERTEX_BUCKET_COUNT = (1<<12)
static