NOTE: Changed the generation procedure, see samples! Erode walkable area before area is generated. Allow to mark areas on chf. Generate regions following areas (+ many fixes here and there to make it alwasy work).
This commit is contained in:
parent
139409c645
commit
9b881bde8c
@ -101,14 +101,14 @@ struct rcCompactHeightfield
|
||||
{
|
||||
inline rcCompactHeightfield() :
|
||||
maxDistance(0), maxRegions(0), cells(0),
|
||||
spans(0), dist(0), reg(0) {}
|
||||
spans(0), dist(0), regs(0), areas(0) {}
|
||||
inline ~rcCompactHeightfield()
|
||||
{
|
||||
delete [] cells;
|
||||
delete [] spans;
|
||||
delete [] dist;
|
||||
delete [] reg;
|
||||
delete [] flags;
|
||||
delete [] regs;
|
||||
delete [] areas;
|
||||
}
|
||||
int width, height; // Width and height of the heighfield.
|
||||
int spanCount; // Number of spans in the heightfield.
|
||||
@ -120,8 +120,8 @@ struct rcCompactHeightfield
|
||||
rcCompactCell* cells; // Pointer to width*height cells.
|
||||
rcCompactSpan* spans; // Pointer to spans.
|
||||
unsigned short* dist; // Pointer to per span distance to border.
|
||||
unsigned short* reg; // Pointer to per span region ID.
|
||||
unsigned short* flags; // Pointer to per span flags.
|
||||
unsigned short* regs; // Pointer to per span region ID.
|
||||
unsigned char* areas; // Pointer to per span area ID.
|
||||
};
|
||||
|
||||
struct rcContour
|
||||
@ -133,6 +133,7 @@ struct rcContour
|
||||
int* rverts; // Raw vertex coordinates, each vertex contains 4 components.
|
||||
int nrverts; // Number of raw vertices.
|
||||
unsigned short reg; // Region ID of the contour.
|
||||
unsigned char area; // Area ID of the contour.
|
||||
};
|
||||
|
||||
struct rcContourSet
|
||||
@ -158,11 +159,14 @@ struct rcContourSet
|
||||
// z = bmin[2] + verts[i*3+2]*cs;
|
||||
struct rcPolyMesh
|
||||
{
|
||||
inline rcPolyMesh() : verts(0), polys(0), regs(0), nverts(0), npolys(0), nvp(3) {}
|
||||
inline ~rcPolyMesh() { delete [] verts; delete [] polys; delete [] regs; }
|
||||
inline rcPolyMesh() : verts(0), polys(0), regs(0), areas(0), nverts(0), npolys(0), nvp(3) {}
|
||||
|
||||
inline ~rcPolyMesh() { delete [] verts; delete [] polys; delete [] regs; delete [] areas; }
|
||||
|
||||
unsigned short* verts; // Vertices of the mesh, 3 elements per vertex.
|
||||
unsigned short* polys; // Polygons of the mesh, nvp*2 elements per polygon.
|
||||
unsigned short* regs; // Regions of the polygons.
|
||||
unsigned short* regs; // Region ID of the polygons.
|
||||
unsigned char* areas; // Area ID of polygons.
|
||||
int nverts; // Number of vertices.
|
||||
int npolys; // Number of polygons.
|
||||
int nvp; // Max number of vertices per polygon.
|
||||
@ -242,12 +246,20 @@ static const unsigned short RC_BORDER_REG = 0x8000;
|
||||
// removed in order to match the segments and vertices at tile boundaries.
|
||||
static const int RC_BORDER_VERTEX = 0x10000;
|
||||
|
||||
static const int RC_AREA_BORDER = 0x20000;
|
||||
|
||||
// Mask used with contours to extract region id.
|
||||
static const int RC_CONTOUR_REG_MASK = 0xffff;
|
||||
|
||||
// Null index which is used with meshes to mark unset or invalid indices.
|
||||
static const unsigned short RC_MESH_NULL_IDX = 0xffff;
|
||||
|
||||
// Area ID that is considered empty.
|
||||
static const unsigned char RC_NULL_AREA = 0;
|
||||
|
||||
// Area ID that is considered generally walkable.
|
||||
static const unsigned char RC_WALKABLE_AREA = 255;
|
||||
|
||||
// Value returned by rcGetCon() if the direction is not connected.
|
||||
static const int RC_NOT_CONNECTED = 0xf;
|
||||
|
||||
@ -496,6 +508,13 @@ bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb
|
||||
rcHeightfield& hf,
|
||||
rcCompactHeightfield& chf);
|
||||
|
||||
bool rcErodeArea(unsigned char areaId, int radius, rcCompactHeightfield& chf);
|
||||
|
||||
bool rcMarkBoxArea(const float* bmin, const float* bmax, unsigned char areaId,
|
||||
rcCompactHeightfield& chf);
|
||||
|
||||
|
||||
|
||||
// Builds distance field and stores it into the combat heightfield.
|
||||
// Params:
|
||||
// chf - (in/out) compact heightfield representing the open space.
|
||||
@ -512,13 +531,11 @@ bool rcBuildDistanceField(rcCompactHeightfield& chf);
|
||||
// removed or merged to neighbour region.
|
||||
// Params:
|
||||
// chf - (in/out) compact heightfield representing the open space.
|
||||
// walkableRadius - (in) the radius of the agent.
|
||||
// minRegionSize - (in) the smallest allowed regions size.
|
||||
// maxMergeRegionSize - (in) the largest allowed regions size which can be merged.
|
||||
// Returns false if operation ran out of memory.
|
||||
bool rcBuildRegions(rcCompactHeightfield& chf,
|
||||
int walkableRadius, int borderSize,
|
||||
int minRegionSize, int mergeRegionSize);
|
||||
int borderSize, int minRegionSize, int mergeRegionSize);
|
||||
|
||||
// Divides the walkable heighfied into simple regions using simple monotone partitioning.
|
||||
// Each region has only one contour and no overlaps.
|
||||
|
@ -58,6 +58,7 @@ struct rcBuildTimes
|
||||
int filterWalkable;
|
||||
int filterMarkReachable;
|
||||
int buildPolymesh;
|
||||
int erodeArea;
|
||||
int buildDistanceField;
|
||||
int buildDistanceFieldDist;
|
||||
int buildDistanceFieldBlur;
|
||||
|
@ -162,14 +162,14 @@ bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb
|
||||
return false;
|
||||
}
|
||||
memset(chf.spans, 0, sizeof(rcCompactSpan)*spanCount);
|
||||
chf.flags = new unsigned short[spanCount];
|
||||
if (!chf.flags)
|
||||
chf.areas = new unsigned char[spanCount];
|
||||
if (!chf.areas)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.flags' (%d)", spanCount);
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount);
|
||||
return false;
|
||||
}
|
||||
memset(chf.flags, 0, sizeof(unsigned short)*spanCount);
|
||||
memset(chf.areas, RC_WALKABLE_AREA, sizeof(unsigned char)*spanCount);
|
||||
|
||||
const int MAX_HEIGHT = 0xffff;
|
||||
|
||||
@ -239,8 +239,6 @@ bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
242
Recast/Source/RecastArea.cpp
Normal file
242
Recast/Source/RecastArea.cpp
Normal file
@ -0,0 +1,242 @@
|
||||
//
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#include <float.h>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "Recast.h"
|
||||
#include "RecastLog.h"
|
||||
#include "RecastTimer.h"
|
||||
|
||||
|
||||
bool rcErodeArea(unsigned char areaId, int radius, rcCompactHeightfield& chf)
|
||||
{
|
||||
const int w = chf.width;
|
||||
const int h = chf.height;
|
||||
|
||||
rcTimeVal startTime = rcGetPerformanceTimer();
|
||||
|
||||
unsigned char* dist = new unsigned char[chf.spanCount];
|
||||
if (!dist)
|
||||
return false;
|
||||
|
||||
// Init distance.
|
||||
memset(dist, 0xff, sizeof(unsigned char)*chf.spanCount);
|
||||
|
||||
// Mark boundary cells.
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const rcCompactCell& c = chf.cells[x+y*w];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
if (chf.areas[i] != RC_NULL_AREA)
|
||||
{
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
int nc = 0;
|
||||
for (int dir = 0; dir < 4; ++dir)
|
||||
{
|
||||
if (rcGetCon(s, dir) != 0xf)
|
||||
{
|
||||
const int ax = x + rcGetDirOffsetX(dir);
|
||||
const int ay = y + rcGetDirOffsetY(dir);
|
||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
|
||||
if (chf.areas[ai] == areaId)
|
||||
nc++;
|
||||
}
|
||||
}
|
||||
// At least one missing neighbour.
|
||||
if (nc != 4)
|
||||
dist[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char nd;
|
||||
|
||||
// Pass 1
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const rcCompactCell& c = chf.cells[x+y*w];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
|
||||
if (rcGetCon(s, 0) != 0xf)
|
||||
{
|
||||
// (-1,0)
|
||||
const int ax = x + rcGetDirOffsetX(0);
|
||||
const int ay = y + rcGetDirOffsetY(0);
|
||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0);
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
nd = (unsigned char)rcMin((int)dist[ai]+2, 255);
|
||||
if (nd < dist[i])
|
||||
dist[i] = nd;
|
||||
|
||||
// (-1,-1)
|
||||
if (rcGetCon(as, 3) != 0xf)
|
||||
{
|
||||
const int aax = ax + rcGetDirOffsetX(3);
|
||||
const int aay = ay + rcGetDirOffsetY(3);
|
||||
const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 3);
|
||||
nd = (unsigned char)rcMin((int)dist[aai]+3, 255);
|
||||
if (nd < dist[i])
|
||||
dist[i] = nd;
|
||||
}
|
||||
}
|
||||
if (rcGetCon(s, 3) != 0xf)
|
||||
{
|
||||
// (0,-1)
|
||||
const int ax = x + rcGetDirOffsetX(3);
|
||||
const int ay = y + rcGetDirOffsetY(3);
|
||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3);
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
nd = (unsigned char)rcMin((int)dist[ai]+2, 255);
|
||||
if (nd < dist[i])
|
||||
dist[i] = nd;
|
||||
|
||||
// (1,-1)
|
||||
if (rcGetCon(as, 2) != 0xf)
|
||||
{
|
||||
const int aax = ax + rcGetDirOffsetX(2);
|
||||
const int aay = ay + rcGetDirOffsetY(2);
|
||||
const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 2);
|
||||
nd = (unsigned char)rcMin((int)dist[aai]+3, 255);
|
||||
if (nd < dist[i])
|
||||
dist[i] = nd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 2
|
||||
for (int y = h-1; y >= 0; --y)
|
||||
{
|
||||
for (int x = w-1; x >= 0; --x)
|
||||
{
|
||||
const rcCompactCell& c = chf.cells[x+y*w];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
|
||||
if (rcGetCon(s, 2) != 0xf)
|
||||
{
|
||||
// (1,0)
|
||||
const int ax = x + rcGetDirOffsetX(2);
|
||||
const int ay = y + rcGetDirOffsetY(2);
|
||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 2);
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
nd = (unsigned char)rcMin((int)dist[ai]+2, 255);
|
||||
if (nd < dist[i])
|
||||
dist[i] = nd;
|
||||
|
||||
// (1,1)
|
||||
if (rcGetCon(as, 1) != 0xf)
|
||||
{
|
||||
const int aax = ax + rcGetDirOffsetX(1);
|
||||
const int aay = ay + rcGetDirOffsetY(1);
|
||||
const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 1);
|
||||
nd = (unsigned char)rcMin((int)dist[aai]+3, 255);
|
||||
if (nd < dist[i])
|
||||
dist[i] = nd;
|
||||
}
|
||||
}
|
||||
if (rcGetCon(s, 1) != 0xf)
|
||||
{
|
||||
// (0,1)
|
||||
const int ax = x + rcGetDirOffsetX(1);
|
||||
const int ay = y + rcGetDirOffsetY(1);
|
||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 1);
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
nd = (unsigned char)rcMin((int)dist[ai]+2, 255);
|
||||
if (nd < dist[i])
|
||||
dist[i] = nd;
|
||||
|
||||
// (-1,1)
|
||||
if (rcGetCon(as, 0) != 0xf)
|
||||
{
|
||||
const int aax = ax + rcGetDirOffsetX(0);
|
||||
const int aay = ay + rcGetDirOffsetY(0);
|
||||
const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 0);
|
||||
nd = (unsigned char)rcMin((int)dist[aai]+3, 255);
|
||||
if (nd < dist[i])
|
||||
dist[i] = nd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned char thr = (unsigned char)(radius*2);
|
||||
for (int i = 0; i < chf.spanCount; ++i)
|
||||
if (dist[i] < thr)
|
||||
chf.areas[i] = 0;
|
||||
|
||||
delete [] dist;
|
||||
|
||||
rcTimeVal endTime = rcGetPerformanceTimer();
|
||||
|
||||
if (rcGetBuildTimes())
|
||||
{
|
||||
rcGetBuildTimes()->erodeArea += rcGetDeltaTimeUsec(startTime, endTime);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rcMarkBoxArea(const float* bmin, const float* bmax, unsigned char areaId,
|
||||
rcCompactHeightfield& chf)
|
||||
{
|
||||
int minx = (int)floorf((bmin[0]-chf.bmin[0])/chf.cs);
|
||||
int miny = (int)floorf((bmin[1]-chf.bmin[1])/chf.ch);
|
||||
int minz = (int)floorf((bmin[2]-chf.bmin[2])/chf.cs);
|
||||
int maxx = (int)ceilf((bmax[0]-chf.bmin[0])/chf.cs);
|
||||
int maxy = (int)ceilf((bmax[1]-chf.bmin[1])/chf.ch);
|
||||
int maxz = (int)ceilf((bmax[2]-chf.bmin[2])/chf.cs);
|
||||
|
||||
minx = rcClamp(minx, 0, chf.width);
|
||||
minz = rcClamp(minz, 0, chf.height);
|
||||
maxx = rcClamp(maxx, 0, chf.width);
|
||||
maxz = rcClamp(maxz, 0, chf.height);
|
||||
|
||||
for (int z = minz; z < maxz; ++z)
|
||||
{
|
||||
for (int x = minx; x < maxx; ++x)
|
||||
{
|
||||
const rcCompactCell& c = chf.cells[x+z*chf.width];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
rcCompactSpan& s = chf.spans[i];
|
||||
if ((int)s.y >= miny && (int)s.y < maxy)
|
||||
{
|
||||
if (areaId < chf.areas[i])
|
||||
chf.areas[i] = areaId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
@ -33,9 +33,11 @@ static int getCornerHeight(int x, int y, int i, int dir,
|
||||
int ch = (int)s.y;
|
||||
int dirp = (dir+1) & 0x3;
|
||||
|
||||
unsigned short regs[4] = {0,0,0,0};
|
||||
unsigned int regs[4] = {0,0,0,0};
|
||||
|
||||
regs[0] = chf.reg[i];
|
||||
// Combine region and area codes in order to prevent
|
||||
// border vertices which are in between two areas to be removed.
|
||||
regs[0] = chf.regs[i] | (chf.areas[i] << 16);
|
||||
|
||||
if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
|
||||
{
|
||||
@ -44,7 +46,7 @@ static int getCornerHeight(int x, int y, int i, int dir,
|
||||
const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir);
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
ch = rcMax(ch, (int)as.y);
|
||||
regs[1] = chf.reg[ai];
|
||||
regs[1] = chf.regs[ai] | (chf.areas[ai] << 16);
|
||||
if (rcGetCon(as, dirp) != RC_NOT_CONNECTED)
|
||||
{
|
||||
const int ax2 = ax + rcGetDirOffsetX(dirp);
|
||||
@ -52,7 +54,7 @@ static int getCornerHeight(int x, int y, int i, int dir,
|
||||
const int ai2 = (int)chf.cells[ax2+ay2*chf.width].index + rcGetCon(as, dirp);
|
||||
const rcCompactSpan& as2 = chf.spans[ai2];
|
||||
ch = rcMax(ch, (int)as2.y);
|
||||
regs[2] = chf.reg[ai2];
|
||||
regs[2] = chf.regs[ai2] | (chf.areas[ai2] << 16);
|
||||
}
|
||||
}
|
||||
if (rcGetCon(s, dirp) != RC_NOT_CONNECTED)
|
||||
@ -62,7 +64,7 @@ static int getCornerHeight(int x, int y, int i, int dir,
|
||||
const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dirp);
|
||||
const rcCompactSpan& as = chf.spans[ai];
|
||||
ch = rcMax(ch, (int)as.y);
|
||||
regs[3] = chf.reg[ai];
|
||||
regs[3] = chf.regs[ai] | (chf.areas[ai] << 16);
|
||||
if (rcGetCon(as, dir) != RC_NOT_CONNECTED)
|
||||
{
|
||||
const int ax2 = ax + rcGetDirOffsetX(dir);
|
||||
@ -70,7 +72,7 @@ static int getCornerHeight(int x, int y, int i, int dir,
|
||||
const int ai2 = (int)chf.cells[ax2+ay2*chf.width].index + rcGetCon(as, dir);
|
||||
const rcCompactSpan& as2 = chf.spans[ai2];
|
||||
ch = rcMax(ch, (int)as2.y);
|
||||
regs[2] = chf.reg[ai2];
|
||||
regs[2] = chf.regs[ai2] | (chf.areas[ai2] << 16);
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,8 +88,9 @@ static int getCornerHeight(int x, int y, int i, int dir,
|
||||
// followed by two interior cells and none of the regions are out of bounds.
|
||||
const bool twoSameExts = (regs[a] & regs[b] & RC_BORDER_REG) != 0 && regs[a] == regs[b];
|
||||
const bool twoInts = ((regs[c] | regs[d]) & RC_BORDER_REG) == 0;
|
||||
const bool intsSameArea = (regs[c]>>16) == (regs[d]>>16);
|
||||
const bool noZeros = regs[a] != 0 && regs[b] != 0 && regs[c] != 0 && regs[d] != 0;
|
||||
if (twoSameExts && twoInts && noZeros)
|
||||
if (twoSameExts && twoInts && intsSameArea && noZeros)
|
||||
{
|
||||
isBorderVertex = true;
|
||||
break;
|
||||
@ -109,6 +112,8 @@ static void walkContour(int x, int y, int i,
|
||||
unsigned char startDir = dir;
|
||||
int starti = i;
|
||||
|
||||
const unsigned char area = chf.areas[i];
|
||||
|
||||
int iter = 0;
|
||||
while (++iter < 40000)
|
||||
{
|
||||
@ -116,6 +121,7 @@ static void walkContour(int x, int y, int i,
|
||||
{
|
||||
// Choose the edge corner
|
||||
bool isBorderVertex = false;
|
||||
bool isAreaBorder = false;
|
||||
int px = x;
|
||||
int py = getCornerHeight(x, y, i, dir, chf, isBorderVertex);
|
||||
int pz = y;
|
||||
@ -132,10 +138,14 @@ static void walkContour(int x, int y, int i,
|
||||
const int ax = x + rcGetDirOffsetX(dir);
|
||||
const int ay = y + rcGetDirOffsetY(dir);
|
||||
const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir);
|
||||
r = (int)chf.reg[ai];
|
||||
r = (int)chf.regs[ai];
|
||||
if (area != chf.areas[ai])
|
||||
isAreaBorder = true;
|
||||
}
|
||||
if (isBorderVertex)
|
||||
r |= RC_BORDER_VERTEX;
|
||||
if (isAreaBorder)
|
||||
r |= RC_AREA_BORDER;
|
||||
points.push(px);
|
||||
points.push(py);
|
||||
points.push(pz);
|
||||
@ -280,7 +290,9 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, float ma
|
||||
for (int i = 0, ni = points.size()/4; i < ni; ++i)
|
||||
{
|
||||
int ii = (i+1) % ni;
|
||||
if ((points[i*4+3] & RC_CONTOUR_REG_MASK) != (points[ii*4+3] & RC_CONTOUR_REG_MASK))
|
||||
const bool differentRegs = (points[i*4+3] & RC_CONTOUR_REG_MASK) != (points[ii*4+3] & RC_CONTOUR_REG_MASK);
|
||||
const bool areaBorders = (points[i*4+3] & RC_AREA_BORDER) != (points[ii*4+3] & RC_AREA_BORDER);
|
||||
if (differentRegs || areaBorders)
|
||||
{
|
||||
simplified.push(points[i*4+0]);
|
||||
simplified.push(points[i*4+1]);
|
||||
@ -306,16 +318,33 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, float ma
|
||||
int by = simplified[ii*4+1];
|
||||
int bz = simplified[ii*4+2];
|
||||
int bi = simplified[ii*4+3];
|
||||
|
||||
|
||||
// Find maximum deviation from the segment.
|
||||
float maxd = 0;
|
||||
int maxi = -1;
|
||||
int ci = (ai+1) % pn;
|
||||
int ci, cinc, endi;
|
||||
|
||||
// Tesselate only outer edges.
|
||||
if ((points[ci*4+3] & RC_CONTOUR_REG_MASK) == 0)
|
||||
// Traverse the segment in lexilogical order so that the
|
||||
// max deviation is calculated similarly when traversing
|
||||
// opposite segments.
|
||||
if (bx > ax || (bx == ax && bz > az))
|
||||
{
|
||||
while (ci != bi)
|
||||
cinc = 1;
|
||||
ci = (ai+cinc) % pn;
|
||||
endi = bi;
|
||||
}
|
||||
else
|
||||
{
|
||||
cinc = pn-1;
|
||||
ci = (bi+cinc) % pn;
|
||||
endi = ai;
|
||||
}
|
||||
|
||||
// Tesselate only outer edges oredges between areas.
|
||||
if ((points[ci*4+3] & RC_CONTOUR_REG_MASK) == 0 ||
|
||||
(points[ci*4+3] & RC_AREA_BORDER))
|
||||
{
|
||||
while (ci != endi)
|
||||
{
|
||||
float d = distancePtSeg(points[ci*4+0], points[ci*4+1]/4, points[ci*4+2],
|
||||
ax, ay/4, az, bx, by/4, bz);
|
||||
@ -324,7 +353,7 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, float ma
|
||||
maxd = d;
|
||||
maxi = ci;
|
||||
}
|
||||
ci = (ci+1) % pn;
|
||||
ci = (ci+cinc) % pn;
|
||||
}
|
||||
}
|
||||
|
||||
@ -571,7 +600,7 @@ bool rcBuildContours(rcCompactHeightfield& chf,
|
||||
{
|
||||
unsigned char res = 0;
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
if (!chf.reg[i] || (chf.reg[i] & RC_BORDER_REG))
|
||||
if (!chf.regs[i] || (chf.regs[i] & RC_BORDER_REG))
|
||||
{
|
||||
flags[i] = 0;
|
||||
continue;
|
||||
@ -584,9 +613,9 @@ bool rcBuildContours(rcCompactHeightfield& chf,
|
||||
const int ax = x + rcGetDirOffsetX(dir);
|
||||
const int ay = y + rcGetDirOffsetY(dir);
|
||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
|
||||
r = chf.reg[ai];
|
||||
r = chf.regs[ai];
|
||||
}
|
||||
if (r == chf.reg[i])
|
||||
if (r == chf.regs[i])
|
||||
res |= (1 << dir);
|
||||
}
|
||||
flags[i] = res ^ 0xf; // Inverse, mark non connected edges.
|
||||
@ -613,9 +642,10 @@ bool rcBuildContours(rcCompactHeightfield& chf,
|
||||
flags[i] = 0;
|
||||
continue;
|
||||
}
|
||||
unsigned short reg = chf.reg[i];
|
||||
const unsigned short reg = chf.regs[i];
|
||||
if (!reg || (reg & RC_BORDER_REG))
|
||||
continue;
|
||||
const unsigned char area = chf.areas[i];
|
||||
|
||||
verts.resize(0);
|
||||
simplified.resize(0);
|
||||
@ -656,6 +686,7 @@ bool rcBuildContours(rcCompactHeightfield& chf,
|
||||
cont->cz /= cont->nverts;*/
|
||||
|
||||
cont->reg = reg;
|
||||
cont->area = area;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -497,11 +497,11 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
|
||||
}
|
||||
|
||||
int nedges = 0;
|
||||
rcScopedDelete<int> edges = new int[nrem*nvp*3];
|
||||
rcScopedDelete<int> edges = new int[nrem*nvp*4];
|
||||
if (!edges)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'edges' (%d).", nrem*nvp*3);
|
||||
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'edges' (%d).", nrem*nvp*4);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -522,6 +522,15 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
|
||||
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hreg' (%d).", nrem*nvp);
|
||||
return false;
|
||||
}
|
||||
|
||||
int nharea = 0;
|
||||
rcScopedDelete<int> harea = new int[nrem*nvp];
|
||||
if (!harea)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'harea' (%d).", nrem*nvp);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
@ -537,10 +546,11 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
|
||||
{
|
||||
if (p[j] != rem && p[k] != rem)
|
||||
{
|
||||
int* e = &edges[nedges*3];
|
||||
int* e = &edges[nedges*4];
|
||||
e[0] = p[k];
|
||||
e[1] = p[j];
|
||||
e[2] = mesh.regs[i];
|
||||
e[3] = mesh.areas[i];
|
||||
nedges++;
|
||||
}
|
||||
}
|
||||
@ -548,6 +558,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
|
||||
unsigned short* p2 = &mesh.polys[(mesh.npolys-1)*nvp*2];
|
||||
memcpy(p,p2,sizeof(unsigned short)*nvp);
|
||||
mesh.regs[i] = mesh.regs[mesh.npolys-1];
|
||||
mesh.areas[i] = mesh.areas[mesh.npolys-1];
|
||||
mesh.npolys--;
|
||||
--i;
|
||||
}
|
||||
@ -572,15 +583,18 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
|
||||
}
|
||||
for (int i = 0; i < nedges; ++i)
|
||||
{
|
||||
if (edges[i*3+0] > rem) edges[i*3+0]--;
|
||||
if (edges[i*3+1] > rem) edges[i*3+1]--;
|
||||
if (edges[i*4+0] > rem) edges[i*4+0]--;
|
||||
if (edges[i*4+1] > rem) edges[i*4+1]--;
|
||||
}
|
||||
|
||||
if (nedges == 0)
|
||||
return true;
|
||||
|
||||
// Start with one vertex, keep appending connected
|
||||
// segments to the start and end of the hole.
|
||||
hole[nhole] = edges[0];
|
||||
hreg[nhole] = edges[2];
|
||||
harea[nhole] = edges[3];
|
||||
nhole++;
|
||||
|
||||
while (nedges)
|
||||
@ -589,28 +603,34 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
|
||||
|
||||
for (int i = 0; i < nedges; ++i)
|
||||
{
|
||||
const int ea = edges[i*3+0];
|
||||
const int eb = edges[i*3+1];
|
||||
const int r = edges[i*3+2];
|
||||
const int ea = edges[i*4+0];
|
||||
const int eb = edges[i*4+1];
|
||||
const int r = edges[i*4+2];
|
||||
const int a = edges[i*4+3];
|
||||
bool add = false;
|
||||
if (hole[0] == eb)
|
||||
{
|
||||
// The segment matches the beginning of the hole boundary.
|
||||
pushFront(ea, hole, nhole);
|
||||
pushFront(r, hreg, nhreg);
|
||||
pushFront(a, harea, nharea);
|
||||
add = true;
|
||||
}
|
||||
else if (hole[nhole-1] == ea)
|
||||
{
|
||||
// The segment matches the end of the hole boundary.
|
||||
pushBack(eb, hole, nhole);
|
||||
pushBack(r, hreg, nhreg);
|
||||
pushBack(a, harea, nharea);
|
||||
add = true;
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
// Remove edge.
|
||||
edges[i*3+0] = edges[(nedges-1)*3+0];
|
||||
edges[i*3+1] = edges[(nedges-1)*3+1];
|
||||
edges[i*3+2] = edges[(nedges-1)*3+2];
|
||||
// The edge segment was added, remove it.
|
||||
edges[i*4+0] = edges[(nedges-1)*4+0];
|
||||
edges[i*4+1] = edges[(nedges-1)*4+1];
|
||||
edges[i*4+2] = edges[(nedges-1)*4+2];
|
||||
edges[i*4+3] = edges[(nedges-1)*4+3];
|
||||
--nedges;
|
||||
match = true;
|
||||
--i;
|
||||
@ -680,6 +700,13 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
|
||||
rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pregs' (%d).", ntris);
|
||||
return false;
|
||||
}
|
||||
rcScopedDelete<unsigned char> pareas = new unsigned char[ntris];
|
||||
if (!pregs)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pareas' (%d).", ntris);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned short* tmpPoly = &polys[ntris*nvp];
|
||||
|
||||
@ -694,7 +721,8 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
|
||||
polys[npolys*nvp+0] = (unsigned short)hole[t[0]];
|
||||
polys[npolys*nvp+1] = (unsigned short)hole[t[1]];
|
||||
polys[npolys*nvp+2] = (unsigned short)hole[t[2]];
|
||||
pregs[npolys] = hreg[t[0]];
|
||||
pregs[npolys] = (unsigned short)hreg[t[0]];
|
||||
pareas[npolys] = (unsigned char)harea[t[0]];
|
||||
npolys++;
|
||||
}
|
||||
}
|
||||
@ -737,6 +765,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
|
||||
mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp);
|
||||
memcpy(pb, &polys[(npolys-1)*nvp], sizeof(unsigned short)*nvp);
|
||||
pregs[bestPb] = pregs[npolys-1];
|
||||
pareas[bestPb] = pareas[npolys-1];
|
||||
npolys--;
|
||||
}
|
||||
else
|
||||
@ -756,6 +785,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
p[j] = polys[i*nvp+j];
|
||||
mesh.regs[mesh.npolys] = pregs[i];
|
||||
mesh.areas[mesh.npolys] = pareas[i];
|
||||
mesh.npolys++;
|
||||
if (mesh.npolys > maxTris)
|
||||
{
|
||||
@ -827,7 +857,14 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.regs' (%d).", maxTris);
|
||||
return false;
|
||||
}
|
||||
|
||||
mesh.areas = new unsigned char[maxTris];
|
||||
if (!mesh.areas)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.areas' (%d).", maxTris);
|
||||
return false;
|
||||
}
|
||||
|
||||
mesh.nverts = 0;
|
||||
mesh.npolys = 0;
|
||||
mesh.nvp = nvp;
|
||||
@ -835,6 +872,7 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
|
||||
memset(mesh.verts, 0, sizeof(unsigned short)*maxVertices*3);
|
||||
memset(mesh.polys, 0xff, sizeof(unsigned short)*maxTris*nvp*2);
|
||||
memset(mesh.regs, 0, sizeof(unsigned short)*maxTris);
|
||||
memset(mesh.areas, 0, sizeof(unsigned char)*maxTris);
|
||||
|
||||
rcScopedDelete<int> nextVert = new int[maxVertices];
|
||||
if (!nextVert)
|
||||
@ -992,6 +1030,7 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
|
||||
for (int k = 0; k < nvp; ++k)
|
||||
p[k] = q[k];
|
||||
mesh.regs[mesh.npolys] = cont.reg;
|
||||
mesh.areas[mesh.npolys] = cont.area;
|
||||
mesh.npolys++;
|
||||
if (mesh.npolys > maxTris)
|
||||
{
|
||||
@ -1091,6 +1130,15 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
|
||||
return false;
|
||||
}
|
||||
memset(mesh.regs, 0, sizeof(unsigned short)*maxPolys);
|
||||
|
||||
mesh.areas = new unsigned char[maxPolys];
|
||||
if (!mesh.areas)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.areas' (%d).", maxPolys);
|
||||
return false;
|
||||
}
|
||||
memset(mesh.areas, 0, sizeof(unsigned char)*maxPolys);
|
||||
|
||||
rcScopedDelete<int> nextVert = new int[maxVerts];
|
||||
if (!nextVert)
|
||||
@ -1131,7 +1179,7 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
|
||||
{
|
||||
unsigned short* v = &pmesh->verts[j*3];
|
||||
vremap[j] = addVertex(v[0]+ox, v[1], v[2]+oz,
|
||||
mesh.verts, firstVert, nextVert, mesh.nverts);
|
||||
mesh.verts, firstVert, nextVert, mesh.nverts);
|
||||
}
|
||||
|
||||
for (int j = 0; j < pmesh->npolys; ++j)
|
||||
@ -1139,6 +1187,7 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh)
|
||||
unsigned short* tgt = &mesh.polys[mesh.npolys*2*mesh.nvp];
|
||||
unsigned short* src = &pmesh->polys[j*2*mesh.nvp];
|
||||
mesh.regs[mesh.npolys] = pmesh->regs[j];
|
||||
mesh.areas[mesh.npolys] = pmesh->areas[j];
|
||||
mesh.npolys++;
|
||||
for (int k = 0; k < mesh.nvp; ++k)
|
||||
{
|
||||
|
@ -47,11 +47,19 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf,
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
const unsigned char area = chf.areas[i];
|
||||
|
||||
int nc = 0;
|
||||
for (int dir = 0; dir < 4; ++dir)
|
||||
{
|
||||
if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
|
||||
nc++;
|
||||
{
|
||||
const int ax = x + rcGetDirOffsetX(dir);
|
||||
const int ay = y + rcGetDirOffsetY(dir);
|
||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
|
||||
if (area == chf.areas[ai])
|
||||
nc++;
|
||||
}
|
||||
}
|
||||
if (nc != 4)
|
||||
src[i] = 0;
|
||||
@ -59,6 +67,7 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Pass 1
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
@ -236,13 +245,15 @@ static unsigned short* boxBlur(rcCompactHeightfield& chf, int thr,
|
||||
|
||||
|
||||
static bool floodRegion(int x, int y, int i,
|
||||
unsigned short level, unsigned short minLevel, unsigned short r,
|
||||
unsigned short level, unsigned short r,
|
||||
rcCompactHeightfield& chf,
|
||||
unsigned short* srcReg, unsigned short* srcDist,
|
||||
rcIntArray& stack)
|
||||
{
|
||||
const int w = chf.width;
|
||||
|
||||
const unsigned char area = chf.areas[i];
|
||||
|
||||
// Flood fill mark region.
|
||||
stack.resize(0);
|
||||
stack.push((int)x);
|
||||
@ -251,7 +262,7 @@ static bool floodRegion(int x, int y, int i,
|
||||
srcReg[i] = r;
|
||||
srcDist[i] = 0;
|
||||
|
||||
unsigned short lev = level >= minLevel+2 ? level-2 : minLevel;
|
||||
unsigned short lev = level >= 2 ? level-2 : 0;
|
||||
int count = 0;
|
||||
|
||||
while (stack.size() > 0)
|
||||
@ -272,6 +283,8 @@ static bool floodRegion(int x, int y, int i,
|
||||
const int ax = cx + rcGetDirOffsetX(dir);
|
||||
const int ay = cy + rcGetDirOffsetY(dir);
|
||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir);
|
||||
if (chf.areas[ai] != area)
|
||||
continue;
|
||||
unsigned short nr = srcReg[ai];
|
||||
if (nr != 0 && nr != r)
|
||||
ar = nr;
|
||||
@ -284,7 +297,8 @@ static bool floodRegion(int x, int y, int i,
|
||||
const int ax2 = ax + rcGetDirOffsetX(dir2);
|
||||
const int ay2 = ay + rcGetDirOffsetY(dir2);
|
||||
const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2);
|
||||
|
||||
if (chf.areas[ai2] != area)
|
||||
continue;
|
||||
unsigned short nr = srcReg[ai2];
|
||||
if (nr != 0 && nr != r)
|
||||
ar = nr;
|
||||
@ -306,6 +320,8 @@ static bool floodRegion(int x, int y, int i,
|
||||
const int ax = cx + rcGetDirOffsetX(dir);
|
||||
const int ay = cy + rcGetDirOffsetY(dir);
|
||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir);
|
||||
if (chf.areas[ai] != area)
|
||||
continue;
|
||||
if (chf.dist[ai] >= lev)
|
||||
{
|
||||
if (srcReg[ai] == 0)
|
||||
@ -342,7 +358,7 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
|
||||
const rcCompactCell& c = chf.cells[x+y*w];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
if (chf.dist[i] >= level && srcReg[i] == 0)
|
||||
if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
|
||||
{
|
||||
stack.push(x);
|
||||
stack.push(y);
|
||||
@ -373,6 +389,7 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
|
||||
|
||||
unsigned short r = srcReg[i];
|
||||
unsigned short d2 = 0xffff;
|
||||
const unsigned char area = chf.areas[i];
|
||||
const rcCompactSpan& s = chf.spans[i];
|
||||
for (int dir = 0; dir < 4; ++dir)
|
||||
{
|
||||
@ -380,6 +397,7 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
|
||||
const int ax = x + rcGetDirOffsetX(dir);
|
||||
const int ay = y + rcGetDirOffsetY(dir);
|
||||
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
|
||||
if (chf.areas[ai] != area) continue;
|
||||
if (srcReg[ai] > 0 && (srcReg[ai] & RC_BORDER_REG) == 0)
|
||||
{
|
||||
if ((int)srcDist[ai]+2 < (int)d2)
|
||||
@ -422,10 +440,11 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
|
||||
|
||||
struct rcRegion
|
||||
{
|
||||
inline rcRegion() : count(0), id(0), remap(false) {}
|
||||
inline rcRegion() : count(0), id(0), area(0), remap(false) {}
|
||||
|
||||
int count;
|
||||
unsigned short id;
|
||||
unsigned char area;
|
||||
bool remap;
|
||||
rcIntArray connections;
|
||||
rcIntArray floors;
|
||||
@ -471,6 +490,8 @@ static void replaceNeighbour(rcRegion& reg, unsigned short oldId, unsigned short
|
||||
|
||||
static bool canMergeWithRegion(const rcRegion& rega, const rcRegion& regb)
|
||||
{
|
||||
if (rega.area != regb.area)
|
||||
return false;
|
||||
int n = 0;
|
||||
for (int i = 0; i < rega.connections.size(); ++i)
|
||||
{
|
||||
@ -719,6 +740,8 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize,
|
||||
if (reg.connections.size() > 0)
|
||||
continue;
|
||||
|
||||
reg.area = chf.areas[i];
|
||||
|
||||
// Check if this cell is next to a border.
|
||||
int ndir = -1;
|
||||
for (int dir = 0; dir < 4; ++dir)
|
||||
@ -936,7 +959,7 @@ bool rcBuildDistanceField(rcCompactHeightfield& chf)
|
||||
}
|
||||
|
||||
static void paintRectRegion(int minx, int maxx, int miny, int maxy,
|
||||
unsigned short regId, unsigned short minLevel,
|
||||
unsigned short regId,
|
||||
rcCompactHeightfield& chf, unsigned short* srcReg)
|
||||
{
|
||||
const int w = chf.width;
|
||||
@ -947,7 +970,7 @@ static void paintRectRegion(int minx, int maxx, int miny, int maxy,
|
||||
const rcCompactCell& c = chf.cells[x+y*w];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
if (chf.dist[i] >= minLevel)
|
||||
if (chf.areas[i] != RC_NULL_AREA)
|
||||
srcReg[i] = regId;
|
||||
}
|
||||
}
|
||||
@ -966,20 +989,18 @@ struct rcSweepSpan
|
||||
};
|
||||
|
||||
bool rcBuildRegionsMonotone(rcCompactHeightfield& chf,
|
||||
int walkableRadius, int borderSize,
|
||||
int minRegionSize, int mergeRegionSize)
|
||||
int borderSize, int minRegionSize, int mergeRegionSize)
|
||||
{
|
||||
rcTimeVal startTime = rcGetPerformanceTimer();
|
||||
/* rcTimeVal startTime = rcGetPerformanceTimer();
|
||||
|
||||
const int w = chf.width;
|
||||
const int h = chf.height;
|
||||
unsigned short minLevel = (unsigned short)(walkableRadius*2);
|
||||
unsigned short id = 1;
|
||||
|
||||
if (chf.reg)
|
||||
if (chf.regs)
|
||||
{
|
||||
delete [] chf.reg;
|
||||
chf.reg = 0;
|
||||
delete [] chf.regs;
|
||||
chf.regs = 0;
|
||||
}
|
||||
|
||||
rcScopedDelete<unsigned short> srcReg = new unsigned short[chf.spanCount];
|
||||
@ -1003,10 +1024,10 @@ bool rcBuildRegionsMonotone(rcCompactHeightfield& chf,
|
||||
// Mark border regions.
|
||||
if (borderSize)
|
||||
{
|
||||
paintRectRegion(0, borderSize, 0, h, id|RC_BORDER_REG, minLevel, chf, srcReg); id++;
|
||||
paintRectRegion(w-borderSize, w, 0, h, id|RC_BORDER_REG, minLevel, chf, srcReg); id++;
|
||||
paintRectRegion(0, w, 0, borderSize, id|RC_BORDER_REG, minLevel, chf, srcReg); id++;
|
||||
paintRectRegion(0, w, h-borderSize, h, id|RC_BORDER_REG, minLevel, chf, srcReg); id++;
|
||||
paintRectRegion(0, borderSize, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
|
||||
paintRectRegion(w-borderSize, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
|
||||
paintRectRegion(0, w, 0, borderSize, id|RC_BORDER_REG, chf, srcReg); id++;
|
||||
paintRectRegion(0, w, h-borderSize, h, id|RC_BORDER_REG, chf, srcReg); id++;
|
||||
}
|
||||
|
||||
rcIntArray prev(256);
|
||||
@ -1110,7 +1131,7 @@ bool rcBuildRegionsMonotone(rcCompactHeightfield& chf,
|
||||
rcTimeVal filterEndTime = rcGetPerformanceTimer();
|
||||
|
||||
// Store the result out.
|
||||
chf.reg = srcReg;
|
||||
chf.regs = srcReg;
|
||||
srcReg = 0;
|
||||
|
||||
rcTimeVal endTime = rcGetPerformanceTimer();
|
||||
@ -1120,23 +1141,23 @@ bool rcBuildRegionsMonotone(rcCompactHeightfield& chf,
|
||||
rcGetBuildTimes()->buildRegions += rcGetDeltaTimeUsec(startTime, endTime);
|
||||
rcGetBuildTimes()->buildRegionsFilter += rcGetDeltaTimeUsec(filterStartTime, filterEndTime);
|
||||
}
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rcBuildRegions(rcCompactHeightfield& chf,
|
||||
int walkableRadius, int borderSize,
|
||||
int minRegionSize, int mergeRegionSize)
|
||||
int borderSize, int minRegionSize, int mergeRegionSize)
|
||||
{
|
||||
rcTimeVal startTime = rcGetPerformanceTimer();
|
||||
|
||||
const int w = chf.width;
|
||||
const int h = chf.height;
|
||||
|
||||
if (!chf.reg)
|
||||
if (!chf.regs)
|
||||
{
|
||||
chf.reg = new unsigned short[chf.spanCount];
|
||||
if (!chf.reg)
|
||||
chf.regs = new unsigned short[chf.spanCount];
|
||||
if (!chf.regs)
|
||||
{
|
||||
if (rcGetLog())
|
||||
rcGetLog()->log(RC_LOG_ERROR, "rcBuildRegions: Out of memory 'chf.reg' (%d).", chf.spanCount);
|
||||
@ -1167,21 +1188,23 @@ bool rcBuildRegions(rcCompactHeightfield& chf,
|
||||
|
||||
unsigned short regionId = 1;
|
||||
unsigned short level = (chf.maxDistance+1) & ~1;
|
||||
|
||||
unsigned short minLevel = (unsigned short)(walkableRadius*2);
|
||||
|
||||
const int expandIters = 4 + walkableRadius * 2;
|
||||
|
||||
// TODO: Figure better formula, expandIters defines how much the
|
||||
// watershed "overflows" and simplifies the regions. Tying it to
|
||||
// agent radius was usually good indication how greedy it could be.
|
||||
// const int expandIters = 4 + walkableRadius * 2;
|
||||
const int expandIters = 8;
|
||||
|
||||
// Mark border regions.
|
||||
paintRectRegion(0, borderSize, 0, h, regionId|RC_BORDER_REG, minLevel, chf, srcReg); regionId++;
|
||||
paintRectRegion(w-borderSize, w, 0, h, regionId|RC_BORDER_REG, minLevel, chf, srcReg); regionId++;
|
||||
paintRectRegion(0, w, 0, borderSize, regionId|RC_BORDER_REG, minLevel, chf, srcReg); regionId++;
|
||||
paintRectRegion(0, w, h-borderSize, h, regionId|RC_BORDER_REG, minLevel, chf, srcReg); regionId++;
|
||||
paintRectRegion(0, borderSize, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
||||
paintRectRegion(w-borderSize, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
||||
paintRectRegion(0, w, 0, borderSize, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
||||
paintRectRegion(0, w, h-borderSize, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
|
||||
|
||||
rcTimeVal expTime = 0;
|
||||
rcTimeVal floodTime = 0;
|
||||
|
||||
while (level > minLevel)
|
||||
while (level > 0)
|
||||
{
|
||||
level = level >= 2 ? level-2 : 0;
|
||||
|
||||
@ -1206,10 +1229,10 @@ bool rcBuildRegions(rcCompactHeightfield& chf,
|
||||
const rcCompactCell& c = chf.cells[x+y*w];
|
||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||
{
|
||||
if (chf.dist[i] < level || srcReg[i] != 0)
|
||||
if (chf.dist[i] < level || srcReg[i] != 0 || chf.areas[i] == RC_NULL_AREA)
|
||||
continue;
|
||||
|
||||
if (floodRegion(x, y, i, minLevel, level, regionId, chf, srcReg, srcDist, stack))
|
||||
if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
|
||||
regionId++;
|
||||
}
|
||||
}
|
||||
@ -1220,7 +1243,7 @@ bool rcBuildRegions(rcCompactHeightfield& chf,
|
||||
}
|
||||
|
||||
// Expand current regions until no empty connected cells found.
|
||||
if (expandRegions(expandIters*8, minLevel, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg)
|
||||
if (expandRegions(expandIters*8, 0, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg)
|
||||
{
|
||||
rcSwap(srcReg, dstReg);
|
||||
rcSwap(srcDist, dstDist);
|
||||
@ -1236,10 +1259,9 @@ bool rcBuildRegions(rcCompactHeightfield& chf,
|
||||
return false;
|
||||
|
||||
rcTimeVal filterEndTime = rcGetPerformanceTimer();
|
||||
|
||||
|
||||
// Write the result out.
|
||||
for (int i = 0; i < chf.spanCount; ++i)
|
||||
chf.reg[i] = srcReg[i];
|
||||
memcpy(chf.regs, srcReg, sizeof(unsigned short)*chf.spanCount);
|
||||
|
||||
rcTimeVal endTime = rcGetPerformanceTimer();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user