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

Classes

struct  rcHeightPatch
 

Macros

#define _USE_MATH_DEFINES
 

Enumerations

enum  EdgeValues { EV_UNDEF = -1, EV_HULL = -2 }
 

Functions

float vdot2 (const float *a, const float *b)
 
float vdistSq2 (const float *p, const float *q)
 
float vdist2 (const float *p, const float *q)
 
float vcross2 (const float *p1, const float *p2, const float *p3)
 
static bool circumCircle (const float *p1, const float *p2, const float *p3, float *c, float &r)
 
static float distPtTri (const float *p, const float *a, const float *b, const float *c)
 
static float distancePtSeg (const float *pt, const float *p, const float *q)
 
static float distancePtSeg2d (const float *pt, const float *p, const float *q)
 
static float distToTriMesh (const float *p, const float *verts, const int, const int *tris, const int ntris)
 
static float distToPoly (int nvert, const float *verts, const float *p)
 
static unsigned short getHeight (const float fx, const float fy, const float fz, const float, const float ics, const float ch, const rcHeightPatch &hp)
 
static int findEdge (const int *edges, int nedges, int s, int t)
 
static int addEdge (rcContext *ctx, int *edges, int &nedges, const int maxEdges, int s, int t, int l, int r)
 
static void updateLeftFace (int *e, int s, int t, int f)
 
static int overlapSegSeg2d (const float *a, const float *b, const float *c, const float *d)
 
static bool overlapEdges (const float *pts, const int *edges, int nedges, int s1, int t1)
 
static void completeFacet (rcContext *ctx, const float *pts, int npts, int *edges, int &nedges, const int maxEdges, int &nfaces, int e)
 
static void delaunayHull (rcContext *ctx, const int npts, const float *pts, const int nhull, const int *hull, rcIntArray &tris, rcIntArray &edges)
 
static float polyMinExtent (const float *verts, const int nverts)
 
int prev (int i, int n)
 
int next (int i, int n)
 
static void triangulateHull (const int, const float *verts, const int nhull, const int *hull, rcIntArray &tris)
 
float getJitterX (const int i)
 
float getJitterY (const int i)
 
static bool buildPolyDetail (rcContext *ctx, const float *in, const int nin, const float sampleDist, const float sampleMaxError, const rcCompactHeightfield &chf, const rcHeightPatch &hp, float *verts, int &nverts, rcIntArray &tris, rcIntArray &edges, rcIntArray &samples)
 
static void getHeightDataSeedsFromVertices (const rcCompactHeightfield &chf, const unsigned short *poly, const int npoly, const unsigned short *verts, const int bs, rcHeightPatch &hp, rcIntArray &stack)
 
static void getHeightData (const rcCompactHeightfield &chf, const unsigned short *poly, const int npoly, const unsigned short *verts, const int bs, rcHeightPatch &hp, rcIntArray &stack, int region)
 
static unsigned char getEdgeFlags (const float *va, const float *vb, const float *vpoly, const int npoly)
 
static unsigned char getTriFlags (const float *va, const float *vb, const float *vc, const float *vpoly, const int npoly)
 
bool rcBuildPolyMeshDetail (rcContext *ctx, const rcPolyMesh &mesh, const rcCompactHeightfield &chf, const float sampleDist, const float sampleMaxError, rcPolyMeshDetail &dmesh)
 
bool rcMergePolyMeshDetails (rcContext *ctx, rcPolyMeshDetail **meshes, const int nmeshes, rcPolyMeshDetail &mesh)
 

Variables

static const unsigned RC_UNSET_HEIGHT = 0xffff
 

Macro Definition Documentation

#define _USE_MATH_DEFINES

Enumeration Type Documentation

enum EdgeValues
Enumerator
EV_UNDEF 
EV_HULL 
239 {
240  EV_UNDEF = -1,
241  EV_HULL = -2,
242 };
Definition: RecastMeshDetail.cpp:241
Definition: RecastMeshDetail.cpp:240

Function Documentation

