diff --git a/server/gameserver/navmeshbuilder.cc b/server/gameserver/navmeshbuilder.cc index 84bd198..5acfc2e 100644 --- a/server/gameserver/navmeshbuilder.cc +++ b/server/gameserver/navmeshbuilder.cc @@ -19,6 +19,8 @@ #include "entity.h" #include "metamgr.h" +#include "navmeshhelper.h" + static const float kAgentMaxSlope = 90; static const float kAgentHeight = 1; static const float kAgentMaxClimb = 1; @@ -37,244 +39,9 @@ static const int kTileSize = 48; static const float kDetailSampleDist = 1; static const float kDetailSampleMaxError = 1; -static const int EXPECTED_LAYERS_PER_TILE = 4; - -static const int MAX_LAYERS = 32; - static const int kMaxTiles = 0; static const int kMaxPolysPerTile = 0; -/// Mask of the ceil part of the area id (3 lower bits) -/// the 0 value (RC_NULL_AREA) is left unused -static const unsigned char SAMPLE_POLYAREA_TYPE_MASK = 0x07; -/// Value for the kind of ceil "ground" -static const unsigned char SAMPLE_POLYAREA_TYPE_GROUND = 0x1; -/// Value for the kind of ceil "water" -static const unsigned char SAMPLE_POLYAREA_TYPE_WATER = 0x2; -/// Value for the kind of ceil "road" -static const unsigned char SAMPLE_POLYAREA_TYPE_ROAD = 0x3; -/// Value for the kind of ceil "grass" -static const unsigned char SAMPLE_POLYAREA_TYPE_GRASS = 0x4; -/// Flag for door area. Can be combined with area types and jump flag. -static const unsigned char SAMPLE_POLYAREA_FLAG_DOOR = 0x08; -/// Flag for jump area. Can be combined with area types and door flag. -static const unsigned char SAMPLE_POLYAREA_FLAG_JUMP = 0x10; - -struct TileCacheData -{ - unsigned char* data; - int dataSize; -}; - -struct rcChunkyTriMeshNode -{ - float bmin[2]; - float bmax[2]; - int i; - int n; -}; - -struct rcChunkyTriMesh -{ - inline rcChunkyTriMesh() : nodes(0), nnodes(0), tris(0), ntris(0), maxTrisPerChunk(0) {}; - inline ~rcChunkyTriMesh() { delete [] nodes; delete [] tris; } - - rcChunkyTriMeshNode* nodes; - int nnodes; - int* tris; - int ntris; - int maxTrisPerChunk; - -private: - // Explicitly disabled copy constructor and copy assignment operator. - #if 0 - rcChunkyTriMesh(const rcChunkyTriMesh&); - rcChunkyTriMesh& operator=(const rcChunkyTriMesh&); - #endif -}; - -static const int MAX_CONVEXVOL_PTS = 12; -struct ConvexVolume -{ - ConvexVolume(): areaMod(RC_AREA_FLAGS_MASK) {} - float verts[MAX_CONVEXVOL_PTS*3]; - float hmin, hmax; - int nverts; - rcAreaModification areaMod; -}; - -inline bool checkOverlapRect(const float amin[2], const float amax[2], - const float bmin[2], const float bmax[2]) -{ - bool overlap = true; - overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap; - overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap; - return overlap; -} - -static int rcGetChunksOverlappingRect(const rcChunkyTriMesh* cm, - float bmin[2], float bmax[2], - int* ids, const int maxIds) -{ - // Traverse tree - int i = 0; - int n = 0; - while (i < cm->nnodes) { - const rcChunkyTriMeshNode* node = &cm->nodes[i]; - const bool overlap = checkOverlapRect(bmin, bmax, node->bmin, node->bmax); - const bool isLeafNode = node->i >= 0; - - if (isLeafNode && overlap) { - if (n < maxIds) { - ids[n] = i; - n++; - } - } - - if (overlap || isLeafNode) - i++; - else { - const int escapeIndex = -node->i; - i += escapeIndex; - } - } - return n; -} - -struct RasterizationContext -{ - RasterizationContext() : - solid(0), - triareas(0), - lset(0), - chf(0), - ntiles(0) - { - memset(tiles, 0, sizeof(TileCacheData)*MAX_LAYERS); - } - - ~RasterizationContext() - { - rcFreeHeightField(solid); - delete [] triareas; - rcFreeHeightfieldLayerSet(lset); - rcFreeCompactHeightfield(chf); - for (int i = 0; i < MAX_LAYERS; ++i) - { - dtFree(tiles[i].data); - tiles[i].data = 0; - } - } - - rcHeightfield* solid; - unsigned char* triareas; - rcHeightfieldLayerSet* lset; - rcCompactHeightfield* chf; - TileCacheData tiles[MAX_LAYERS]; - int ntiles; -}; - -struct LinearAllocator : public dtTileCacheAlloc -{ - unsigned char* buffer; - size_t capacity; - size_t top; - size_t high; - - LinearAllocator(const size_t cap) : buffer(0), capacity(0), top(0), high(0) - { - resize(cap); - } - - ~LinearAllocator() - { - dtFree(buffer); - } - - void resize(const size_t cap) - { - if (buffer) dtFree(buffer); - buffer = (unsigned char*)dtAlloc(cap, DT_ALLOC_PERM); - capacity = cap; - } - - virtual void reset() - { - high = dtMax(high, top); - top = 0; - } - - virtual void* alloc(const size_t size) - { - if (!buffer) - return 0; - if (top+size > capacity) - return 0; - unsigned char* mem = &buffer[top]; - top += size; - return mem; - } - - virtual void free(void* /*ptr*/) - { - // Empty - } -}; - -struct FastLZCompressor : public dtTileCacheCompressor -{ - virtual int maxCompressedSize(const int bufferSize) - { - return (int)(bufferSize* 1.05f); - } - - virtual dtStatus compress(const unsigned char* buffer, const int bufferSize, - unsigned char* compressed, const int /*maxCompressedSize*/, int* compressedSize) - { - *compressedSize = fastlz_compress((const void *const)buffer, bufferSize, compressed); - return DT_SUCCESS; - } - - virtual dtStatus decompress(const unsigned char* compressed, const int compressedSize, - unsigned char* buffer, const int maxBufferSize, int* bufferSize) - { - *bufferSize = fastlz_decompress(compressed, compressedSize, buffer, maxBufferSize); - return *bufferSize < 0 ? DT_FAILURE : DT_SUCCESS; - } -}; - -struct MeshProcess : public dtTileCacheMeshProcess -{ - inline MeshProcess() - { - } - - virtual void process(struct dtNavMeshCreateParams* params, - unsigned char* polyAreas, - unsigned short* polyFlags) - { -#if 0 - // Update poly flags from areas. - for (int i = 0; i < params->polyCount; ++i) - { - polyFlags[i] = sampleAreaToFlags(polyAreas[i]); - } - - // Pass in off-mesh connections. - if (m_geom) - { - params->offMeshConVerts = m_geom->getOffMeshConnectionVerts(); - params->offMeshConRad = m_geom->getOffMeshConnectionRads(); - params->offMeshConDir = m_geom->getOffMeshConnectionDirs(); - params->offMeshConAreas = m_geom->getOffMeshConnectionAreas(); - params->offMeshConFlags = m_geom->getOffMeshConnectionFlags(); - params->offMeshConUserID = m_geom->getOffMeshConnectionId(); - params->offMeshConCount = m_geom->getOffMeshConnectionCount(); - } -#endif - } -}; - void NavMeshBuilder::Init() { diff --git a/server/gameserver/navmeshhelper.cc b/server/gameserver/navmeshhelper.cc new file mode 100644 index 0000000..e69de29 diff --git a/server/gameserver/navmeshhelper.h b/server/gameserver/navmeshhelper.h new file mode 100644 index 0000000..ec987f1 --- /dev/null +++ b/server/gameserver/navmeshhelper.h @@ -0,0 +1,236 @@ +#pragma once + +static const int EXPECTED_LAYERS_PER_TILE = 4; + +static const int MAX_LAYERS = 32; + +/// Mask of the ceil part of the area id (3 lower bits) +/// the 0 value (RC_NULL_AREA) is left unused +static const unsigned char SAMPLE_POLYAREA_TYPE_MASK = 0x07; +/// Value for the kind of ceil "ground" +static const unsigned char SAMPLE_POLYAREA_TYPE_GROUND = 0x1; +/// Value for the kind of ceil "water" +static const unsigned char SAMPLE_POLYAREA_TYPE_WATER = 0x2; +/// Value for the kind of ceil "road" +static const unsigned char SAMPLE_POLYAREA_TYPE_ROAD = 0x3; +/// Value for the kind of ceil "grass" +static const unsigned char SAMPLE_POLYAREA_TYPE_GRASS = 0x4; +/// Flag for door area. Can be combined with area types and jump flag. +static const unsigned char SAMPLE_POLYAREA_FLAG_DOOR = 0x08; +/// Flag for jump area. Can be combined with area types and door flag. +static const unsigned char SAMPLE_POLYAREA_FLAG_JUMP = 0x10; + +struct TileCacheData +{ + unsigned char* data; + int dataSize; +}; + +struct rcChunkyTriMeshNode +{ + float bmin[2]; + float bmax[2]; + int i; + int n; +}; + +struct rcChunkyTriMesh +{ + inline rcChunkyTriMesh() : nodes(0), nnodes(0), tris(0), ntris(0), maxTrisPerChunk(0) {}; + inline ~rcChunkyTriMesh() { delete [] nodes; delete [] tris; } + + rcChunkyTriMeshNode* nodes; + int nnodes; + int* tris; + int ntris; + int maxTrisPerChunk; + +private: + // Explicitly disabled copy constructor and copy assignment operator. + #if 0 + rcChunkyTriMesh(const rcChunkyTriMesh&); + rcChunkyTriMesh& operator=(const rcChunkyTriMesh&); + #endif +}; + +static const int MAX_CONVEXVOL_PTS = 12; +struct ConvexVolume +{ + ConvexVolume(): areaMod(RC_AREA_FLAGS_MASK) {} + float verts[MAX_CONVEXVOL_PTS*3]; + float hmin, hmax; + int nverts; + rcAreaModification areaMod; +}; + +inline bool checkOverlapRect(const float amin[2], const float amax[2], + const float bmin[2], const float bmax[2]) +{ + bool overlap = true; + overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap; + overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap; + return overlap; +} + +int rcGetChunksOverlappingRect(const rcChunkyTriMesh* cm, + float bmin[2], float bmax[2], + int* ids, const int maxIds) +{ + // Traverse tree + int i = 0; + int n = 0; + while (i < cm->nnodes) { + const rcChunkyTriMeshNode* node = &cm->nodes[i]; + const bool overlap = checkOverlapRect(bmin, bmax, node->bmin, node->bmax); + const bool isLeafNode = node->i >= 0; + + if (isLeafNode && overlap) { + if (n < maxIds) { + ids[n] = i; + n++; + } + } + + if (overlap || isLeafNode) + i++; + else { + const int escapeIndex = -node->i; + i += escapeIndex; + } + } + return n; +} + +struct RasterizationContext +{ + RasterizationContext() : + solid(0), + triareas(0), + lset(0), + chf(0), + ntiles(0) + { + memset(tiles, 0, sizeof(TileCacheData)*MAX_LAYERS); + } + + ~RasterizationContext() + { + rcFreeHeightField(solid); + delete [] triareas; + rcFreeHeightfieldLayerSet(lset); + rcFreeCompactHeightfield(chf); + for (int i = 0; i < MAX_LAYERS; ++i) + { + dtFree(tiles[i].data); + tiles[i].data = 0; + } + } + + rcHeightfield* solid; + unsigned char* triareas; + rcHeightfieldLayerSet* lset; + rcCompactHeightfield* chf; + TileCacheData tiles[MAX_LAYERS]; + int ntiles; +}; + +struct LinearAllocator : public dtTileCacheAlloc +{ + unsigned char* buffer; + size_t capacity; + size_t top; + size_t high; + + LinearAllocator(const size_t cap) : buffer(0), capacity(0), top(0), high(0) + { + resize(cap); + } + + ~LinearAllocator() + { + dtFree(buffer); + } + + void resize(const size_t cap) + { + if (buffer) dtFree(buffer); + buffer = (unsigned char*)dtAlloc(cap, DT_ALLOC_PERM); + capacity = cap; + } + + virtual void reset() + { + high = dtMax(high, top); + top = 0; + } + + virtual void* alloc(const size_t size) + { + if (!buffer) + return 0; + if (top+size > capacity) + return 0; + unsigned char* mem = &buffer[top]; + top += size; + return mem; + } + + virtual void free(void* /*ptr*/) + { + // Empty + } +}; + +struct FastLZCompressor : public dtTileCacheCompressor +{ + virtual int maxCompressedSize(const int bufferSize) + { + return (int)(bufferSize* 1.05f); + } + + virtual dtStatus compress(const unsigned char* buffer, const int bufferSize, + unsigned char* compressed, const int /*maxCompressedSize*/, int* compressedSize) + { + *compressedSize = fastlz_compress((const void *const)buffer, bufferSize, compressed); + return DT_SUCCESS; + } + + virtual dtStatus decompress(const unsigned char* compressed, const int compressedSize, + unsigned char* buffer, const int maxBufferSize, int* bufferSize) + { + *bufferSize = fastlz_decompress(compressed, compressedSize, buffer, maxBufferSize); + return *bufferSize < 0 ? DT_FAILURE : DT_SUCCESS; + } +}; + +struct MeshProcess : public dtTileCacheMeshProcess +{ + inline MeshProcess() + { + } + + virtual void process(struct dtNavMeshCreateParams* params, + unsigned char* polyAreas, + unsigned short* polyFlags) + { +#if 0 + // Update poly flags from areas. + for (int i = 0; i < params->polyCount; ++i) + { + polyFlags[i] = sampleAreaToFlags(polyAreas[i]); + } + + // Pass in off-mesh connections. + if (m_geom) + { + params->offMeshConVerts = m_geom->getOffMeshConnectionVerts(); + params->offMeshConRad = m_geom->getOffMeshConnectionRads(); + params->offMeshConDir = m_geom->getOffMeshConnectionDirs(); + params->offMeshConAreas = m_geom->getOffMeshConnectionAreas(); + params->offMeshConFlags = m_geom->getOffMeshConnectionFlags(); + params->offMeshConUserID = m_geom->getOffMeshConnectionId(); + params->offMeshConCount = m_geom->getOffMeshConnectionCount(); + } +#endif + } +};