Added option to add rotated Box obstacle to TileCache. (#278)
Very useful when you have a obstacle with a big difference in x to z ratio and that could be rotated (not aligned), like a wall.
This commit is contained in:
parent
46654531e4
commit
840c100639
@ -38,7 +38,8 @@ enum ObstacleState
|
||||
enum ObstacleType
|
||||
{
|
||||
DT_OBSTACLE_CYLINDER,
|
||||
DT_OBSTACLE_BOX,
|
||||
DT_OBSTACLE_BOX, // AABB
|
||||
DT_OBSTACLE_ORIENTED_BOX, // OBB
|
||||
};
|
||||
|
||||
struct dtObstacleCylinder
|
||||
@ -54,6 +55,13 @@ struct dtObstacleBox
|
||||
float bmax[ 3 ];
|
||||
};
|
||||
|
||||
struct dtObstacleOrientedBox
|
||||
{
|
||||
float center[ 3 ];
|
||||
float extents[ 3 ];
|
||||
float rotAux[ 2 ]; //{ cos(0.5f*angle)*sin(-0.5f*angle); cos(0.5f*angle)*cos(0.5f*angle) - 0.5 }
|
||||
};
|
||||
|
||||
static const int DT_MAX_TOUCHED_TILES = 8;
|
||||
struct dtTileCacheObstacle
|
||||
{
|
||||
@ -61,6 +69,7 @@ struct dtTileCacheObstacle
|
||||
{
|
||||
dtObstacleCylinder cylinder;
|
||||
dtObstacleBox box;
|
||||
dtObstacleOrientedBox orientedBox;
|
||||
};
|
||||
|
||||
dtCompressedTileRef touched[DT_MAX_TOUCHED_TILES];
|
||||
@ -130,9 +139,15 @@ public:
|
||||
|
||||
dtStatus removeTile(dtCompressedTileRef ref, unsigned char** data, int* dataSize);
|
||||
|
||||
// Cylinder obstacle.
|
||||
dtStatus addObstacle(const float* pos, const float radius, const float height, dtObstacleRef* result);
|
||||
|
||||
// Aabb obstacle.
|
||||
dtStatus addBoxObstacle(const float* bmin, const float* bmax, dtObstacleRef* result);
|
||||
|
||||
// Box obstacle: can be rotated in Y.
|
||||
dtStatus addBoxObstacle(const float* center, const float* extents, const float yRadians, dtObstacleRef* result);
|
||||
|
||||
dtStatus removeObstacle(const dtObstacleRef ref);
|
||||
|
||||
dtStatus queryTiles(const float* bmin, const float* bmax,
|
||||
|
@ -130,6 +130,9 @@ dtStatus dtMarkCylinderArea(dtTileCacheLayer& layer, const float* orig, const fl
|
||||
dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch,
|
||||
const float* bmin, const float* bmax, const unsigned char areaId);
|
||||
|
||||
dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch,
|
||||
const float* center, const float* extents, const float* rotAux, const unsigned char areaId);
|
||||
|
||||
dtStatus dtBuildTileCacheRegions(dtTileCacheAlloc* alloc,
|
||||
dtTileCacheLayer& layer,
|
||||
const int walkableClimb);
|
||||
|
@ -420,6 +420,45 @@ dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, dtObs
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtStatus dtTileCache::addBoxObstacle(const float* center, const float* extents, const float yRadians, dtObstacleRef* result)
|
||||
{
|
||||
if (m_nreqs >= MAX_REQUESTS)
|
||||
return DT_FAILURE | DT_BUFFER_TOO_SMALL;
|
||||
|
||||
dtTileCacheObstacle* ob = 0;
|
||||
if (m_nextFreeObstacle)
|
||||
{
|
||||
ob = m_nextFreeObstacle;
|
||||
m_nextFreeObstacle = ob->next;
|
||||
ob->next = 0;
|
||||
}
|
||||
if (!ob)
|
||||
return DT_FAILURE | DT_OUT_OF_MEMORY;
|
||||
|
||||
unsigned short salt = ob->salt;
|
||||
memset(ob, 0, sizeof(dtTileCacheObstacle));
|
||||
ob->salt = salt;
|
||||
ob->state = DT_OBSTACLE_PROCESSING;
|
||||
ob->type = DT_OBSTACLE_ORIENTED_BOX;
|
||||
dtVcopy(ob->orientedBox.center, center);
|
||||
dtVcopy(ob->orientedBox.extents, extents);
|
||||
|
||||
float coshalf= cosf(0.5f*yRadians);
|
||||
float sinhalf = sinf(-0.5f*yRadians);
|
||||
ob->orientedBox.rotAux[0] = coshalf*sinhalf;
|
||||
ob->orientedBox.rotAux[1] = coshalf*coshalf - 0.5f;
|
||||
|
||||
ObstacleRequest* req = &m_reqs[m_nreqs++];
|
||||
memset(req, 0, sizeof(ObstacleRequest));
|
||||
req->action = REQUEST_ADD;
|
||||
req->ref = getObstacleRef(ob);
|
||||
|
||||
if (result)
|
||||
*result = req->ref;
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtStatus dtTileCache::removeObstacle(const dtObstacleRef ref)
|
||||
{
|
||||
if (!ref)
|
||||
@ -652,6 +691,11 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh*
|
||||
dtMarkBoxArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
|
||||
ob->box.bmin, ob->box.bmax, 0);
|
||||
}
|
||||
else if (ob->type == DT_OBSTACLE_ORIENTED_BOX)
|
||||
{
|
||||
dtMarkBoxArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
|
||||
ob->orientedBox.center, ob->orientedBox.extents, ob->orientedBox.rotAux, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -761,4 +805,16 @@ void dtTileCache::getObstacleBounds(const struct dtTileCacheObstacle* ob, float*
|
||||
dtVcopy(bmin, ob->box.bmin);
|
||||
dtVcopy(bmax, ob->box.bmax);
|
||||
}
|
||||
else if (ob->type == DT_OBSTACLE_ORIENTED_BOX)
|
||||
{
|
||||
const dtObstacleOrientedBox &orientedBox = ob->orientedBox;
|
||||
|
||||
float maxr = 1.41f*dtMax(orientedBox.extents[0], orientedBox.extents[2]);
|
||||
bmin[0] = orientedBox.center[0] - maxr;
|
||||
bmax[0] = orientedBox.center[0] + maxr;
|
||||
bmin[1] = orientedBox.center[1] - orientedBox.extents[1];
|
||||
bmax[1] = orientedBox.center[1] + orientedBox.extents[1];
|
||||
bmin[2] = orientedBox.center[2] - maxr;
|
||||
bmax[2] = orientedBox.center[2] + maxr;
|
||||
}
|
||||
}
|
||||
|
@ -2041,6 +2041,60 @@ dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float c
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch,
|
||||
const float* center, const float* extents, const float* rotAux, const unsigned char areaId)
|
||||
{
|
||||
const int w = (int)layer.header->width;
|
||||
const int h = (int)layer.header->height;
|
||||
const float ics = 1.0f/cs;
|
||||
const float ich = 1.0f/ch;
|
||||
|
||||
float cx = (center[0] - orig[0])*ics;
|
||||
float cz = (center[2] - orig[2])*ics;
|
||||
|
||||
float maxr = 1.41f*dtMax(extents[0], extents[2]);
|
||||
int minx = (int)floorf(cx - maxr*ics);
|
||||
int maxx = (int)floorf(cx + maxr*ics);
|
||||
int minz = (int)floorf(cz - maxr*ics);
|
||||
int maxz = (int)floorf(cz + maxr*ics);
|
||||
int miny = (int)floorf((center[1]-extents[1]-orig[1])*ich);
|
||||
int maxy = (int)floorf((center[1]+extents[1]-orig[1])*ich);
|
||||
|
||||
if (maxx < 0) return DT_SUCCESS;
|
||||
if (minx >= w) return DT_SUCCESS;
|
||||
if (maxz < 0) return DT_SUCCESS;
|
||||
if (minz >= h) return DT_SUCCESS;
|
||||
|
||||
if (minx < 0) minx = 0;
|
||||
if (maxx >= w) maxx = w-1;
|
||||
if (minz < 0) minz = 0;
|
||||
if (maxz >= h) maxz = h-1;
|
||||
|
||||
float xhalf = extents[0]*ics + 0.5f;
|
||||
float zhalf = extents[2]*ics + 0.5f;
|
||||
|
||||
for (int z = minz; z <= maxz; ++z)
|
||||
{
|
||||
for (int x = minx; x <= maxx; ++x)
|
||||
{
|
||||
float x2 = 2.0f*(float(x) - cx);
|
||||
float z2 = 2.0f*(float(z) - cz);
|
||||
float xrot = rotAux[1]*x2 + rotAux[0]*z2;
|
||||
if (xrot > xhalf || xrot < -xhalf)
|
||||
continue;
|
||||
float zrot = rotAux[1]*z2 - rotAux[0]*x2;
|
||||
if (zrot > zhalf || zrot < -zhalf)
|
||||
continue;
|
||||
const int y = layer.heights[x+z*w];
|
||||
if (y < miny || y > maxy)
|
||||
continue;
|
||||
layer.areas[x+z*w] = areaId;
|
||||
}
|
||||
}
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtStatus dtBuildTileCacheLayer(dtTileCacheCompressor* comp,
|
||||
dtTileCacheLayerHeader* header,
|
||||
const unsigned char* heights,
|
||||
|
Loading…
x
Reference in New Issue
Block a user