static int addEdge ( rcContext ctx,
int *  edges,
int &  nedges,
const int  maxEdges,
int  s,
int  t,
int  l,
int  r 
)
static
256 {
257  if (nedges >= maxEdges)
258  {
259  ctx->log(RC_LOG_ERROR, "addEdge: Too many edges (%d/%d).", nedges, maxEdges);
260  return EV_UNDEF;
261  }
262 
263  // Add edge if not already in the triangulation.
264  int e = findEdge(edges, nedges, s, t);
265  if (e == EV_UNDEF)
266  {
267  int* edge = &edges[nedges*4];
268  edge[0] = s;
269  edge[1] = t;
270  edge[2] = l;
271  edge[3] = r;
272  return nedges++;
273  }
274  else
275  {
276  return EV_UNDEF;
277  }
278 }
static int findEdge(const int *edges, int nedges, int s, int t)
Definition: RecastMeshDetail.cpp:244
An error log entry.
Definition: Recast.h:31
Definition: RecastMeshDetail.cpp:240
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool buildPolyDetail ( rcContext ctx,
const float *  in,
const int  nin,
const float  sampleDist,
const float  sampleMaxError,
const rcCompactHeightfield chf,
const rcHeightPatch hp,
float *  verts,
int &  nverts,
rcIntArray tris,
rcIntArray edges,
rcIntArray samples 
)
static
596 {
597  static const int MAX_VERTS = 127;
598  static const int MAX_TRIS = 255; // Max tris for delaunay is 2n-2-k (n=num verts, k=num hull verts).
599  static const int MAX_VERTS_PER_EDGE = 32;
600  float edge[(MAX_VERTS_PER_EDGE+1)*3];
601  int hull[MAX_VERTS];
602  int nhull = 0;
603 
604  nverts = 0;
605 
606  for (int i = 0; i < nin; ++i)
607  rcVcopy(&verts[i*3], &in[i*3]);
608  nverts = nin;
609 
610  edges.resize(0);
611  tris.resize(0);
612 
613  const float cs = chf.cs;
614  const float ics = 1.0f/cs;
615 
616  // Calculate minimum extents of the polygon based on input data.
617  float minExtent = polyMinExtent(verts, nverts);
618 
619  // Tessellate outlines.
620  // This is done in separate pass in order to ensure
621  // seamless height values across the ply boundaries.
622  if (sampleDist > 0)
623  {
624  for (int i = 0, j = nin-1; i < nin; j=i++)
625  {
626  const float* vj = &in[j*3];
627  const float* vi = &in[i*3];
628  bool swapped = false;
629  // Make sure the segments are always handled in same order
630  // using lexological sort or else there will be seams.
631  if (fabsf(vj[0]-vi[0]) < 1e-6f)
632  {
633  if (vj[2] > vi[2])
634  {
635  rcSwap(vj,vi);
636  swapped = true;
637  }
638  }
639  else
640  {
641  if (vj[0] > vi[0])
642  {
643  rcSwap(vj,vi);
644  swapped = true;
645  }
646  }
647  // Create samples along the edge.
648  float dx = vi[0] - vj[0];
649  float dy = vi[1] - vj[1];
650  float dz = vi[2] - vj[2];
651  float d = sqrtf(dx*dx + dz*dz);
652  int nn = 1 + (int)floorf(d/sampleDist);
653  if (nn >= MAX_VERTS_PER_EDGE) nn = MAX_VERTS_PER_EDGE-1;
654  if (nverts+nn >= MAX_VERTS)
655  nn = MAX_VERTS-1-nverts;
656 
657  for (int k = 0; k <= nn; ++k)
658  {
659  float u = (float)k/(float)nn;
660  float* pos = &edge[k*3];
661  pos[0] = vj[0] + dx*u;
662  pos[1] = vj[1] + dy*u;
663  pos[2] = vj[2] + dz*u;
664  pos[1] = getHeight(pos[0],pos[1],pos[2], cs, ics, chf.ch, hp)*chf.ch;
665  }
666  // Simplify samples.
667  int idx[MAX_VERTS_PER_EDGE] = {0,nn};
668  int nidx = 2;
669  for (int k = 0; k < nidx-1; )
670  {
671  const int a = idx[k];
672  const int b = idx[k+1];
673  const float* va = &edge[a*3];
674  const float* vb = &edge[b*3];
675  // Find maximum deviation along the segment.
676  float maxd = 0;
677  int maxi = -1;
678  for (int m = a+1; m < b; ++m)
679  {
680  float dev = distancePtSeg(&edge[m*3],va,vb);
681  if (dev > maxd)
682  {
683  maxd = dev;
684  maxi = m;
685  }
686  }
687  // If the max deviation is larger than accepted error,
688  // add new point, else continue to next segment.
689  if (maxi != -1 && maxd > rcSqr(sampleMaxError))
690  {
691  for (int m = nidx; m > k; --m)
692  idx[m] = idx[m-1];
693  idx[k+1] = maxi;
694  nidx++;
695  }
696  else
697  {
698  ++k;
699  }
700  }
701 
702  hull[nhull++] = j;
703  // Add new vertices.
704  if (swapped)
705  {
706  for (int k = nidx-2; k > 0; --k)
707  {
708  rcVcopy(&verts[nverts*3], &edge[idx[k]*3]);
709  hull[nhull++] = nverts;
710  nverts++;
711  }
712  }
713  else
714  {
715  for (int k = 1; k < nidx-1; ++k)
716  {
717  rcVcopy(&verts[nverts*3], &edge[idx[k]*3]);
718  hull[nhull++] = nverts;
719  nverts++;
720  }
721  }
722  }
723  }
724 
725  // If the polygon minimum extent is small (sliver or small triangle), do not try to add internal points.
726  if (minExtent < sampleDist*2)
727  {
728  triangulateHull(nverts, verts, nhull, hull, tris);
729  return true;
730  }
731 
732  // Tessellate the base mesh.
733  // We're using the triangulateHull instead of delaunayHull as it tends to
734  // create a bit better triangulation for long thing triangles when there
735  // are no internal points.
736  triangulateHull(nverts, verts, nhull, hull, tris);
737 
738  if (tris.size() == 0)
739  {
740  // Could not triangulate the poly, make sure there is some valid data there.
741  ctx->log(RC_LOG_WARNING, "buildPolyDetail: Could not triangulate polygon (%d verts).", nverts);
742  return true;
743  }
744 
745  if (sampleDist > 0)
746  {
747  // Create sample locations in a grid.
748  float bmin[3], bmax[3];
749  rcVcopy(bmin, in);
750  rcVcopy(bmax, in);
751  for (int i = 1; i < nin; ++i)
752  {
753  rcVmin(bmin, &in[i*3]);
754  rcVmax(bmax, &in[i*3]);
755  }
756  int x0 = (int)floorf(bmin[0]/sampleDist);
757  int x1 = (int)ceilf(bmax[0]/sampleDist);
758  int z0 = (int)floorf(bmin[2]/sampleDist);
759  int z1 = (int)ceilf(bmax[2]/sampleDist);
760  samples.resize(0);
761  for (int z = z0; z < z1; ++z)
762  {
763  for (int x = x0; x < x1; ++x)
764  {
765  float pt[3];
766  pt[0] = x*sampleDist;
767  pt[1] = (bmax[1]+bmin[1])*0.5f;
768  pt[2] = z*sampleDist;
769  // Make sure the samples are not too close to the edges.
770  if (distToPoly(nin,in,pt) > -sampleDist/2) continue;
771  samples.push(x);
772  samples.push(getHeight(pt[0], pt[1], pt[2], cs, ics, chf.ch, hp));
773  samples.push(z);
774  samples.push(0); // Not added
775  }
776  }
777 
778  // Add the samples starting from the one that has the most
779  // error. The procedure stops when all samples are added
780  // or when the max error is within treshold.
781  const int nsamples = samples.size()/4;
782  for (int iter = 0; iter < nsamples; ++iter)
783  {
784  if (nverts >= MAX_VERTS)
785  break;
786 
787  // Find sample with most error.
788  float bestpt[3] = {0,0,0};
789  float bestd = 0;
790  int besti = -1;
791  for (int i = 0; i < nsamples; ++i)
792  {
793  const int* s = &samples[i*4];
794  if (s[3]) continue; // skip added.
795  float pt[3];
796  // The sample location is jittered to get rid of some bad triangulations
797  // which are cause by symmetrical data from the grid structure.
798  pt[0] = s[0]*sampleDist + getJitterX(i)*cs*0.1f;
799  pt[1] = s[1]*chf.ch;
800  pt[2] = s[2]*sampleDist + getJitterY(i)*cs*0.1f;
801  float d = distToTriMesh(pt, verts, nverts, &tris[0], tris.size()/4);
802  if (d < 0) continue; // did not hit the mesh.
803  if (d > bestd)
804  {
805  bestd = d;
806  besti = i;
807  rcVcopy(bestpt,pt);
808  }
809  }
810  // If the max error is within accepted threshold, stop tesselating.
811  if (bestd <= sampleMaxError || besti == -1)
812  break;
813  // Mark sample as added.
814  samples[besti*4+3] = 1;
815  // Add the new sample point.
816  rcVcopy(&verts[nverts*3],bestpt);
817  nverts++;
818 
819  // Create new triangulation.
820  // TODO: Incremental add instead of full rebuild.
821  edges.resize(0);
822  tris.resize(0);
823  delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges);
824  }
825  }
826 
827  const int ntris = tris.size()/4;
828  if (ntris > MAX_TRIS)
829  {
830  tris.resize(MAX_TRIS*4);
831  ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Shrinking triangle count from %d to max %d.", ntris, MAX_TRIS);
832  }
833 
834  return true;
835 }
static float distToTriMesh(const float *p, const float *verts, const int, const int *tris, const int ntris)
Definition: RecastMeshDetail.cpp:169
static void triangulateHull(const int, const float *verts, const int nhull, const int *hull, rcIntArray &tris)
Definition: RecastMeshDetail.cpp:514
void rcSwap(T &a, T &b)
Definition: Recast.h:560
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
void rcVmin(float *mn, const float *v)
Definition: Recast.h:657
An error log entry.
Definition: Recast.h:31
static float distToPoly(int nvert, const float *verts, const float *p)
Definition: RecastMeshDetail.cpp:185
static float distancePtSeg(const float *pt, const float *p, const float *q)
Definition: RecastMeshDetail.cpp:124
G3D::int16 z
Definition: Vector3int16.h:46
static void delaunayHull(rcContext *ctx, const int npts, const float *pts, const int nhull, const int *hull, rcIntArray &tris, rcIntArray &edges)
Definition: RecastMeshDetail.cpp:413
float getJitterY(const int i)
Definition: RecastMeshDetail.cpp:586
void rcVcopy(float *dest, const float *v)
Definition: Recast.h:677
float getJitterX(const int i)
Definition: RecastMeshDetail.cpp:581
T rcSqr(T a)
Definition: Recast.h:582
float cs
The size of each cell. (On the xz-plane.)
Definition: Recast.h:317
float ch
The height of each cell. (The minimum increment along the y-axis.)
Definition: Recast.h:318
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
G3D::int16 x
Definition: Vector2int16.h:37
static unsigned short getHeight(const float fx, const float fy, const float fz, const float, const float ics, const float ch, const rcHeightPatch &hp)
Definition: RecastMeshDetail.cpp:203
A warning log entry.
Definition: Recast.h:30
static float polyMinExtent(const float *verts, const int nverts)
Definition: RecastMeshDetail.cpp:490
void resize(int n)
Definition: RecastAlloc.cpp:75
void push(int item)
Definition: RecastAlloc.h:83
void rcVmax(float *mx, const float *v)
Definition: Recast.h:667

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool circumCircle ( const float *  p1,
const float *  p2,
const float *  p3,
float *  c,
float &  r 
)
static
69 {
70  static const float EPS = 1e-6f;
71  // Calculate the circle relative to p1, to avoid some precision issues.
72  const float v1[3] = {0,0,0};
73  float v2[3], v3[3];
74  rcVsub(v2, p2,p1);
75  rcVsub(v3, p3,p1);
76 
77  const float cp = vcross2(v1, v2, v3);
78  if (fabsf(cp) > EPS)
79  {
80  const float v1Sq = vdot2(v1,v1);
81  const float v2Sq = vdot2(v2,v2);
82  const float v3Sq = vdot2(v3,v3);
83  c[0] = (v1Sq*(v2[2]-v3[2]) + v2Sq*(v3[2]-v1[2]) + v3Sq*(v1[2]-v2[2])) / (2*cp);
84  c[1] = 0;
85  c[2] = (v1Sq*(v3[0]-v2[0]) + v2Sq*(v1[0]-v3[0]) + v3Sq*(v2[0]-v1[0])) / (2*cp);
86  r = vdist2(c, v1);
87  rcVadd(c, c, p1);
88  return true;
89  }
90 
91  rcVcopy(c, p1);
92  r = 0;
93  return false;
94 }
void rcVadd(float *dest, const float *v1, const float *v2)
Definition: Recast.h:636
float vcross2(const float *p1, const float *p2, const float *p3)
Definition: RecastMeshDetail.cpp:58
float vdist2(const float *p, const float *q)
Definition: RecastMeshDetail.cpp:53
void rcVcopy(float *dest, const float *v)
Definition: Recast.h:677
void rcVsub(float *dest, const float *v1, const float *v2)
Definition: Recast.h:647
float vdot2(const float *a, const float *b)
Definition: RecastMeshDetail.cpp:41

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void completeFacet ( rcContext ctx,
const float *  pts,
int  npts,
int *  edges,
int &  nedges,
const int  maxEdges,
int &  nfaces,
int  e 
)
static
318 {
319  static const float EPS = 1e-5f;
320 
321  int* edge = &edges[e*4];
322 
323  // Cache s and t.
324  int s,t;
325  if (edge[2] == EV_UNDEF)
326  {
327  s = edge[0];
328  t = edge[1];
329  }
330  else if (edge[3] == EV_UNDEF)
331  {
332  s = edge[1];
333  t = edge[0];
334  }
335  else
336  {
337  // Edge already completed.
338  return;
339  }
340 
341  // Find best point on left of edge.
342  int pt = npts;
343  float c[3] = {0,0,0};
344  float r = -1;
345  for (int u = 0; u < npts; ++u)
346  {
347  if (u == s || u == t) continue;
348  if (vcross2(&pts[s*3], &pts[t*3], &pts[u*3]) > EPS)
349  {
350  if (r < 0)
351  {
352  // The circle is not updated yet, do it now.
353  pt = u;
354  circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r);
355  continue;
356  }
357  const float d = vdist2(c, &pts[u*3]);
358  const float tol = 0.001f;
359  if (d > r*(1+tol))
360  {
361  // Outside current circumcircle, skip.
362  continue;
363  }
364  else if (d < r*(1-tol))
365  {
366  // Inside safe circumcircle, update circle.
367  pt = u;
368  circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r);
369  }
370  else
371  {
372  // Inside epsilon circum circle, do extra tests to make sure the edge is valid.
373  // s-u and t-u cannot overlap with s-pt nor t-pt if they exists.
374  if (overlapEdges(pts, edges, nedges, s,u))
375  continue;
376  if (overlapEdges(pts, edges, nedges, t,u))
377  continue;
378  // Edge is valid.
379  pt = u;
380  circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r);
381  }
382  }
383  }
384 
385  // Add new triangle or update edge info if s-t is on hull.
386  if (pt < npts)
387  {
388  // Update face information of edge being completed.
389  updateLeftFace(&edges[e*4], s, t, nfaces);
390 
391  // Add new edge or update face info of old edge.
392  e = findEdge(edges, nedges, pt, s);
393  if (e == EV_UNDEF)
394  addEdge(ctx, edges, nedges, maxEdges, pt, s, nfaces, EV_UNDEF);
395  else
396  updateLeftFace(&edges[e*4], pt, s, nfaces);
397 
398  // Add new edge or update face info of old edge.
399  e = findEdge(edges, nedges, t, pt);
400  if (e == EV_UNDEF)
401  addEdge(ctx, edges, nedges, maxEdges, t, pt, nfaces, EV_UNDEF);
402  else
403  updateLeftFace(&edges[e*4], t, pt, nfaces);
404 
405  nfaces++;
406  }
407  else
408  {
409  updateLeftFace(&edges[e*4], s, t, EV_HULL);
410  }
411 }
static void updateLeftFace(int *e, int s, int t, int f)
Definition: RecastMeshDetail.cpp:280
Definition: RecastMeshDetail.cpp:241
static int findEdge(const int *edges, int nedges, int s, int t)
Definition: RecastMeshDetail.cpp:244
static bool circumCircle(const float *p1, const float *p2, const float *p3, float *c, float &r)
Definition: RecastMeshDetail.cpp:67
float vcross2(const float *p1, const float *p2, const float *p3)
Definition: RecastMeshDetail.cpp:58
float vdist2(const float *p, const float *q)
Definition: RecastMeshDetail.cpp:53
Definition: RecastMeshDetail.cpp:240
static bool overlapEdges(const float *pts, const int *edges, int nedges, int s1, int t1)
Definition: RecastMeshDetail.cpp:302
static int addEdge(rcContext *ctx, int *edges, int &nedges, const int maxEdges, int s, int t, int l, int r)
Definition: RecastMeshDetail.cpp:255

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void delaunayHull ( rcContext ctx,
const int  npts,
const float *  pts,
const int  nhull,
const int *  hull,
rcIntArray tris,
rcIntArray edges 
)
static
416 {
417  int nfaces = 0;
418  int nedges = 0;
419  const int maxEdges = npts*10;
420  edges.resize(maxEdges*4);
421 
422  for (int i = 0, j = nhull-1; i < nhull; j=i++)
423  addEdge(ctx, &edges[0], nedges, maxEdges, hull[j],hull[i], EV_HULL, EV_UNDEF);
424 
425  int currentEdge = 0;
426  while (currentEdge < nedges)
427  {
428  if (edges[currentEdge*4+2] == EV_UNDEF)
429  completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge);
430  if (edges[currentEdge*4+3] == EV_UNDEF)
431  completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge);
432  currentEdge++;
433  }
434 
435  // Create tris
436  tris.resize(nfaces*4);
437  for (int i = 0; i < nfaces*4; ++i)
438  tris[i] = -1;
439 
440  for (int i = 0; i < nedges; ++i)
441  {
442  const int* e = &edges[i*4];
443  if (e[3] >= 0)
444  {
445  // Left face
446  int* t = &tris[e[3]*4];
447  if (t[0] == -1)
448  {
449  t[0] = e[0];
450  t[1] = e[1];
451  }
452  else if (t[0] == e[1])
453  t[2] = e[0];
454  else if (t[1] == e[0])
455  t[2] = e[1];
456  }
457  if (e[2] >= 0)
458  {
459  // Right
460  int* t = &tris[e[2]*4];
461  if (t[0] == -1)
462  {
463  t[0] = e[1];
464  t[1] = e[0];
465  }
466  else if (t[0] == e[0])
467  t[2] = e[1];
468  else if (t[1] == e[1])
469  t[2] = e[0];
470  }
471  }
472 
473  for (int i = 0; i < tris.size()/4; ++i)
474  {
475  int* t = &tris[i*4];
476  if (t[0] == -1 || t[1] == -1 || t[2] == -1)
477  {
478  ctx->log(RC_LOG_WARNING, "delaunayHull: Removing dangling face %d [%d,%d,%d].", i, t[0],t[1],t[2]);
479  t[0] = tris[tris.size()-4];
480  t[1] = tris[tris.size()-3];
481  t[2] = tris[tris.size()-2];
482  t[3] = tris[tris.size()-1];
483  tris.resize(tris.size()-4);
484  --i;
485  }
486  }
487 }
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
Definition: RecastMeshDetail.cpp:241
Definition: RecastMeshDetail.cpp:240
static void completeFacet(rcContext *ctx, const float *pts, int npts, int *edges, int &nedges, const int maxEdges, int &nfaces, int e)
Definition: RecastMeshDetail.cpp:317
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
A warning log entry.
Definition: Recast.h:30
void resize(int n)
Definition: RecastAlloc.cpp:75
static int addEdge(rcContext *ctx, int *edges, int &nedges, const int maxEdges, int s, int t, int l, int r)
Definition: RecastMeshDetail.cpp:255

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static float distancePtSeg ( const float *  pt,
const float *  p,
const float *  q 
)
static
125 {
126  float pqx = q[0] - p[0];
127  float pqy = q[1] - p[1];
128  float pqz = q[2] - p[2];
129  float dx = pt[0] - p[0];
130  float dy = pt[1] - p[1];
131  float dz = pt[2] - p[2];
132  float d = pqx*pqx + pqy*pqy + pqz*pqz;
133  float t = pqx*dx + pqy*dy + pqz*dz;
134  if (d > 0)
135  t /= d;
136  if (t < 0)
137  t = 0;
138  else if (t > 1)
139  t = 1;
140 
141  dx = p[0] + t*pqx - pt[0];
142  dy = p[1] + t*pqy - pt[1];
143  dz = p[2] + t*pqz - pt[2];
144 
145  return dx*dx + dy*dy + dz*dz;
146 }

