2
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
4
// This software is provided 'as-is', without any express or implied
5
// warranty. In no event will the authors be held liable for any damages
6
// arising from the use of this software.
7
// Permission is granted to anyone to use this software for any purpose,
8
// including commercial applications, and to alter it and redistribute it
9
// freely, subject to the following restrictions:
10
// 1. The origin of this software must not be misrepresented; you must not
11
// claim that you wrote the original software. If you use this software
12
// in a product, an acknowledgment in the product documentation would be
13
// appreciated but is not required.
14
// 2. Altered source versions must be plainly marked as such, and must not be
15
// misrepresented as being the original software.
16
// 3. This notice may not be removed or altered from any source distribution.
20
#define _USE_MATH_DEFINES
27
#include "RecastAlloc.h"
28
#include "RecastAssert.h"
38
/// This class does not provide logging or timer functionality on its
39
/// own. Both must be provided by a concrete implementation
40
/// by overriding the protected member functions. Also, this class does not
41
/// provide an interface for extracting log messages. (Only adding them.)
42
/// So concrete implementations must provide one.
44
/// If no logging or timers are required, just pass an instance of this
45
/// class through the Recast build process.
52
/// // Where ctx is an instance of rcContext and filepath is a char array.
53
/// ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath);
55
void rcContext::log(const rcLogCategory category, const char* format, ...)
59
static const int MSG_SIZE = 512;
63
int len = vsnprintf(msg, MSG_SIZE, format, ap);
67
msg[MSG_SIZE-1] = '\0';
70
doLog(category, msg, len);
73
rcHeightfield* rcAllocHeightfield()
75
rcHeightfield* hf = (rcHeightfield*)rcAlloc(sizeof(rcHeightfield), RC_ALLOC_PERM);
76
memset(hf, 0, sizeof(rcHeightfield));
80
void rcFreeHeightField(rcHeightfield* hf)
88
rcSpanPool* next = hf->pools->next;
95
rcCompactHeightfield* rcAllocCompactHeightfield()
97
rcCompactHeightfield* chf = (rcCompactHeightfield*)rcAlloc(sizeof(rcCompactHeightfield), RC_ALLOC_PERM);
98
memset(chf, 0, sizeof(rcCompactHeightfield));
102
void rcFreeCompactHeightfield(rcCompactHeightfield* chf)
113
rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet()
115
rcHeightfieldLayerSet* lset = (rcHeightfieldLayerSet*)rcAlloc(sizeof(rcHeightfieldLayerSet), RC_ALLOC_PERM);
116
memset(lset, 0, sizeof(rcHeightfieldLayerSet));
120
void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset)
123
for (int i = 0; i < lset->nlayers; ++i)
125
rcFree(lset->layers[i].heights);
126
rcFree(lset->layers[i].areas);
127
rcFree(lset->layers[i].cons);
129
rcFree(lset->layers);
134
rcContourSet* rcAllocContourSet()
136
rcContourSet* cset = (rcContourSet*)rcAlloc(sizeof(rcContourSet), RC_ALLOC_PERM);
137
memset(cset, 0, sizeof(rcContourSet));
141
void rcFreeContourSet(rcContourSet* cset)
144
for (int i = 0; i < cset->nconts; ++i)
146
rcFree(cset->conts[i].verts);
147
rcFree(cset->conts[i].rverts);
153
rcPolyMesh* rcAllocPolyMesh()
155
rcPolyMesh* pmesh = (rcPolyMesh*)rcAlloc(sizeof(rcPolyMesh), RC_ALLOC_PERM);
156
memset(pmesh, 0, sizeof(rcPolyMesh));
160
void rcFreePolyMesh(rcPolyMesh* pmesh)
163
rcFree(pmesh->verts);
164
rcFree(pmesh->polys);
166
rcFree(pmesh->flags);
167
rcFree(pmesh->areas);
171
rcPolyMeshDetail* rcAllocPolyMeshDetail()
173
rcPolyMeshDetail* dmesh = (rcPolyMeshDetail*)rcAlloc(sizeof(rcPolyMeshDetail), RC_ALLOC_PERM);
174
memset(dmesh, 0, sizeof(rcPolyMeshDetail));
178
void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh)
181
rcFree(dmesh->meshes);
182
rcFree(dmesh->verts);
187
void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax)
189
// Calculate bounding box.
190
rcVcopy(bmin, verts);
191
rcVcopy(bmax, verts);
192
for (int i = 1; i < nv; ++i)
194
const float* v = &verts[i*3];
200
void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h)
202
*w = (int)((bmax[0] - bmin[0])/cs+0.5f);
203
*h = (int)((bmax[2] - bmin[2])/cs+0.5f);
208
/// See the #rcConfig documentation for more information on the configuration parameters.
210
/// @see rcAllocHeightfield, rcHeightfield
211
bool rcCreateHeightfield(rcContext* /*ctx*/, rcHeightfield& hf, int width, int height,
212
const float* bmin, const float* bmax,
215
// TODO: VC complains about unref formal variable, figure out a way to handle this better.
220
rcVcopy(hf.bmin, bmin);
221
rcVcopy(hf.bmax, bmax);
224
hf.spans = (rcSpan**)rcAlloc(sizeof(rcSpan*)*hf.width*hf.height, RC_ALLOC_PERM);
227
memset(hf.spans, 0, sizeof(rcSpan*)*hf.width*hf.height);
231
static void calcTriNormal(const float* v0, const float* v1, const float* v2, float* norm)
236
rcVcross(norm, e0, e1);
242
/// Only sets the aread id's for the walkable triangles. Does not alter the
243
/// area id's for unwalkable triangles.
245
/// See the #rcConfig documentation for more information on the configuration parameters.
247
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
248
void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
249
const float* verts, int /*nv*/,
250
const int* tris, int nt,
251
unsigned char* areas)
253
// TODO: VC complains about unref formal variable, figure out a way to handle this better.
256
const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
260
for (int i = 0; i < nt; ++i)
262
const int* tri = &tris[i*3];
263
calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
264
// Check if the face is walkable.
265
if (norm[1] > walkableThr)
266
areas[i] = RC_WALKABLE_AREA;
272
/// Only sets the aread id's for the unwalkable triangles. Does not alter the
273
/// area id's for walkable triangles.
275
/// See the #rcConfig documentation for more information on the configuration parameters.
277
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
278
void rcClearUnwalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
279
const float* verts, int /*nv*/,
280
const int* tris, int nt,
281
unsigned char* areas)
283
// TODO: VC complains about unref formal variable, figure out a way to handle this better.
286
const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
290
for (int i = 0; i < nt; ++i)
292
const int* tri = &tris[i*3];
293
calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
294
// Check if the face is walkable.
295
if (norm[1] <= walkableThr)
296
areas[i] = RC_NULL_AREA;
300
int rcGetHeightFieldSpanCount(rcContext* /*ctx*/, rcHeightfield& hf)
302
// TODO: VC complains about unref formal variable, figure out a way to handle this better.
305
const int w = hf.width;
306
const int h = hf.height;
308
for (int y = 0; y < h; ++y)
310
for (int x = 0; x < w; ++x)
312
for (rcSpan* s = hf.spans[x + y*w]; s; s = s->next)
314
if (s->area != RC_NULL_AREA)
324
/// This is just the beginning of the process of fully building a compact heightfield.
325
/// Various filters may be applied applied, then the distance field and regions built.
326
/// E.g: #rcBuildDistanceField and #rcBuildRegions
328
/// See the #rcConfig documentation for more information on the configuration parameters.
330
/// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig
331
bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb,
332
rcHeightfield& hf, rcCompactHeightfield& chf)
336
ctx->startTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
338
const int w = hf.width;
339
const int h = hf.height;
340
const int spanCount = rcGetHeightFieldSpanCount(ctx, hf);
345
chf.spanCount = spanCount;
346
chf.walkableHeight = walkableHeight;
347
chf.walkableClimb = walkableClimb;
349
rcVcopy(chf.bmin, hf.bmin);
350
rcVcopy(chf.bmax, hf.bmax);
351
chf.bmax[1] += walkableHeight*hf.ch;
354
chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*w*h, RC_ALLOC_PERM);
357
ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", w*h);
360
memset(chf.cells, 0, sizeof(rcCompactCell)*w*h);
361
chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*spanCount, RC_ALLOC_PERM);
364
ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount);
367
memset(chf.spans, 0, sizeof(rcCompactSpan)*spanCount);
368
chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*spanCount, RC_ALLOC_PERM);
371
ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount);
374
memset(chf.areas, RC_NULL_AREA, sizeof(unsigned char)*spanCount);
376
const int MAX_HEIGHT = 0xffff;
378
// Fill in cells and spans.
380
for (int y = 0; y < h; ++y)
382
for (int x = 0; x < w; ++x)
384
const rcSpan* s = hf.spans[x + y*w];
385
// If there are no spans at this cell, just leave the data to index=0, count=0.
387
rcCompactCell& c = chf.cells[x+y*w];
392
if (s->area != RC_NULL_AREA)
394
const int bot = (int)s->smax;
395
const int top = s->next ? (int)s->next->smin : MAX_HEIGHT;
396
chf.spans[idx].y = (unsigned short)rcClamp(bot, 0, 0xffff);
397
chf.spans[idx].h = (unsigned char)rcClamp(top - bot, 0, 0xff);
398
chf.areas[idx] = s->area;
407
// Find neighbour connections.
408
const int MAX_LAYERS = RC_NOT_CONNECTED-1;
409
int tooHighNeighbour = 0;
410
for (int y = 0; y < h; ++y)
412
for (int x = 0; x < w; ++x)
414
const rcCompactCell& c = chf.cells[x+y*w];
415
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
417
rcCompactSpan& s = chf.spans[i];
419
for (int dir = 0; dir < 4; ++dir)
421
rcSetCon(s, dir, RC_NOT_CONNECTED);
422
const int nx = x + rcGetDirOffsetX(dir);
423
const int ny = y + rcGetDirOffsetY(dir);
424
// First check that the neighbour cell is in bounds.
425
if (nx < 0 || ny < 0 || nx >= w || ny >= h)
428
// Iterate over all neighbour spans and check if any of the is
429
// accessible from current cell.
430
const rcCompactCell& nc = chf.cells[nx+ny*w];
431
for (int k = (int)nc.index, nk = (int)(nc.index+nc.count); k < nk; ++k)
433
const rcCompactSpan& ns = chf.spans[k];
434
const int bot = rcMax(s.y, ns.y);
435
const int top = rcMin(s.y+s.h, ns.y+ns.h);
437
// Check that the gap between the spans is walkable,
438
// and that the climb height between the gaps is not too high.
439
if ((top - bot) >= walkableHeight && rcAbs((int)ns.y - (int)s.y) <= walkableClimb)
441
// Mark direction as walkable.
442
const int idx = k - (int)nc.index;
443
if (idx < 0 || idx > MAX_LAYERS)
445
tooHighNeighbour = rcMax(tooHighNeighbour, idx);
448
rcSetCon(s, dir, idx);
458
if (tooHighNeighbour > MAX_LAYERS)
460
ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers %d (max: %d)",
461
tooHighNeighbour, MAX_LAYERS);
464
ctx->stopTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
470
static int getHeightfieldMemoryUsage(const rcHeightfield& hf)
474
size += hf.width * hf.height * sizeof(rcSpan*);
476
rcSpanPool* pool = hf.pools;
479
size += (sizeof(rcSpanPool) - sizeof(rcSpan)) + sizeof(rcSpan)*RC_SPANS_PER_POOL;
485
static int getCompactHeightFieldMemoryusage(const rcCompactHeightfield& chf)
488
size += sizeof(rcCompactHeightfield);
489
size += sizeof(rcCompactSpan) * chf.spanCount;
490
size += sizeof(rcCompactCell) * chf.width * chf.height;
b'\\ No newline at end of file'