+ Here is the caller graph for this function:

static float distancePtSeg2d ( const float *  pt,
const float *  p,
const float *  q 
)
static
149 {
150  float pqx = q[0] - p[0];
151  float pqz = q[2] - p[2];
152  float dx = pt[0] - p[0];
153  float dz = pt[2] - p[2];
154  float d = pqx*pqx + pqz*pqz;
155  float t = pqx*dx + pqz*dz;
156  if (d > 0)
157  t /= d;
158  if (t < 0)
159  t = 0;
160  else if (t > 1)
161  t = 1;
162 
163  dx = p[0] + t*pqx - pt[0];
164  dz = p[2] + t*pqz - pt[2];
165 
166  return dx*dx + dz*dz;
167 }

+ Here is the caller graph for this function:

static float distPtTri ( const float *  p,
const float *  a,
const float *  b,
const float *  c 
)
static
97 {
98  float v0[3], v1[3], v2[3];
99  rcVsub(v0, c,a);
100  rcVsub(v1, b,a);
101  rcVsub(v2, p,a);
102 
103  const float dot00 = vdot2(v0, v0);
104  const float dot01 = vdot2(v0, v1);
105  const float dot02 = vdot2(v0, v2);
106  const float dot11 = vdot2(v1, v1);
107  const float dot12 = vdot2(v1, v2);
108 
109  // Compute barycentric coordinates
110  const float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
111  const float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
112  float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
113 
114  // If point lies inside the triangle, return interpolated y-coord.
115  static const float EPS = 1e-4f;
116  if (u >= -EPS && v >= -EPS && (u+v) <= 1+EPS)
117  {
118  const float y = a[1] + v0[1]*u + v1[1]*v;
119  return fabsf(y-p[1]);
120  }
121  return FLT_MAX;
122 }
G3D::int16 y
Definition: Vector2int16.h:38
void rcVsub(float *dest, const float *v1, const float *v2)
Definition: Recast.h:647
float vdot2(const float *a, const float *b)
Definition: RecastMeshDetail.cpp:41

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static float distToPoly ( int  nvert,
const float *  verts,
const float *  p 
)
static
186 {
187 
188  float dmin = FLT_MAX;
189  int i, j, c = 0;
190  for (i = 0, j = nvert-1; i < nvert; j = i++)
191  {
192  const float* vi = &verts[i*3];
193  const float* vj = &verts[j*3];
194  if (((vi[2] > p[2]) != (vj[2] > p[2])) &&
195  (p[0] < (vj[0]-vi[0]) * (p[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) )
196  c = !c;
197  dmin = rcMin(dmin, distancePtSeg2d(p, vj, vi));
198  }
199  return c ? -dmin : dmin;
200 }
T rcMin(T a, T b)
Definition: Recast.h:566
static float distancePtSeg2d(const float *pt, const float *p, const float *q)
Definition: RecastMeshDetail.cpp:148

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static float distToTriMesh ( const float *  p,
const float *  verts,
const int  ,
const int *  tris,
const int  ntris 
)
static
170 {
171  float dmin = FLT_MAX;
172  for (int i = 0; i < ntris; ++i)
173  {
174  const float* va = &verts[tris[i*4+0]*3];
175  const float* vb = &verts[tris[i*4+1]*3];
176  const float* vc = &verts[tris[i*4+2]*3];
177  float d = distPtTri(p, va,vb,vc);
178  if (d < dmin)
179  dmin = d;
180  }
181  if (dmin == FLT_MAX) return -1;
182  return dmin;
183 }
static float distPtTri(const float *p, const float *a, const float *b, const float *c)
Definition: RecastMeshDetail.cpp:96

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int findEdge ( const int *  edges,
int  nedges,
int  s,
int  t 
)
static
245 {
246  for (int i = 0; i < nedges; i++)
247  {
248  const int* e = &edges[i*4];
249  if ((e[0] == s && e[1] == t) || (e[0] == t && e[1] == s))
250  return i;
251  }
252  return EV_UNDEF;
253 }
Definition: RecastMeshDetail.cpp:240

+ Here is the caller graph for this function:

static unsigned char getEdgeFlags ( const float *  va,
const float *  vb,
const float *  vpoly,
const int  npoly 
)
static
1090 {
1091  // Return true if edge (va,vb) is part of the polygon.
1092  static const float thrSqr = rcSqr(0.001f);
1093  for (int i = 0, j = npoly-1; i < npoly; j=i++)
1094  {
1095  if (distancePtSeg2d(va, &vpoly[j*3], &vpoly[i*3]) < thrSqr &&
1096  distancePtSeg2d(vb, &vpoly[j*3], &vpoly[i*3]) < thrSqr)
1097  return 1;
1098  }
1099  return 0;
1100 }
T rcSqr(T a)
Definition: Recast.h:582
static float distancePtSeg2d(const float *pt, const float *p, const float *q)
Definition: RecastMeshDetail.cpp:148

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static unsigned short getHeight ( const float  fx,
const float  fy,
const float  fz,
const float  ,
const float  ics,
const float  ch,
const rcHeightPatch hp 
)
static
206 {
207  int ix = (int)floorf(fx*ics + 0.01f);
208  int iz = (int)floorf(fz*ics + 0.01f);
209  ix = rcClamp(ix-hp.xmin, 0, hp.width - 1);
210  iz = rcClamp(iz-hp.ymin, 0, hp.height - 1);
211  unsigned short h = hp.data[ix+iz*hp.width];
212  if (h == RC_UNSET_HEIGHT)
213  {
214  // Special case when data might be bad.
215  // Find nearest neighbour pixel which has valid height.
216  const int off[8*2] = { -1,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1};
217  float dmin = FLT_MAX;
218  for (int i = 0; i < 8; ++i)
219  {
220  const int nx = ix+off[i*2+0];
221  const int nz = iz+off[i*2+1];
222  if (nx < 0 || nz < 0 || nx >= hp.width || nz >= hp.height) continue;
223  const unsigned short nh = hp.data[nx+nz*hp.width];
224  if (nh == RC_UNSET_HEIGHT) continue;
225 
226  const float d = fabsf(nh*ch - fy);
227  if (d < dmin)
228  {
229  h = nh;
230  dmin = d;
231  }
232  }
233  }
234  return h;
235 }
int xmin
Definition: RecastMeshDetail.cpp:37
int height
Definition: RecastMeshDetail.cpp:37
int width
Definition: RecastMeshDetail.cpp:37
T rcClamp(T v, T mn, T mx)
Definition: Recast.h:589
unsigned short * data
Definition: RecastMeshDetail.cpp:36
int ymin
Definition: RecastMeshDetail.cpp:37
static const unsigned RC_UNSET_HEIGHT
Definition: RecastMeshDetail.cpp:30

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void getHeightData ( const rcCompactHeightfield chf,
const unsigned short *  poly,
const int  npoly,
const unsigned short *  verts,
const int  bs,
rcHeightPatch hp,
rcIntArray stack,
int  region 
)
static
981 {
982  // Note: Reads to the compact heightfield are offset by border size (bs)
983  // since border size offset is already removed from the polymesh vertices.
984 
985  stack.resize(0);
986  memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height);
987 
988  bool empty = true;
989 
990  // Copy the height from the same region, and mark region borders
991  // as seed points to fill the rest.
992  for (int hy = 0; hy < hp.height; hy++)
993  {
994  int y = hp.ymin + hy + bs;
995  for (int hx = 0; hx < hp.width; hx++)
996  {
997  int x = hp.xmin + hx + bs;
998  const rcCompactCell& c = chf.cells[x+y*chf.width];
999  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
1000  {
1001  const rcCompactSpan& s = chf.spans[i];
1002  if (s.reg == region)
1003  {
1004  // Store height
1005  hp.data[hx + hy*hp.width] = s.y;
1006  empty = false;
1007 
1008  // If any of the neighbours is not in same region,
1009  // add the current location as flood fill start
1010  bool border = false;
1011  for (int dir = 0; dir < 4; ++dir)
1012  {
1013  if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
1014  {
1015  const int ax = x + rcGetDirOffsetX(dir);
1016  const int ay = y + rcGetDirOffsetY(dir);
1017  const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir);
1018  const rcCompactSpan& as = chf.spans[ai];
1019  if (as.reg != region)
1020  {
1021  border = true;
1022  break;
1023  }
1024  }
1025  }
1026  if (border)
1027  {
1028  stack.push(x);
1029  stack.push(y);
1030  stack.push(i);
1031  }
1032  break;
1033  }
1034  }
1035  }
1036  }
1037 
1038  // if the polygon does not contian any points from the current region (rare, but happens)
1039  // then use the cells closest to the polygon vertices as seeds to fill the height field
1040  if (empty)
1041  getHeightDataSeedsFromVertices(chf, poly, npoly, verts, bs, hp, stack);
1042 
1043  static const int RETRACT_SIZE = 256;
1044  int head = 0;
1045 
1046  while (head*3 < stack.size())
1047  {
1048  int cx = stack[head*3+0];
1049  int cy = stack[head*3+1];
1050  int ci = stack[head*3+2];
1051  head++;
1052  if (head >= RETRACT_SIZE)
1053  {
1054  head = 0;
1055  if (stack.size() > RETRACT_SIZE*3)
1056  memmove(&stack[0], &stack[RETRACT_SIZE*3], sizeof(int)*(stack.size()-RETRACT_SIZE*3));
1057  stack.resize(stack.size()-RETRACT_SIZE*3);
1058  }
1059 
1060  const rcCompactSpan& cs = chf.spans[ci];
1061  for (int dir = 0; dir < 4; ++dir)
1062  {
1063  if (rcGetCon(cs, dir) == RC_NOT_CONNECTED) continue;
1064 
1065  const int ax = cx + rcGetDirOffsetX(dir);
1066  const int ay = cy + rcGetDirOffsetY(dir);
1067  const int hx = ax - hp.xmin - bs;
1068  const int hy = ay - hp.ymin - bs;
1069 
1070  if (hx < 0 || hx >= hp.width || hy < 0 || hy >= hp.height)
1071  continue;
1072 
1073  if (hp.data[hx + hy*hp.width] != RC_UNSET_HEIGHT)
1074  continue;
1075 
1076  const int ai = (int)chf.cells[ax + ay*chf.width].index + rcGetCon(cs, dir);
1077  const rcCompactSpan& as = chf.spans[ai];
1078 
1079  hp.data[hx + hy*hp.width] = as.y;
1080 
1081  stack.push(ax);
1082  stack.push(ay);
1083  stack.push(ai);
1084  }
1085  }
1086 }
int xmin
Definition: RecastMeshDetail.cpp:37
Represents a span of unobstructed space within a compact heightfield.
Definition: Recast.h:295
static const int RC_NOT_CONNECTED
Definition: Recast.h:547
unsigned short reg
The id of the region the span belongs to. (Or zero if not in a region.)
Definition: Recast.h:298
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
int rcGetDirOffsetY(int dir)
Definition: Recast.h:1048
unsigned short y
The lower extent of the span. (Measured from the heightfield's base.)
Definition: Recast.h:297
rcCompactSpan * spans
Array of spans. [Size: spanCount].
Definition: Recast.h:320
int rcGetCon(const rcCompactSpan &s, int dir)
Definition: Recast.h:1028
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
Provides information on the content of a cell column in a compact heightfield.
Definition: Recast.h:288
static void getHeightDataSeedsFromVertices(const rcCompactHeightfield &chf, const unsigned short *poly, const int npoly, const unsigned short *verts, const int bs, rcHeightPatch &hp, rcIntArray &stack)
Definition: RecastMeshDetail.cpp:838
unsigned int count
Number of spans in the column.
Definition: Recast.h:291
int rcGetDirOffsetX(int dir)
Definition: Recast.h:1038
int height
Definition: RecastMeshDetail.cpp:37
int width
Definition: RecastMeshDetail.cpp:37
G3D::int16 y
Definition: Vector2int16.h:38
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
unsigned short * data
Definition: RecastMeshDetail.cpp:36
int ymin
Definition: RecastMeshDetail.cpp:37
G3D::int16 x
Definition: Vector2int16.h:37
static const unsigned RC_UNSET_HEIGHT
Definition: RecastMeshDetail.cpp:30
void resize(int n)
Definition: RecastAlloc.cpp:75
void push(int item)
Definition: RecastAlloc.h:83

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void getHeightDataSeedsFromVertices ( const rcCompactHeightfield chf,
const unsigned short *  poly,
const int  npoly,
const unsigned short *  verts,
const int  bs,
rcHeightPatch hp,
rcIntArray stack 
)
static
842 {
843  // Floodfill the heightfield to get 2D height data,
844  // starting at vertex locations as seeds.
845 
846  // Note: Reads to the compact heightfield are offset by border size (bs)
847  // since border size offset is already removed from the polymesh vertices.
848 
849  memset(hp.data, 0, sizeof(unsigned short)*hp.width*hp.height);
850 
851  stack.resize(0);
852 
853  static const int offset[9*2] =
854  {
855  0,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1, -1,0,
856  };
857 
858  // Use poly vertices as seed points for the flood fill.
859  for (int j = 0; j < npoly; ++j)
860  {
861  int cx = 0, cz = 0, ci =-1;
862  int dmin = RC_UNSET_HEIGHT;
863  for (int k = 0; k < 9; ++k)
864  {
865  const int ax = (int)verts[poly[j]*3+0] + offset[k*2+0];
866  const int ay = (int)verts[poly[j]*3+1];
867  const int az = (int)verts[poly[j]*3+2] + offset[k*2+1];
868  if (ax < hp.xmin || ax >= hp.xmin+hp.width ||
869  az < hp.ymin || az >= hp.ymin+hp.height)
870  continue;
871 
872  const rcCompactCell& c = chf.cells[(ax+bs)+(az+bs)*chf.width];
873  for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
874  {
875  const rcCompactSpan& s = chf.spans[i];
876  int d = rcAbs(ay - (int)s.y);
877  if (d < dmin)
878  {
879  cx = ax;
880  cz = az;
881  ci = i;
882  dmin = d;
883  }
884  }
885  }
886  if (ci != -1)
887  {
888  stack.push(cx);
889  stack.push(cz);
890  stack.push(ci);
891  }
892  }
893 
894  // Find center of the polygon using flood fill.
895  int pcx = 0, pcz = 0;
896  for (int j = 0; j < npoly; ++j)
897  {
898  pcx += (int)verts[poly[j]*3+0];
899  pcz += (int)verts[poly[j]*3+2];
900  }
901  pcx /= npoly;
902  pcz /= npoly;
903 
904  for (int i = 0; i < stack.size(); i += 3)
905  {
906  int cx = stack[i+0];
907  int cy = stack[i+1];
908  int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width;
909  hp.data[idx] = 1;
910  }
911 
912  while (stack.size() > 0)
913  {
914  int ci = stack.pop();
915  int cy = stack.pop();
916  int cx = stack.pop();
917 
918  // Check if close to center of the polygon.
919  if (rcAbs(cx-pcx) <= 1 && rcAbs(cy-pcz) <= 1)
920  {
921  stack.resize(0);
922  stack.push(cx);
923  stack.push(cy);
924  stack.push(ci);
925  break;
926  }
927 
928  const rcCompactSpan& cs = chf.spans[ci];
929 
930  for (int dir = 0; dir < 4; ++dir)
931  {
932  if (rcGetCon(cs, dir) == RC_NOT_CONNECTED) continue;
933 
934  const int ax = cx + rcGetDirOffsetX(dir);
935  const int ay = cy + rcGetDirOffsetY(dir);
936 
937  if (ax < hp.xmin || ax >= (hp.xmin+hp.width) ||
938  ay < hp.ymin || ay >= (hp.ymin+hp.height))
939  continue;
940 
941  if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != 0)
942  continue;
943 
944  const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir);
945 
946  int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width;
947  hp.data[idx] = 1;
948 
949  stack.push(ax);
950  stack.push(ay);
951  stack.push(ai);
952  }
953  }
954 
955  memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height);
956 
957  // Mark start locations.
958  for (int i = 0; i < stack.size(); i += 3)
959  {
960  int cx = stack[i+0];
961  int cy = stack[i+1];
962  int ci = stack[i+2];
963  int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width;
964  const rcCompactSpan& cs = chf.spans[ci];
965  hp.data[idx] = cs.y;
966 
967  // getHeightData seeds are given in coordinates with borders
968  stack[i+0] += bs;
969  stack[i+1] += bs;
970  }
971 
972 }
int xmin
Definition: RecastMeshDetail.cpp:37
T rcAbs(T a)
Definition: Recast.h:577
Represents a span of unobstructed space within a compact heightfield.
Definition: Recast.h:295
static const int RC_NOT_CONNECTED
Definition: Recast.h:547
rcCompactCell * cells
Array of cells. [Size: width*height].
Definition: Recast.h:319
int size() const
The current size of the integer array.
Definition: RecastAlloc.h:100
int rcGetDirOffsetY(int dir)
Definition: Recast.h:1048
unsigned short y
The lower extent of the span. (Measured from the heightfield's base.)
Definition: Recast.h:297
rcCompactSpan * spans
Array of spans. [Size: spanCount].
Definition: Recast.h:320
int rcGetCon(const rcCompactSpan &s, int dir)
Definition: Recast.h:1028
unsigned int index
Index to the first span in the column.
Definition: Recast.h:290
Provides information on the content of a cell column in a compact heightfield.
Definition: Recast.h:288
unsigned int count
Number of spans in the column.
Definition: Recast.h:291
int rcGetDirOffsetX(int dir)
Definition: Recast.h:1038
int height
Definition: RecastMeshDetail.cpp:37
int width
Definition: RecastMeshDetail.cpp:37
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
int pop()
Definition: RecastAlloc.h:87
unsigned short * data
Definition: RecastMeshDetail.cpp:36
int ymin
Definition: RecastMeshDetail.cpp:37
static const unsigned RC_UNSET_HEIGHT
Definition: RecastMeshDetail.cpp:30
void resize(int n)
Definition: RecastAlloc.cpp:75
void push(int item)
Definition: RecastAlloc.h:83

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

float getJitterX ( const int  i)
inline
582 {
583  return (((i * 0x8da6b343) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
584 }

+ Here is the caller graph for this function:

float getJitterY ( const int  i)
inline
587 {
588  return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
589 }

+ Here is the caller graph for this function:

static unsigned char getTriFlags ( const float *  va,
const float *  vb,
const float *  vc,
const float *  vpoly,
const int  npoly 
)
static
1104 {
1105  unsigned char flags = 0;
1106  flags |= getEdgeFlags(va,vb,vpoly,npoly) << 0;
1107  flags |= getEdgeFlags(vb,vc,vpoly,npoly) << 2;
1108  flags |= getEdgeFlags(vc,va,vpoly,npoly) << 4;
1109  return flags;
1110 }
static unsigned char getEdgeFlags(const float *va, const float *vb, const float *vpoly, const int npoly)
Definition: RecastMeshDetail.cpp:1088
uint8 flags
Definition: DisableMgr.cpp:44

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

+ Here is the caller graph for this function:

static bool overlapEdges ( const float *  pts,
const int *  edges,
int  nedges,
int  s1,
int  t1 
)
static
303 {
304  for (int i = 0; i < nedges; ++i)
305  {
306  const int s0 = edges[i*4+0];
307  const int t0 = edges[i*4+1];
308  // Same or connected edges do not overlap.
309  if (s0 == s1 || s0 == t1 || t0 == s1 || t0 == t1)
310  continue;
311  if (overlapSegSeg2d(&pts[s0*3],&pts[t0*3], &pts[s1*3],&pts[t1*3]))
312  return true;
313  }
314  return false;
315 }
static int overlapSegSeg2d(const float *a, const float *b, const float *c, const float *d)
Definition: RecastMeshDetail.cpp:288

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int overlapSegSeg2d ( const float *  a,
const float *  b,
const float *  c,
const float *  d 
)
static
289 {
290  const float a1 = vcross2(a, b, d);
291  const float a2 = vcross2(a, b, c);
292  if (a1*a2 < 0.0f)
293  {
294  float a3 = vcross2(c, d, a);
295  float a4 = a3 + a2 - a1;
296  if (a3 * a4 < 0.0f)
297  return 1;
298  }
299  return 0;
300 }
float vcross2(const float *p1, const float *p2, const float *p3)
Definition: RecastMeshDetail.cpp:58

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static float polyMinExtent ( const float *  verts,
const int  nverts 
)
static
491 {
492  float minDist = FLT_MAX;
493  for (int i = 0; i < nverts; i++)
494  {
495  const int ni = (i+1) % nverts;
496  const float* p1 = &verts[i*3];
497  const float* p2 = &verts[ni*3];
498  float maxEdgeDist = 0;
499  for (int j = 0; j < nverts; j++)
500  {
501  if (j == i || j == ni) continue;
502  float d = distancePtSeg2d(&verts[j*3], p1,p2);
503  maxEdgeDist = rcMax(maxEdgeDist, d);
504  }
505  minDist = rcMin(minDist, maxEdgeDist);
506  }
507  return rcSqrt(minDist);
508 }
float rcSqrt(float x)
Definition: Recast.cpp:30
T rcMin(T a, T b)
Definition: Recast.h:566
T rcMax(T a, T b)
Definition: Recast.h:572
static float distancePtSeg2d(const float *pt, const float *p, const float *q)
Definition: RecastMeshDetail.cpp:148

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

+ Here is the caller graph for this function:

bool rcBuildPolyMeshDetail ( rcContext ctx,
const rcPolyMesh mesh,
const rcCompactHeightfield chf,
const float  sampleDist,
const float  sampleMaxError,
rcPolyMeshDetail dmesh 
)

See the rcConfig documentation for more information on the configuration parameters.

See also
rcAllocPolyMeshDetail, rcPolyMesh, rcCompactHeightfield, rcPolyMeshDetail, rcConfig
1120 {
1121  rcAssert(ctx);
1122 
1124 
1125  if (mesh.nverts == 0 || mesh.npolys == 0)
1126  return true;
1127 
1128  const int nvp = mesh.nvp;
1129  const float cs = mesh.cs;
1130  const float ch = mesh.ch;
1131  const float* orig = mesh.bmin;
1132  const int borderSize = mesh.borderSize;
1133 
1134  rcIntArray edges(64);
1135  rcIntArray tris(512);
1136  rcIntArray stack(512);
1137  rcIntArray samples(512);
1138  float verts[256*3];
1139  rcHeightPatch hp;
1140  int nPolyVerts = 0;
1141  int maxhw = 0, maxhh = 0;
1142 
1143  rcScopedDelete<int> bounds = (int*)rcAlloc(sizeof(int)*mesh.npolys*4, RC_ALLOC_TEMP);
1144  if (!bounds)
1145  {
1146  ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'bounds' (%d).", mesh.npolys*4);
1147  return false;
1148  }
1149  rcScopedDelete<float> poly = (float*)rcAlloc(sizeof(float)*nvp*3, RC_ALLOC_TEMP);
1150  if (!poly)
1151  {
1152  ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'poly' (%d).", nvp*3);
1153  return false;
1154  }
1155 
1156  // Find max size for a polygon area.
1157  for (int i = 0; i < mesh.npolys; ++i)
1158  {
1159  const unsigned short* p = &mesh.polys[i*nvp*2];
1160  int& xmin = bounds[i*4+0];
1161  int& xmax = bounds[i*4+1];
1162  int& ymin = bounds[i*4+2];
1163  int& ymax = bounds[i*4+3];
1164  xmin = chf.width;
1165  xmax = 0;
1166  ymin = chf.height;
1167  ymax = 0;
1168  for (int j = 0; j < nvp; ++j)
1169  {
1170  if(p[j] == RC_MESH_NULL_IDX) break;
1171  const unsigned short* v = &mesh.verts[p[j]*3];
1172  xmin = rcMin(xmin, (int)v[0]);
1173  xmax = rcMax(xmax, (int)v[0]);
1174  ymin = rcMin(ymin, (int)v[2]);
1175  ymax = rcMax(ymax, (int)v[2]);
1176  nPolyVerts++;
1177  }
1178  xmin = rcMax(0,xmin-1);
1179  xmax = rcMin(chf.width,xmax+1);
1180  ymin = rcMax(0,ymin-1);
1181  ymax = rcMin(chf.height,ymax+1);
1182  if (xmin >= xmax || ymin >= ymax) continue;
1183  maxhw = rcMax(maxhw, xmax-xmin);
1184  maxhh = rcMax(maxhh, ymax-ymin);
1185  }
1186 
1187  hp.data = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxhw*maxhh, RC_ALLOC_TEMP);
1188  if (!hp.data)
1189  {
1190  ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'hp.data' (%d).", maxhw*maxhh);
1191  return false;
1192  }
1193 
1194  dmesh.nmeshes = mesh.npolys;
1195  dmesh.nverts = 0;
1196  dmesh.ntris = 0;
1197  dmesh.meshes = (unsigned int*)rcAlloc(sizeof(unsigned int)*dmesh.nmeshes*4, RC_ALLOC_PERM);
1198  if (!dmesh.meshes)
1199  {
1200  ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.meshes' (%d).", dmesh.nmeshes*4);
1201  return false;
1202  }
1203 
1204  int vcap = nPolyVerts+nPolyVerts/2;
1205  int tcap = vcap*2;
1206 
1207  dmesh.nverts = 0;
1208  dmesh.verts = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM);
1209  if (!dmesh.verts)
1210  {
1211  ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", vcap*3);
1212  return false;
1213  }
1214  dmesh.ntris = 0;
1215  dmesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char)*tcap*4, RC_ALLOC_PERM);
1216  if (!dmesh.tris)
1217  {
1218  ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", tcap*4);
1219  return false;
1220  }
1221 
1222  for (int i = 0; i < mesh.npolys; ++i)
1223  {
1224  const unsigned short* p = &mesh.polys[i*nvp*2];
1225 
1226  // Store polygon vertices for processing.
1227  int npoly = 0;
1228  for (int j = 0; j < nvp; ++j)
1229  {
1230  if(p[j] == RC_MESH_NULL_IDX) break;
1231  const unsigned short* v = &mesh.verts[p[j]*3];
1232  poly[j*3+0] = v[0]*cs;
1233  poly[j*3+1] = v[1]*ch;
1234  poly[j*3+2] = v[2]*cs;
1235  npoly++;
1236  }
1237 
1238  // Get the height data from the area of the polygon.
1239  hp.xmin = bounds[i*4+0];
1240  hp.ymin = bounds[i*4+2];
1241  hp.width = bounds[i*4+1]-bounds[i*4+0];
1242  hp.height = bounds[i*4+3]-bounds[i*4+2];
1243  getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack, mesh.regs[i]);
1244 
1245  // Build detail mesh.
1246  int nverts = 0;
1247  if (!buildPolyDetail(ctx, poly, npoly,
1248  sampleDist, sampleMaxError,
1249  chf, hp, verts, nverts, tris,
1250  edges, samples))
1251  {
1252  return false;
1253  }
1254 
1255  // Move detail verts to world space.
1256  for (int j = 0; j < nverts; ++j)
1257  {
1258  verts[j*3+0] += orig[0];
1259  verts[j*3+1] += orig[1] + chf.ch; // Is this offset necessary?
1260  verts[j*3+2] += orig[2];
1261  }
1262  // Offset poly too, will be used to flag checking.
1263  for (int j = 0; j < npoly; ++j)
1264  {
1265  poly[j*3+0] += orig[0];
1266  poly[j*3+1] += orig[1];
1267  poly[j*3+2] += orig[2];
1268  }
1269 
1270  // Store detail submesh.
1271  const int ntris = tris.size()/4;
1272 
1273  dmesh.meshes[i*4+0] = (unsigned int)dmesh.nverts;
1274  dmesh.meshes[i*4+1] = (unsigned int)nverts;
1275  dmesh.meshes[i*4+2] = (unsigned int)dmesh.ntris;
1276  dmesh.meshes[i*4+3] = (unsigned int)ntris;
1277 
1278  // Store vertices, allocate more memory if necessary.
1279  if (dmesh.nverts+nverts > vcap)
1280  {
1281  while (dmesh.nverts+nverts > vcap)
1282  vcap += 256;
1283 
1284  float* newv = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM);
1285  if (!newv)
1286  {
1287  ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newv' (%d).", vcap*3);
1288  return false;
1289  }
1290  if (dmesh.nverts)
1291  memcpy(newv, dmesh.verts, sizeof(float)*3*dmesh.nverts);
1292  rcFree(dmesh.verts);
1293  dmesh.verts = newv;
1294  }
1295  for (int j = 0; j < nverts; ++j)
1296  {
1297  dmesh.verts[dmesh.nverts*3+0] = verts[j*3+0];
1298  dmesh.verts[dmesh.nverts*3+1] = verts[j*3+1];
1299  dmesh.verts[dmesh.nverts*3+2] = verts[j*3+2];
1300  dmesh.nverts++;
1301  }
1302 
1303  // Store triangles, allocate more memory if necessary.
1304  if (dmesh.ntris+ntris > tcap)
1305  {
1306  while (dmesh.ntris+ntris > tcap)
1307  tcap += 256;
1308  unsigned char* newt = (unsigned char*)rcAlloc(sizeof(unsigned char)*tcap*4, RC_ALLOC_PERM);
1309  if (!newt)
1310  {
1311  ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newt' (%d).", tcap*4);
1312  return false;
1313  }
1314  if (dmesh.ntris)
1315  memcpy(newt, dmesh.tris, sizeof(unsigned char)*4*dmesh.ntris);
1316  rcFree(dmesh.tris);
1317  dmesh.tris = newt;
1318  }
1319  for (int j = 0; j < ntris; ++j)
1320  {
1321  const int* t = &tris[j*4];
1322  dmesh.tris[dmesh.ntris*4+0] = (unsigned char)t[0];
1323  dmesh.tris[dmesh.ntris*4+1] = (unsigned char)t[1];
1324  dmesh.tris[dmesh.ntris*4+2] = (unsigned char)t[2];
1325  dmesh.tris[dmesh.ntris*4+3] = getTriFlags(&verts[t[0]*3], &verts[t[1]*3], &verts[t[2]*3], poly, npoly);
1326  dmesh.ntris++;
1327  }
1328  }
1329 
1331 
1332  return true;
1333 }
int xmin
Definition: RecastMeshDetail.cpp:37
int height
The height of the heightfield. (Along the z-axis in cell units.)
Definition: Recast.h:308
#define rcAssert
Definition: RecastAssert.h:30
int nverts
The number of vertices.
Definition: Recast.h:390
int ntris
The number of triangles in tris.
Definition: Recast.h:411
unsigned short * verts
The mesh vertices. [Form: (x, y, z) * nverts].
Definition: Recast.h:385
float * verts
The mesh vertices. [Size: 3*nverts].
Definition: Recast.h:407
T rcMin(T a, T b)
Definition: Recast.h:566
float ch
The height of each cell. (The minimum increment along the y-axis.)
Definition: Recast.h:397
float cs
The size of each cell. (On the xz-plane.)
Definition: Recast.h:396
The time to build the polygon mesh detail. (See: rcBuildPolyMeshDetail)
Definition: Recast.h:91
int nmeshes
The number of sub-meshes defined by meshes.
Definition: Recast.h:409
An error log entry.
Definition: Recast.h:31
Definition: RecastAlloc.h:105
static bool buildPolyDetail(rcContext *ctx, const float *in, const int nin, const float sampleDist, const float sampleMaxError, const rcCompactHeightfield &chf, const rcHeightPatch &hp, float *verts, int &nverts, rcIntArray &tris, rcIntArray &edges, rcIntArray &samples)
Definition: RecastMeshDetail.cpp:591
static void getHeightData(const rcCompactHeightfield &chf, const unsigned short *poly, const int npoly, const unsigned short *verts, const int bs, rcHeightPatch &hp, rcIntArray &stack, int region)
Definition: RecastMeshDetail.cpp:976
void rcFree(void *ptr)
Definition: RecastAlloc.cpp:55
unsigned char * tris
The mesh triangles. [Size: 4*ntris].
Definition: Recast.h:408
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
static const unsigned short RC_MESH_NULL_IDX
Definition: Recast.h:533
int height
Definition: RecastMeshDetail.cpp:37
int width
Definition: RecastMeshDetail.cpp:37
int width
The width of the heightfield. (Along the x-axis in cell units.)
Definition: Recast.h:307
static unsigned char getTriFlags(const float *va, const float *vb, const float *vc, const float *vpoly, const int npoly)
Definition: RecastMeshDetail.cpp:1102
void startTimer(const rcTimerLabel label)
Definition: Recast.h:131
Memory will persist after a function call.
Definition: RecastAlloc.h:26
unsigned short * data
Definition: RecastMeshDetail.cpp:36
int ymin
Definition: RecastMeshDetail.cpp:37
int borderSize
The AABB border size used to generate the source data from which the mesh was derived.
Definition: Recast.h:398
float ch
The height of each cell. (The minimum increment along the y-axis.)
Definition: Recast.h:318
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
unsigned int * meshes
The sub-mesh data. [Size: 4*nmeshes].
Definition: Recast.h:406
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
int nverts
The number of vertices in verts.
Definition: Recast.h:410
float bmin[3]
The minimum bounds in world space. [(x, y, z)].
Definition: Recast.h:394
A simple dynamic array of integers.
Definition: RecastAlloc.h:61
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
Definition: RecastMeshDetail.cpp:32

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool rcMergePolyMeshDetails ( rcContext ctx,
rcPolyMeshDetail **  meshes,
const int  nmeshes,
rcPolyMeshDetail mesh 
)
See also
rcAllocPolyMeshDetail, rcPolyMeshDetail
1337 {
1338  rcAssert(ctx);
1339 
1341 
1342  int maxVerts = 0;
1343  int maxTris = 0;
1344  int maxMeshes = 0;
1345 
1346  for (int i = 0; i < nmeshes; ++i)
1347  {
1348  if (!meshes[i]) continue;
1349  maxVerts += meshes[i]->nverts;
1350  maxTris += meshes[i]->ntris;
1351  maxMeshes += meshes[i]->nmeshes;
1352  }
1353 
1354  mesh.nmeshes = 0;
1355  mesh.meshes = (unsigned int*)rcAlloc(sizeof(unsigned int)*maxMeshes*4, RC_ALLOC_PERM);
1356  if (!mesh.meshes)
1357  {
1358  ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'pmdtl.meshes' (%d).", maxMeshes*4);
1359  return false;
1360  }
1361 
1362  mesh.ntris = 0;
1363  mesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris*4, RC_ALLOC_PERM);
1364  if (!mesh.tris)
1365  {
1366  ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", maxTris*4);
1367  return false;
1368  }
1369 
1370  mesh.nverts = 0;
1371  mesh.verts = (float*)rcAlloc(sizeof(float)*maxVerts*3, RC_ALLOC_PERM);
1372  if (!mesh.verts)
1373  {
1374  ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", maxVerts*3);
1375  return false;
1376  }
1377 
1378  // Merge datas.
1379  for (int i = 0; i < nmeshes; ++i)
1380  {
1381  rcPolyMeshDetail* dm = meshes[i];
1382  if (!dm) continue;
1383  for (int j = 0; j < dm->nmeshes; ++j)
1384  {
1385  unsigned int* dst = &mesh.meshes[mesh.nmeshes*4];
1386  unsigned int* src = &dm->meshes[j*4];
1387  dst[0] = (unsigned int)mesh.nverts+src[0];
1388  dst[1] = src[1];
1389  dst[2] = (unsigned int)mesh.ntris+src[2];
1390  dst[3] = src[3];
1391  mesh.nmeshes++;
1392  }
1393 
1394  for (int k = 0; k < dm->nverts; ++k)
1395  {
1396  rcVcopy(&mesh.verts[mesh.nverts*3], &dm->verts[k*3]);
1397  mesh.nverts++;
1398  }
1399  for (int k = 0; k < dm->ntris; ++k)
1400  {
1401  mesh.tris[mesh.ntris*4+0] = dm->tris[k*4+0];
1402  mesh.tris[mesh.ntris*4+1] = dm->tris[k*4+1];
1403  mesh.tris[mesh.ntris*4+2] = dm->tris[k*4+2];
1404  mesh.tris[mesh.ntris*4+3] = dm->tris[k*4+3];
1405  mesh.ntris++;
1406  }
1407  }
1408 
1410 
1411  return true;
1412 }
#define rcAssert
Definition: RecastAssert.h:30
int ntris
The number of triangles in tris.
Definition: Recast.h:411
float * verts
The mesh vertices. [Size: 3*nverts].
Definition: Recast.h:407
int nmeshes
The number of sub-meshes defined by meshes.
Definition: Recast.h:409
An error log entry.
Definition: Recast.h:31
unsigned char * tris
The mesh triangles. [Size: 4*ntris].
Definition: Recast.h:408
void * rcAlloc(int size, rcAllocHint hint)
Definition: RecastAlloc.cpp:44
void rcVcopy(float *dest, const float *v)
Definition: Recast.h:677
void startTimer(const rcTimerLabel label)
Definition: Recast.h:131
Memory will persist after a function call.
Definition: RecastAlloc.h:26
The time to merge polygon mesh details. (See: rcMergePolyMeshDetails)
Definition: Recast.h:93
void log(const rcLogCategory category, const char *format,...)
Definition: Recast.cpp:55
unsigned int * meshes
The sub-mesh data. [Size: 4*nmeshes].
Definition: Recast.h:406
void stopTimer(const rcTimerLabel label)
Definition: Recast.h:135
int nverts
The number of vertices in verts.
Definition: Recast.h:410
Definition: Recast.h:404

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void triangulateHull ( const int  ,
const float *  verts,
const int  nhull,
const int *  hull,
rcIntArray tris 
)
static
515 {
516  int start = 0, left = 1, right = nhull-1;
517 
518  // Start from an ear with shortest perimeter.
519  // This tends to favor well formed triangles as starting point.
520  float dmin = 0;
521  for (int i = 0; i < nhull; i++)
522  {
523  int pi = prev(i, nhull);
524  int ni = next(i, nhull);
525  const float* pv = &verts[hull[pi]*3];
526  const float* cv = &verts[hull[i]*3];
527  const float* nv = &verts[hull[ni]*3];
528  const float d = vdist2(pv,cv) + vdist2(cv,nv) + vdist2(nv,pv);
529  if (d < dmin)
530  {
531  start = i;
532  left = ni;
533  right = pi;
534  dmin = d;
535  }
536  }
537 
538  // Add first triangle
539  tris.push(hull[start]);
540  tris.push(hull[left]);
541  tris.push(hull[right]);
542  tris.push(0);
543 
544  // Triangulate the polygon by moving left or right,
545  // depending on which triangle has shorter perimeter.
546  // This heuristic was chose emprically, since it seems
547  // handle tesselated straight edges well.
548  while (next(left, nhull) != right)
549  {
550  // Check to see if se should advance left or right.
551  int nleft = next(left, nhull);
552  int nright = prev(right, nhull);
553 
554  const float* cvleft = &verts[hull[left]*3];
555  const float* nvleft = &verts[hull[nleft]*3];
556  const float* cvright = &verts[hull[right]*3];
557  const float* nvright = &verts[hull[nright]*3];
558  const float dleft = vdist2(cvleft, nvleft) + vdist2(nvleft, cvright);
559  const float dright = vdist2(cvright, nvright) + vdist2(cvleft, nvright);
560 
561  if (dleft < dright)
562  {
563  tris.push(hull[left]);
564  tris.push(hull[nleft]);
565  tris.push(hull[right]);
566  tris.push(0);
567  left = nleft;
568  }
569  else
570  {
571  tris.push(hull[left]);
572  tris.push(hull[nright]);
573  tris.push(hull[right]);
574  tris.push(0);
575  right = nright;
576  }
577  }
578 }
double pi()
Definition: g3dmath.h:147
float vdist2(const float *p, const float *q)
Definition: RecastMeshDetail.cpp:53
bool left(const int *a, const int *b, const int *c)
Definition: RecastContour.cpp:487
int next(int i, int n)
Definition: RecastMeshDetail.cpp:512
int prev(int i, int n)
Definition: RecastMeshDetail.cpp:511
void push(int item)
Definition: RecastAlloc.h:83

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void updateLeftFace ( int *  e,
int  s,
int  t,
int  f 
)
static
281 {
282  if (e[0] == s && e[1] == t && e[2] == EV_UNDEF)
283  e[2] = f;
284  else if (e[1] == s && e[0] == t && e[3] == EV_UNDEF)
285  e[3] = f;
286 }
Definition: RecastMeshDetail.cpp:240

+ Here is the caller graph for this function:

float vcross2 ( const float *  p1,
const float *  p2,
const float *  p3 
)
inline
59 {
60  const float u1 = p2[0] - p1[0];
61  const float v1 = p2[2] - p1[2];
62  const float u2 = p3[0] - p1[0];
63  const float v2 = p3[2] - p1[2];
64  return u1 * v2 - v1 * u2;
65 }

+ Here is the caller graph for this function:

float vdist2 ( const float *  p,
const float *  q 
)
inline
54 {
55  return sqrtf(vdistSq2(p,q));
56 }
float vdistSq2(const float *p, const float *q)
Definition: RecastMeshDetail.cpp:46

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

float vdistSq2 ( const float *  p,
const float *  q 
)
inline
47 {
48  const float dx = q[0] - p[0];
49  const float dy = q[2] - p[2];
50  return dx*dx + dy*dy;
51 }

+ Here is the caller graph for this function:

float vdot2 ( const float *  a,
const float *  b 
)
inline
42 {
43  return a[0]*b[0] + a[2]*b[2];
44 }

+ Here is the caller graph for this function:

Variable Documentation

const unsigned RC_UNSET_HEIGHT = 0xffff
static