Created
December 2, 2010 23:43
-
-
Save vermie/726329 to your computer and use it in GitHub Desktop.
solomesh tile approach
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/contrib/mmap/src/MapBuilder.cpp b/contrib/mmap/src/MapBuilder.cpp | |
index 43330f5..453b936 100644 | |
--- a/contrib/mmap/src/MapBuilder.cpp | |
+++ b/contrib/mmap/src/MapBuilder.cpp | |
@@ -650,10 +650,9 @@ namespace MMAP | |
// old code for non-statically assigned bitmask sizes: | |
///*** calculate number of bits needed to store tiles & polys ***/ | |
- //uint32 tileCount = tiles->size() * rcSqr(TILES_PER_MMTILE); | |
- //tileBits = dtIlog2(dtNextPow2(tileCount); | |
+ //int tileBits = dtIlog2(dtNextPow2(tiles->size())); | |
//if (tileBits < 1) tileBits = 1; // need at least one bit! | |
- //polyBits = sizeof(dtPolyRef)*8 - SALT_MIN_BITS - tileBits; | |
+ //int polyBits = sizeof(dtPolyRef)*8 - SALT_MIN_BITS - tileBits; | |
int tileBits = STATIC_TILE_BITS; | |
int polyBits = STATIC_POLY_BITS; | |
@@ -689,8 +688,8 @@ namespace MMAP | |
// navmesh creation params | |
dtNavMeshParams navMeshParams; | |
memset(&navMeshParams, 0, sizeof(dtNavMeshParams)); | |
- navMeshParams.tileWidth = GRID_SIZE / TILES_PER_MMTILE; | |
- navMeshParams.tileHeight = GRID_SIZE / TILES_PER_MMTILE; | |
+ navMeshParams.tileWidth = GRID_SIZE; | |
+ navMeshParams.tileHeight = GRID_SIZE; | |
rcVcopy(navMeshParams.orig, bmin); | |
navMeshParams.maxTiles = maxTiles; | |
navMeshParams.maxPolys = maxPolysPerTile; | |
@@ -728,27 +727,7 @@ namespace MMAP | |
// console output | |
char tileString[10]; | |
sprintf(tileString, "[%02i,%02i]: ", tileX, tileY); | |
- | |
- // open the file for writing | |
- char fileName[255]; | |
- sprintf(fileName, "mmaps/%03u%02i%02i.mmtile", mapID, tileY, tileX); | |
- FILE* file = fopen(fileName, "wb"); | |
- if (!file) | |
- { | |
- char message[1024]; | |
- sprintf(message, "Failed to open %s for writing!\n", fileName); | |
- perror(message); | |
- return; | |
- } | |
- | |
- mmapTileHeader header(m_terrainBuilder); | |
- fwrite(&header, sizeof(header), 1, file); | |
- | |
- float cellSize = 0.5f; // larger number => less voxels => faster build time | |
- // too large, and tight spaces won't be pathable. | |
- float agentHeight = 1.5f; | |
- float agentRadius = 0.5f; | |
- float agentMaxClimb = 1.65f; | |
+ printf("%s Building movemap tiles... \r", tileString); | |
IntermediateValues iv; | |
initIntermediateValues(iv); | |
@@ -764,316 +743,352 @@ namespace MMAP | |
int lTriCount = meshData.liquidTris.size() / 3; | |
uint8* lTriFlags = meshData.liquidType.getCArray(); | |
- // init detour tile bounds | |
- float tileMin[3], tileMax[3]; | |
- rcVcopy(tileMin, bmin); | |
- rcVcopy(tileMax, bmax); | |
+ // these are WORLD UNIT based metrics | |
+ // this are basic unit dimentions | |
+ // value have to divide GRID_SIZE(533.33333f) ( aka: 0.5333, 0.3333, 0.1333, etc ) | |
+ const static float BASE_UNIT_DIM = 0.53333333f; | |
+ | |
+ // All are in UNIT metrics! | |
+ const static int VERTEX_PER_MAP = int(GRID_SIZE/BASE_UNIT_DIM + 0.5f); | |
+ const static int VERTEX_PER_TILE = 40; // must divide VERTEX_PER_MAP | |
+ const static int TILES_PER_MAP = VERTEX_PER_MAP/VERTEX_PER_TILE; | |
- /* init mmtile config */ | |
rcConfig config; | |
memset(&config, 0, sizeof(rcConfig)); | |
- config.maxVertsPerPoly = 6; | |
- // these are WORLD UNIT based metrics | |
- config.cs = cellSize; | |
- config.ch = .3f; | |
- config.walkableSlopeAngle = m_maxWalkableAngle; | |
+ rcVcopy(config.bmin, bmin); | |
+ rcVcopy(config.bmax, bmax); | |
- // these are VOXEL-based metrics | |
- config.tileSize = (int)ceilf(TILE_SIZE / config.cs); | |
- config.walkableRadius = (int)ceilf(agentRadius / config.cs); | |
+ config.maxVertsPerPoly = DT_VERTS_PER_POLYGON; | |
+ config.cs = BASE_UNIT_DIM; | |
+ config.ch = BASE_UNIT_DIM; | |
+ config.walkableSlopeAngle = m_maxWalkableAngle; | |
+ config.tileSize = VERTEX_PER_TILE; | |
+ config.walkableRadius = 1; | |
config.borderSize = config.walkableRadius + 3; | |
- config.maxEdgeLen = 1500; | |
- config.walkableHeight = (int)ceilf(agentHeight / config.ch); | |
- config.walkableClimb = (int)ceilf(agentHeight / config.ch); | |
- config.minRegionArea = (int)rcSqr(50); | |
- config.mergeRegionArea = (int)rcSqr(20); | |
- config.maxSimplificationError = 1.3f; | |
- config.detailSampleDist = config.cs * 16.f; | |
- config.detailSampleMaxError = config.ch * 1.f; | |
- | |
- vector<dtTileRef> finishedTiles; | |
- | |
- for (uint32 x = 0; x < TILES_PER_MMTILE; ++x) | |
+ config.maxEdgeLen = VERTEX_PER_TILE + 1; //anything bigger than tileSize | |
+ config.walkableHeight = 3; | |
+ config.walkableClimb = 2; // keep less than walkableHeight | |
+ config.minRegionArea = rcSqr(50); | |
+ config.mergeRegionArea = rcSqr(30); | |
+ config.maxSimplificationError = 2.5f; // eliminates most jagged edges (tinny polygons) | |
+ config.detailSampleDist = config.cs * 8; | |
+ config.detailSampleMaxError = config.ch * 2; | |
+ | |
+ // this sets the dimensions of the heightfield - should maybe happen before border padding | |
+ rcCalcGridSize(config.bmin, config.bmax, config.cs, &config.width, &config.height); | |
+ | |
+ // allocate subregions : tiles | |
+ TileSet* tileSet = new TileSet; | |
+ rcVcopy(tileSet->bmin, config.bmin); | |
+ rcVcopy(tileSet->bmax, config.bmax); | |
+ tileSet->cs = config.cs; | |
+ tileSet->ch = config.ch; | |
+ tileSet->width = TILES_PER_MAP; | |
+ tileSet->height = TILES_PER_MAP; | |
+ tileSet->tiles = new Tile[tileSet->height * tileSet->width]; | |
+ | |
+ // Initialize per tile config. | |
+ rcConfig tileCfg; | |
+ memcpy(&tileCfg, &config, sizeof(rcConfig)); | |
+ tileCfg.width = config.tileSize + config.borderSize*2; | |
+ tileCfg.height = config.tileSize + config.borderSize*2; | |
+ | |
+ // build all tiles | |
+ for (int y = 0; y < tileSet->height; ++y) | |
{ | |
- tileMin[0] = bmin[0] + TILE_SIZE * x; | |
- tileMax[0] = tileMin[0] + TILE_SIZE; | |
- | |
- for (uint32 y = 0; y < TILES_PER_MMTILE; ++y) | |
+ for (int x = 0; x < tileSet->width; ++x) | |
{ | |
- tileMin[2] = bmin[2] + TILE_SIZE * y; | |
- tileMax[2] = tileMin[2] + TILE_SIZE; | |
- | |
- clearIntermediateValues(iv); | |
- | |
- /* tile-specific config settings */ | |
- rcVcopy(config.bmin, tileMin); | |
- rcVcopy(config.bmax, tileMax); | |
- | |
- // pad bounds with a border | |
- float pad = config.borderSize*config.cs; | |
- config.bmin[0] -= pad; | |
- config.bmin[2] -= pad; | |
- config.bmax[0] += pad; | |
- config.bmax[2] += pad; | |
- | |
- // this sets the dimensions of the heightfield - should maybe happen before border padding | |
- rcCalcGridSize(config.bmin, config.bmax, config.cs, &config.width, &config.height); | |
- | |
- /* start build */ | |
+ Tile& tile = tileSet->tiles[x + y*tileSet->width]; | |
+ tile.x = x; | |
+ tile.y = y; | |
+ | |
+ // Calculate the per tile bounding box. | |
+ tileCfg.bmin[0] = config.bmin[0] + (x*config.tileSize - config.borderSize)*config.cs; | |
+ tileCfg.bmin[2] = config.bmin[2] + (y*config.tileSize - config.borderSize)*config.cs; | |
+ tileCfg.bmax[0] = config.bmin[0] + ((x+1)*config.tileSize + config.borderSize)*config.cs; | |
+ tileCfg.bmax[2] = config.bmin[2] + ((y+1)*config.tileSize + config.borderSize)*config.cs; | |
+ | |
+ float tbmin[2], tbmax[2]; | |
+ tbmin[0] = tileCfg.bmin[0]; | |
+ tbmin[1] = tileCfg.bmin[2]; | |
+ tbmax[0] = tileCfg.bmax[0]; | |
+ tbmax[1] = tileCfg.bmax[2]; | |
// build heightfield | |
- printf("%sBuilding Recast Heightfield... \r", tileString); | |
- iv.heightfield = rcAllocHeightfield(); | |
- if (!iv.heightfield || !rcCreateHeightfield(m_rcContext, *iv.heightfield, config.width, config.height, config.bmin, config.bmax, config.cs, config.ch)) | |
+ tile.solid = rcAllocHeightfield(); | |
+ if (!tile.solid || !rcCreateHeightfield(m_rcContext, *tile.solid, tileCfg.width, tileCfg.height, tileCfg.bmin, tileCfg.bmax, tileCfg.cs, tileCfg.ch)) | |
{ | |
printf("%sFailed building heightfield! \n", tileString); | |
continue; | |
} | |
- printf("%sRasterizing triangles... \r", tileString); | |
- | |
- // flag walkable terrain triangles | |
- iv.triFlags = (unsigned char*)dtAlloc(sizeof(unsigned char)*tTriCount, DT_ALLOC_PERM); | |
- memset(iv.triFlags, NAV_GROUND, tTriCount*sizeof(unsigned char)); | |
- rcClearUnwalkableTriangles(m_rcContext, config.walkableSlopeAngle, tVerts, tVertCount, tTris, tTriCount, iv.triFlags); | |
- rcRasterizeTriangles(m_rcContext, tVerts, tVertCount, tTris, iv.triFlags, tTriCount, *iv.heightfield, config.walkableClimb); | |
- dtFree(iv.triFlags); | |
- iv.triFlags = NULL; | |
+ // mark all walkable tiles, both liquids and solids | |
+ unsigned char* triFlags = new unsigned char[tTriCount]; | |
+ memset(triFlags, NAV_GROUND, tTriCount*sizeof(unsigned char)); | |
+ rcClearUnwalkableTriangles(m_rcContext, tileCfg.walkableSlopeAngle, tVerts, tVertCount, tTris, tTriCount, triFlags); | |
+ rcRasterizeTriangles(m_rcContext, tVerts, tVertCount, tTris, triFlags, tTriCount, *tile.solid, config.walkableClimb); | |
+ delete [] triFlags; | |
- // filter out unwalkable spans (order of calls matters, see rcFilterLowHangingWalkableObstacles) | |
- rcFilterLowHangingWalkableObstacles(m_rcContext, config.walkableClimb, *iv.heightfield); | |
- rcFilterLedgeSpans(m_rcContext, config.walkableHeight, config.walkableClimb, *iv.heightfield); | |
- rcFilterWalkableLowHeightSpans(m_rcContext, config.walkableHeight, *iv.heightfield); | |
+ rcFilterLowHangingWalkableObstacles(m_rcContext, config.walkableClimb, *tile.solid); | |
+ rcFilterLedgeSpans(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid); | |
+ rcFilterWalkableLowHeightSpans(m_rcContext, tileCfg.walkableHeight, *tile.solid); | |
- // do after filtering because same rules don't apply to swimming | |
- rcRasterizeTriangles(m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, *iv.heightfield, config.walkableClimb); | |
+ rcRasterizeTriangles(m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, *tile.solid, config.walkableClimb); | |
// compact heightfield spans | |
- printf("%sCompacting heightfield... \r", tileString); | |
- iv.compactHeightfield = rcAllocCompactHeightfield(); | |
- if (!iv.compactHeightfield || !rcBuildCompactHeightfield(m_rcContext, config.walkableHeight, config.walkableClimb, *iv.heightfield, *iv.compactHeightfield)) | |
+ tile.chf = rcAllocCompactHeightfield(); | |
+ if (!tile.chf || !rcBuildCompactHeightfield(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid, *tile.chf)) | |
{ | |
printf("%sFailed compacting heightfield! \n", tileString); | |
continue; | |
} | |
- if (!m_debugOutput) | |
- { | |
- rcFreeHeightField(iv.heightfield); | |
- iv.heightfield = NULL; | |
- } | |
- | |
// build polymesh intermediates | |
- printf("%sEroding walkable area width... \r", tileString); | |
- if (!rcErodeWalkableArea(m_rcContext, config.walkableRadius, *iv.compactHeightfield)) | |
+ if (!rcErodeWalkableArea(m_rcContext, config.walkableRadius, *tile.chf)) | |
{ | |
printf("%sFailed eroding area! \n", tileString); | |
continue; | |
} | |
- printf("%sSmoothing area boundaries... \r", tileString); | |
- if (!rcMedianFilterWalkableArea(m_rcContext, *iv.compactHeightfield)) | |
- { | |
- printf("%sFailed median filter! \n", tileString); | |
- continue; | |
- } | |
- | |
- printf("%sBuilding distance field... \r", tileString); | |
- if (!rcBuildDistanceField(m_rcContext, *iv.compactHeightfield)) | |
+ if (!rcBuildDistanceField(m_rcContext, *tile.chf)) | |
{ | |
printf("%sFailed building distance field! \n", tileString); | |
continue; | |
} | |
- // bottleneck is here | |
- printf("%sBuilding regions... \r", tileString); | |
- if (!rcBuildRegions(m_rcContext, *iv.compactHeightfield, config.borderSize, config.minRegionArea, config.mergeRegionArea)) | |
+ if (!rcBuildRegions(m_rcContext, *tile.chf, tileCfg.borderSize, tileCfg.minRegionArea, tileCfg.mergeRegionArea)) | |
{ | |
printf("%sFailed building regions! \n", tileString); | |
continue; | |
} | |
- printf("%sBuilding contours... \r", tileString); | |
- iv.contours = rcAllocContourSet(); | |
- if (!iv.contours || !rcBuildContours(m_rcContext, *iv.compactHeightfield, config.maxSimplificationError, config.maxEdgeLen, *iv.contours)) | |
+ tile.cset = rcAllocContourSet(); | |
+ if (!tile.cset || !rcBuildContours(m_rcContext, *tile.chf, tileCfg.maxSimplificationError, tileCfg.maxEdgeLen, *tile.cset)) | |
{ | |
printf("%sFailed building contours! \n", tileString); | |
continue; | |
} | |
// build polymesh | |
- printf("%sBuilding polymesh... \r", tileString); | |
- iv.polyMesh = rcAllocPolyMesh(); | |
- if (!iv.polyMesh || !rcBuildPolyMesh(m_rcContext, *iv.contours, config.maxVertsPerPoly, *iv.polyMesh)) | |
+ tile.pmesh = rcAllocPolyMesh(); | |
+ if (!tile.pmesh || !rcBuildPolyMesh(m_rcContext, *tile.cset, tileCfg.maxVertsPerPoly, *tile.pmesh)) | |
{ | |
printf("%sFailed building polymesh! \n", tileString); | |
continue; | |
} | |
- printf("%sBuilding polymesh detail... \r", tileString); | |
- iv.polyMeshDetail = rcAllocPolyMeshDetail(); | |
- if (!iv.polyMeshDetail || !rcBuildPolyMeshDetail(m_rcContext, *iv.polyMesh, *iv.compactHeightfield, config.detailSampleDist, config.detailSampleMaxError, *iv.polyMeshDetail)) | |
+ tile.dmesh = rcAllocPolyMeshDetail(); | |
+ if (!tile.dmesh || !rcBuildPolyMeshDetail(m_rcContext, *tile.pmesh, *tile.chf, tileCfg.detailSampleDist, tileCfg .detailSampleMaxError, *tile.dmesh)) | |
{ | |
printf("%sFailed building polymesh detail! \n", tileString); | |
continue; | |
} | |
- if (!m_debugOutput) | |
- { | |
- rcFreeCompactHeightfield(iv.compactHeightfield); | |
- iv.compactHeightfield = NULL; | |
- rcFreeContourSet(iv.contours); | |
- iv.contours = NULL; | |
- } | |
+ // free those up | |
+ // we may want to keep them in the future for debug | |
+ // but right now, we don't have the code to merge them | |
+ rcFreeHeightField(tile.solid); | |
+ tile.solid = NULL; | |
+ rcFreeCompactHeightfield(tile.chf); | |
+ tile.chf = NULL; | |
+ rcFreeContourSet(tile.cset); | |
+ tile.cset = NULL; | |
+ } | |
+ } | |
- // this might be handled within Recast at some point | |
- // very important, without this tiles do not get connected to neighbors!! | |
- printf("%sCleaning vertex padding... \r", tileString); | |
- for (int i = 0; i < iv.polyMesh->nverts; ++i) | |
- { | |
- unsigned short* v = &iv.polyMesh->verts[i*3]; | |
- v[0] -= (unsigned short)config.borderSize; | |
- v[2] -= (unsigned short)config.borderSize; | |
- } | |
+ // merge per tile poly and detail meshes | |
+ rcPolyMesh** pmmerge = new rcPolyMesh*[tileSet->width*tileSet->height]; | |
+ if (!pmmerge) | |
+ { | |
+ printf("%s alloc pmmerge FIALED! \r", tileString); | |
+ return; | |
+ } | |
- // polymesh vertex indices are stored with ushorts in detour, can't have more than 65535 | |
- if (iv.polyMesh->nverts >= 0xffff) | |
- { | |
- printf("%sToo many vertices! \n", tileString); | |
- continue; | |
- } | |
+ rcPolyMeshDetail** dmmerge = new rcPolyMeshDetail*[tileSet->width*tileSet->height]; | |
+ if (!dmmerge) | |
+ { | |
+ printf("%s alloc dmmerge FIALED! \r", tileString); | |
+ return; | |
+ } | |
- printf("%sSetting polys as walkable... \r", tileString); | |
- // handle area type here | |
- // TODO: special flag for DYNAMIC polygons, ie surfaces that can be turned on and off | |
- for (int i = 0; i < iv.polyMesh->npolys; ++i) | |
- if (iv.polyMesh->areas[i] & RC_WALKABLE_AREA) | |
- iv.polyMesh->flags[i] = iv.polyMesh->areas[i]; | |
- | |
- dtNavMeshCreateParams params; | |
- memset(¶ms, 0, sizeof(params)); | |
- params.verts = iv.polyMesh->verts; | |
- params.vertCount = iv.polyMesh->nverts; | |
- params.polys = iv.polyMesh->polys; | |
- params.polyAreas = iv.polyMesh->areas; | |
- params.polyFlags = iv.polyMesh->flags; | |
- params.polyCount = iv.polyMesh->npolys; | |
- params.nvp = iv.polyMesh->nvp; | |
- params.detailMeshes = iv.polyMeshDetail->meshes; | |
- params.detailVerts = iv.polyMeshDetail->verts; | |
- params.detailVertsCount = iv.polyMeshDetail->nverts; | |
- params.detailTris = iv.polyMeshDetail->tris; | |
- params.detailTriCount = iv.polyMeshDetail->ntris; | |
- params.walkableHeight = agentHeight; | |
- params.walkableRadius = agentRadius; | |
- params.walkableClimb = agentMaxClimb; | |
- float pos[3] = {(tileMin[0] + tileMax[0]) / 2, 0.f, (tileMin[2] + tileMax[2]) / 2}; // center of current dtTile | |
- navMesh->calcTileLoc(pos, ¶ms.tileX, ¶ms.tileY); | |
- rcVcopy(params.bmin, tileMin); | |
- rcVcopy(params.bmax, tileMax); | |
- params.cs = config.cs; | |
- params.ch = config.ch; | |
- params.tileSize = config.tileSize; | |
- | |
- // will hold final navmesh | |
- unsigned char* navData = NULL; | |
- int navDataSize = 0; | |
- | |
- // these values are checked within dtCreateNavMeshData - handle them here | |
- // so we have a clear error message | |
- if (params.nvp > DT_VERTS_PER_POLYGON) | |
- { | |
- printf("%sInvalid verts-per-polygon value! \n", tileString); | |
- continue; | |
- } | |
- if (params.vertCount >= 0xffff) | |
+ int nmerge = 0; | |
+ for (int y = 0; y < tileSet->height; ++y) | |
+ { | |
+ for (int x = 0; x < tileSet->width; ++x) | |
+ { | |
+ Tile& tile = tileSet->tiles[x + y*tileSet->width]; | |
+ if (tile.pmesh) | |
{ | |
- printf("%sToo many vertices! \n", tileString); | |
- continue; | |
+ pmmerge[nmerge] = tile.pmesh; | |
+ dmmerge[nmerge] = tile.dmesh; | |
+ nmerge++; | |
} | |
- if (!params.vertCount || !params.verts) | |
- { | |
- // occurs mostly when adjacent tiles have models | |
- // loaded but those models don't span into this tile | |
+ } | |
+ } | |
- // message is an annoyance | |
- //printf("%sNo vertices to build tile! \n", tileString); | |
- continue; | |
- } | |
- if (!params.polyCount || !params.polys) | |
- { | |
- printf("%sNo polygons to build tile! \n", tileString); | |
- continue; | |
- } | |
- if (!params.detailMeshes || !params.detailVerts || !params.detailTris) | |
- { | |
- printf("%sNo detail mesh to build tile! \n", tileString); | |
- continue; | |
- } | |
+ iv.polyMesh = rcAllocPolyMesh(); | |
+ if (!iv.polyMesh) | |
+ { | |
+ printf("%s alloc iv.polyMesh FIALED! \r", tileString); | |
+ return; | |
+ } | |
+ rcMergePolyMeshes(m_rcContext, pmmerge, nmerge, *iv.polyMesh); | |
- printf("%sBuilding navmesh tile... \r", tileString); | |
- if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize)) | |
- { | |
- printf("%s Failed building navmesh tile! \n", tileString); | |
- continue; | |
- } | |
+ iv.polyMeshDetail = rcAllocPolyMeshDetail(); | |
+ if (!iv.polyMeshDetail) | |
+ { | |
+ printf("%s alloc m_dmesh FIALED! \r", tileString); | |
+ return; | |
+ } | |
+ rcMergePolyMeshDetails(m_rcContext, dmmerge, nmerge, *iv.polyMeshDetail); | |
- dtTileRef tileRef = 0; | |
- printf("%sAdding tile to navmesh... \r", tileString); | |
- // DT_TILE_FREE_DATA tells detour to unallocate memory when the tile | |
- // is removed via removeTile() | |
- dtStatus dtResult = navMesh->addTile(navData, navDataSize, 0, 0, &tileRef); | |
- if (!tileRef || dtResult != DT_SUCCESS) | |
- { | |
- printf("%sFailed adding tile to navmesh! \n", tileString); | |
- continue; | |
- } | |
+ // free things up | |
+ delete [] pmmerge; | |
+ delete [] dmmerge; | |
- // store tile ref so that tile can be written to disk later | |
- finishedTiles.push_back(tileRef); | |
- ++header.tileCount; | |
- | |
- // TODO: writing this to file does no good, debug data is just overwritten by next tile | |
- //if (m_debugOutput) | |
- //{ | |
- // for (int i = 0; i < iv.polyMesh->nverts; ++i) | |
- // { | |
- // unsigned short* v = &iv.polyMesh->verts[i*3]; | |
- // v[0] += (unsigned short)config.borderSize; | |
- // v[2] += (unsigned short)config.borderSize; | |
- // } | |
- // writeIV(mapID, tileX, tileY, iv); | |
- //} | |
- } | |
+ delete tileSet; | |
+ | |
+ // remove padding for extraction | |
+ for (int i = 0; i < iv.polyMesh->nverts; ++i) | |
+ { | |
+ unsigned short* v = &iv.polyMesh->verts[i*3]; | |
+ v[0] -= (unsigned short)config.borderSize; | |
+ v[2] -= (unsigned short)config.borderSize; | |
} | |
- printf("%sWriting to file... \r", tileString); | |
- for (vector<dtTileRef>::iterator it = finishedTiles.begin(); it != finishedTiles.end(); ++it) | |
+ // set polygons as walkable | |
+ // TODO: special flags for DYNAMIC polygons, ie surfaces that can be turned on and off | |
+ for (int i = 0; i < iv.polyMesh->npolys; ++i) | |
+ if (iv.polyMesh->areas[i] & RC_WALKABLE_AREA) | |
+ iv.polyMesh->flags[i] = iv.polyMesh->areas[i]; | |
+ | |
+ // setup mesh parameters | |
+ dtNavMeshCreateParams params; | |
+ memset(¶ms, 0, sizeof(params)); | |
+ params.verts = iv.polyMesh->verts; | |
+ params.vertCount = iv.polyMesh->nverts; | |
+ params.polys = iv.polyMesh->polys; | |
+ params.polyAreas = iv.polyMesh->areas; | |
+ params.polyFlags = iv.polyMesh->flags; | |
+ params.polyCount = iv.polyMesh->npolys; | |
+ params.nvp = iv.polyMesh->nvp; | |
+ params.detailMeshes = iv.polyMeshDetail->meshes; | |
+ params.detailVerts = iv.polyMeshDetail->verts; | |
+ params.detailVertsCount = iv.polyMeshDetail->nverts; | |
+ params.detailTris = iv.polyMeshDetail->tris; | |
+ params.detailTriCount = iv.polyMeshDetail->ntris; | |
+ params.walkableHeight = BASE_UNIT_DIM*config.walkableHeight; // agent height | |
+ params.walkableRadius = BASE_UNIT_DIM*config.walkableRadius; // agent radius | |
+ params.walkableClimb = BASE_UNIT_DIM*config.walkableClimb; // keep less that walkableHeight (aka agent height)! | |
+ params.tileX = (((bmin[0] + bmax[0]) / 2) - navMesh->getParams()->orig[0]) / GRID_SIZE; | |
+ params.tileY = (((bmin[2] + bmax[2]) / 2) - navMesh->getParams()->orig[2]) / GRID_SIZE; | |
+ rcVcopy(params.bmin, bmin); | |
+ rcVcopy(params.bmax, bmax); | |
+ params.cs = config.cs; | |
+ params.ch = config.ch; | |
+ params.tileSize = VERTEX_PER_MAP; | |
+ | |
+ // will hold final navmesh | |
+ unsigned char* navData = NULL; | |
+ int navDataSize = 0; | |
+ | |
+ do | |
{ | |
- int dataSize; | |
- unsigned char* data; | |
+ // these values are checked within dtCreateNavMeshData - handle them here | |
+ // so we have a clear error message | |
+ if (params.nvp > DT_VERTS_PER_POLYGON) | |
+ { | |
+ printf("%s Invalid verts-per-polygon value! \n", tileString); | |
+ continue; | |
+ } | |
+ if (params.vertCount >= 0xffff) | |
+ { | |
+ printf("%s Too many vertices! \n", tileString); | |
+ continue; | |
+ } | |
+ if (!params.vertCount || !params.verts) | |
+ { | |
+ // occurs mostly when adjacent tiles have models | |
+ // loaded but those models don't span into this tile | |
- // remove the tile from the mesh, and retrieve the tile's data so that | |
- // we can write it to disk | |
- navMesh->removeTile(*it, &data, &dataSize); | |
+ // message is an annoyance | |
+ //printf("%sNo vertices to build tile! \n", tileString); | |
+ continue; | |
+ } | |
+ if (!params.polyCount || !params.polys) | |
+ { | |
+ printf("%s No polygons to build tile! \n", tileString); | |
+ continue; | |
+ } | |
+ if (!params.detailMeshes || !params.detailVerts || !params.detailTris) | |
+ { | |
+ printf("%s No detail mesh to build tile! \n", tileString); | |
+ continue; | |
+ } | |
- fwrite(&dataSize, sizeof(dataSize), 1, file); | |
- fwrite(data, sizeof(unsigned char), dataSize, file); | |
+ printf("%s Building navmesh tile... \r", tileString); | |
+ if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize)) | |
+ { | |
+ printf("%s Failed building navmesh tile! \n", tileString); | |
+ continue; | |
+ } | |
- // free memory used by tile | |
- dtFree(data); | |
- } | |
+ dtTileRef tileRef = 0; | |
+ printf("%s Adding tile to navmesh... \r", tileString); | |
+ // DT_TILE_FREE_DATA tells detour to unallocate memory when the tile | |
+ // is removed via removeTile() | |
+ dtStatus dtResult = navMesh->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, &tileRef); | |
+ if (!tileRef || dtResult != DT_SUCCESS) | |
+ { | |
+ printf("%s Failed adding tile to navmesh! \n", tileString); | |
+ continue; | |
+ } | |
+ | |
+ // file output | |
+ char fileName[255]; | |
+ sprintf(fileName, "mmaps/%03u%02i%02i.mmtile", mapID, tileY, tileX); | |
+ FILE* file = fopen(fileName, "wb"); | |
+ if (!file) | |
+ { | |
+ char message[1024]; | |
+ sprintf(message, "Failed to open %s for writing!\n", fileName); | |
+ perror(message); | |
+ navMesh->removeTile(tileRef, NULL, NULL); | |
+ continue; | |
+ } | |
+ | |
+ printf("%s Writing to file... \r", tileString); | |
+ | |
+ // write header | |
+ mmapTileHeader header(m_terrainBuilder); | |
+ header.size = uint32(navDataSize); | |
+ fwrite(&header, sizeof(mmapTileHeader), 1, file); | |
+ | |
+ // write data | |
+ fwrite(navData, sizeof(unsigned char), navDataSize, file); | |
+ fclose(file); | |
+ | |
+ // now that tile is written to disk, we can unload it | |
+ navMesh->removeTile(tileRef, NULL, NULL); | |
+ } while (0); | |
- // re-write header, so that tilecount is up to date | |
- fseek(file, 0, SEEK_SET); | |
- fwrite(&header, sizeof(header), 1, file); | |
- fclose(file); | |
if (m_debugOutput) | |
+ { | |
+ // restore padding so that the debug visualization is correct | |
+ for (int i = 0; i < iv.polyMesh->nverts; ++i) | |
+ { | |
+ unsigned short* v = &iv.polyMesh->verts[i*3]; | |
+ v[0] += (unsigned short)config.borderSize; | |
+ v[2] += (unsigned short)config.borderSize; | |
+ } | |
+ | |
generateObjFile(mapID, tileX, tileY, meshData); | |
+ writeIV(mapID, tileX, tileY, iv); | |
+ } | |
- m_rcContext->resetLog(); | |
+ clearIntermediateValues(iv); | |
} | |
void MapBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax) | |
@@ -1098,7 +1113,6 @@ namespace MMAP | |
{ | |
iv.compactHeightfield = NULL; | |
iv.heightfield = NULL; | |
- iv.triFlags = NULL; | |
iv.contours = NULL; | |
iv.polyMesh = NULL; | |
iv.polyMeshDetail = NULL; | |
@@ -1111,7 +1125,6 @@ namespace MMAP | |
rcFreeContourSet(iv.contours); iv.contours = NULL; | |
rcFreePolyMesh(iv.polyMesh); iv.polyMesh = NULL; | |
rcFreePolyMeshDetail(iv.polyMeshDetail); iv.polyMeshDetail = NULL; | |
- dtFree(iv.triFlags); iv.triFlags = NULL; | |
} | |
void MapBuilder::generateObjFile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData meshData) | |
@@ -1119,7 +1132,7 @@ namespace MMAP | |
generateRealObj(mapID, tileX, tileY, meshData); | |
char tileString[25]; | |
- sprintf(tileString, "[%02u,%02u]: ", tileX, tileY); | |
+ sprintf(tileString, "[%02u,%02u]: ", tileY, tileX); | |
printf("%sWriting debug output... \r", tileString); | |
char objFileName[255]; | |
@@ -1219,24 +1232,26 @@ namespace MMAP | |
string name("meshes/%03u%02i%02i."); | |
#define DEBUG_WRITE(fileExtension,data) \ | |
- sprintf(fileName, (name + fileExtension).c_str(), mapID, tileY, tileX); \ | |
- file = fopen(fileName, "wb"); \ | |
- if (!file) \ | |
- { \ | |
- char message[1024]; \ | |
- sprintf(message, "%sFailed to open %s for writing!\n", tileString, fileName); \ | |
- perror(message); \ | |
- } \ | |
- else \ | |
- debugWrite(file, data); \ | |
- if(file) fclose(file); \ | |
- printf("%sWriting debug output... \r", tileString) | |
- | |
- DEBUG_WRITE("hf", iv.heightfield); | |
- DEBUG_WRITE("chf", iv.compactHeightfield); | |
- DEBUG_WRITE("cs", iv.contours); | |
- DEBUG_WRITE("pmesh", iv.polyMesh); | |
- DEBUG_WRITE("dmesh", iv.polyMeshDetail); | |
+ do { \ | |
+ sprintf(fileName, (name + fileExtension).c_str(), mapID, tileY, tileX); \ | |
+ file = fopen(fileName, "wb"); \ | |
+ if (!file) \ | |
+ { \ | |
+ char message[1024]; \ | |
+ sprintf(message, "%sFailed to open %s for writing!\n", tileString, fileName); \ | |
+ perror(message); \ | |
+ } \ | |
+ else \ | |
+ debugWrite(file, data); \ | |
+ if(file) fclose(file); \ | |
+ printf("%sWriting debug output... \r", tileString); \ | |
+ } while (false) | |
+ | |
+ if (iv.heightfield) DEBUG_WRITE("hf", iv.heightfield); | |
+ if (iv.compactHeightfield) DEBUG_WRITE("chf", iv.compactHeightfield); | |
+ if (iv.contours) DEBUG_WRITE("cs", iv.contours); | |
+ if (iv.polyMesh) DEBUG_WRITE("pmesh", iv.polyMesh); | |
+ if (iv.polyMeshDetail) DEBUG_WRITE("dmesh", iv.polyMeshDetail); | |
#undef DEBUG_WRITE | |
} | |
diff --git a/contrib/mmap/src/MapBuilder.h b/contrib/mmap/src/MapBuilder.h | |
index ce8dea4..e8b0d90 100644 | |
--- a/contrib/mmap/src/MapBuilder.h | |
+++ b/contrib/mmap/src/MapBuilder.h | |
@@ -35,11 +35,8 @@ using namespace std; | |
using namespace VMAP; | |
// G3D namespace typedefs conflicts with ACE typedefs | |
-#define MMAP_MAGIC 0x4d4d4150 // 'MMAP' | |
-#define MMAP_VERSION 1 | |
- | |
-#define TILES_PER_MMTILE 16 | |
-#define TILE_SIZE (GRID_SIZE / TILES_PER_MMTILE) | |
+#define MMAP_MAGIC 0x4d4d4150 | |
+#define MMAP_VERSION 2 | |
namespace MMAP | |
{ | |
@@ -48,7 +45,6 @@ namespace MMAP | |
struct IntermediateValues | |
{ | |
rcHeightfield* heightfield; | |
- unsigned char* triFlags; | |
rcCompactHeightfield* compactHeightfield; | |
rcContourSet* contours; | |
rcPolyMesh* polyMesh; | |
@@ -60,7 +56,7 @@ namespace MMAP | |
uint32 mmapMagic; | |
uint32 dtVersion; | |
uint32 mmapVersion; | |
- uint32 tileCount; | |
+ uint32 size; | |
bool usesHiRes : 1; | |
bool usesLiquids : 1; | |
@@ -68,21 +64,51 @@ namespace MMAP | |
mmapMagic(MMAP_MAGIC), | |
dtVersion(DT_NAVMESH_VERSION), | |
mmapVersion(MMAP_VERSION), | |
- tileCount(0) | |
+ size(0) | |
{} | |
mmapTileHeader(TerrainBuilder* terrainBuilder) : | |
mmapMagic(MMAP_MAGIC), | |
dtVersion(DT_NAVMESH_VERSION), | |
mmapVersion(MMAP_VERSION), | |
- tileCount(0) | |
+ size(0) | |
{ | |
usesHiRes = terrainBuilder->usesHiRes(); | |
usesLiquids = terrainBuilder->usesLiquids(); | |
} | |
private: | |
- mmapTileHeader(const mmapTileHeader &header); | |
+ mmapTileHeader(const mmapTileHeader& header); | |
+ }; | |
+ | |
+ struct Tile | |
+ { | |
+ inline Tile() : chf(0), solid(0), cset(0), pmesh(0), dmesh(0), buildTime(0) {} | |
+ inline ~Tile() | |
+ { | |
+ rcFreeCompactHeightfield(chf); | |
+ rcFreeContourSet(cset); | |
+ rcFreeHeightField(solid); | |
+ rcFreePolyMesh(pmesh); | |
+ rcFreePolyMeshDetail(dmesh); | |
+ } | |
+ int x, y; | |
+ rcCompactHeightfield* chf; | |
+ rcHeightfield* solid; | |
+ rcContourSet* cset; | |
+ rcPolyMesh* pmesh; | |
+ rcPolyMeshDetail* dmesh; | |
+ int buildTime; | |
+ }; | |
+ | |
+ struct TileSet | |
+ { | |
+ inline TileSet() : width(0), height(0), tiles(0) {} | |
+ inline ~TileSet() { delete [] tiles; } | |
+ int width, height; | |
+ float bmin[3], bmax[3]; | |
+ float cs, ch; | |
+ Tile* tiles; | |
}; | |
class MapBuilder | |
@@ -114,6 +140,7 @@ namespace MMAP | |
// load and unload models | |
bool loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData); | |
+ void unloadVMap(uint32 mapID, uint32 tileX, uint32 tileY); | |
// vert and triangle methods | |
void transform(vector<Vector3> original, vector<Vector3> &transformed, | |
@@ -169,6 +196,7 @@ namespace MMAP | |
float m_maxWalkableAngle; | |
+ // build performance - not really used for now | |
rcContext* m_rcContext; | |
}; | |
} | |
diff --git a/dep/recastnavigation/RecastDemo/Include/Debug.h b/dep/recastnavigation/RecastDemo/Include/Debug.h | |
index ae533d1..8e6e0c5 100644 | |
--- a/dep/recastnavigation/RecastDemo/Include/Debug.h | |
+++ b/dep/recastnavigation/RecastDemo/Include/Debug.h | |
@@ -59,13 +59,13 @@ struct mmapTileHeader | |
unsigned int mmapMagic; | |
unsigned int dtVersion; | |
unsigned int mmapVersion; | |
- unsigned int tileCount; | |
+ unsigned int size; | |
bool usesHiRes : 1; | |
bool usesLiquid : 1; | |
mmapTileHeader() : | |
mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION), | |
- mmapVersion(MMAP_VERSION), tileCount(0) | |
+ mmapVersion(MMAP_VERSION), size(0) | |
{} | |
}; | |
diff --git a/dep/recastnavigation/RecastDemo/Source/Debug.cpp b/dep/recastnavigation/RecastDemo/Source/Debug.cpp | |
index ebbc3ac..e9c4a97 100644 | |
--- a/dep/recastnavigation/RecastDemo/Source/Debug.cpp | |
+++ b/dep/recastnavigation/RecastDemo/Source/Debug.cpp | |
@@ -51,22 +51,16 @@ void duReadNavMesh(char* tile, dtNavMesh* &navMesh) | |
mmapTileHeader header; | |
fread(&header, sizeof(header), 1, file); | |
- unsigned int length; | |
+ unsigned char* data = (unsigned char*)dtAlloc(header.size, DT_ALLOC_PERM); | |
+ fread(data, header.size, 1, file); | |
- for (unsigned int i2 = 0; i2 < header.tileCount; ++i2) | |
- { | |
- fread(&length, sizeof(length), 1, file); | |
- | |
- unsigned char* data = (unsigned char*)dtAlloc(length, DT_ALLOC_PERM); | |
- fread(data, length, 1, file); | |
+ dtStatus status = navMesh->addTile(data, header.size, DT_TILE_FREE_DATA, 0 , NULL); | |
- dtStatus status = navMesh->addTile(data, length, DT_TILE_FREE_DATA, 0 , NULL); | |
+ if (status != DT_SUCCESS) | |
+ dtFree(data); | |
+ else | |
+ count++; | |
- if (status != DT_SUCCESS) | |
- dtFree(data); | |
- else | |
- count++; | |
- } | |
fclose(file); | |
} | |
} | |
diff --git a/src/game/GridMap.h b/src/game/GridMap.h | |
index c13a9f0..48ee48a 100644 | |
--- a/src/game/GridMap.h | |
+++ b/src/game/GridMap.h | |
@@ -286,7 +286,7 @@ private: | |
void LoadNavMesh(int gx, int gy); | |
void UnloadNavMesh(int gx, int gy); | |
dtNavMesh* m_navMesh; | |
- UNORDERED_MAP<uint32, std::list<dtTileRef>*> m_mmapLoadedTiles; // maps [map grid coords] to [dtTile] | |
+ UNORDERED_MAP<uint32, dtTileRef> m_mmapLoadedTiles; // maps [map grid coords] to [dtTile] | |
static std::set<uint32> s_mmapDisabledIds; // stores list of mapids which do not use pathfinding | |
// end movemap-related | |
diff --git a/src/game/MoveMap.cpp b/src/game/MoveMap.cpp | |
index 2bcd577..a136af4 100644 | |
--- a/src/game/MoveMap.cpp | |
+++ b/src/game/MoveMap.cpp | |
@@ -22,38 +22,35 @@ | |
#include "Utilities/UnorderedMapSet.h" | |
#include "World.h" | |
-/****** TerrainInfo navmesh load/unload ******/ | |
- | |
uint32 packTileID(int x, int y) { return uint32(x << 16 | y); } | |
void TerrainInfo::LoadNavMesh(int gx, int gy) | |
{ | |
- // load the navmesh first | |
if (!m_navMesh) | |
{ | |
uint32 pathLen = sWorld.GetDataPath().length() + strlen("mmaps/%03i.mmap")+1; | |
- char *fileName = new char[pathLen]; | |
- snprintf(fileName, pathLen, (sWorld.GetDataPath()+"mmaps/%03i.mmap").c_str(), m_mapId); | |
+ char *temp = new char[pathLen]; | |
+ snprintf(temp, pathLen, (sWorld.GetDataPath()+"mmaps/%03i.mmap").c_str(), m_mapId); | |
+ std::string fileName = temp; | |
+ delete [] temp; | |
- FILE* file = fopen(fileName, "rb"); | |
+ FILE* file = fopen(fileName.c_str(), "rb"); | |
if (!file) | |
{ | |
- sLog.outDebug("MMAP: Error: Could not open mmap file '%s'", fileName); | |
- delete [] fileName; | |
+ sLog.outDebug("MMAP: Error: Could not open mmap file '%s'", fileName.c_str()); | |
return; | |
} | |
dtNavMeshParams params; | |
fread(¶ms, sizeof(dtNavMeshParams), 1, file); | |
fclose(file); | |
- delete [] fileName; | |
m_navMesh = dtAllocNavMesh(); | |
if (!m_navMesh->init(¶ms)) | |
{ | |
dtFreeNavMesh(m_navMesh); | |
m_navMesh = NULL; | |
- sLog.outError("MMAP: Failed to initialize mmap %03u from file %s", m_mapId, fileName); | |
+ sLog.outError("MMAP: Failed to initialize mmap %03u from file %s", m_mapId, fileName.c_str()); | |
return; | |
} | |
} | |
@@ -66,56 +63,73 @@ void TerrainInfo::LoadNavMesh(int gx, int gy) | |
return; | |
} | |
- // now load the tile | |
- MmapTileReader reader(m_mapId, gx, gy); | |
- if (!reader.check()) | |
+ // mmaps/0000000.mmtile | |
+ uint32 pathLen = sWorld.GetDataPath().length() + strlen("mmaps/%03i%02i%02i.mmtile")+1; | |
+ char *fileName = new char[pathLen]; | |
+ snprintf(fileName, pathLen, (sWorld.GetDataPath()+"mmaps/%03i%02i%02i.mmtile").c_str(), m_mapId, gx, gy); | |
+ | |
+ FILE *file = fopen(fileName, "rb"); | |
+ if (!file) | |
{ | |
- sLog.outError("MMAP: Bad header in mmap %03u%02i%02i.mmtile", m_mapId, gx, gy); | |
+ sLog.outDebug("MMAP: Could not open mmtile file '%s'", fileName); | |
+ delete [] fileName; | |
return; | |
} | |
+ delete [] fileName; | |
- tileRefList* newTiles = new tileRefList(); | |
- unsigned char* data = NULL; | |
- uint32 length = 0; | |
+ // read header | |
+ mmapTileHeader fileHeader; | |
+ fread(&fileHeader, sizeof(mmapTileHeader), 1, file); | |
- while (reader.read(data, length)) | |
+ if (fileHeader.mmapMagic != MMAP_MAGIC) | |
{ | |
- dtMeshHeader* header = (dtMeshHeader*)data; | |
- dtTileRef tileRef = 0; | |
- | |
- // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed | |
- dtStatus dtResult = m_navMesh->addTile(data, length, DT_TILE_FREE_DATA, 0, &tileRef); | |
- if(dtResult == DT_SUCCESS) | |
- newTiles->push_back(tileRef); | |
- else | |
- dtFree(data); | |
+ sLog.outError("MMAP: Bad header in mmap %03u%02i%02i.mmtile", m_mapId, gx, gy); | |
+ return; | |
} | |
- // have we loaded everything we expected? | |
- if(reader.getTileCount() == newTiles->size()) | |
- { | |
- sLog.outDetail("MMAP: Loaded mmtile %03i[%02i,%02i]", m_mapId, gx, gy); | |
- m_mmapLoadedTiles.insert(std::pair<uint32, tileRefList*>(packedGridPos, newTiles)); | |
- } | |
- else | |
- { | |
- // one or more of the tiles failed | |
- // we cannot allow having partially loaded maps | |
- sLog.outError("MMAP: Could not load %03u%02i%02i.mmtile into navmesh", m_mapId, gx, gy); | |
+ unsigned char* data = (unsigned char*)dtAlloc(fileHeader.size, DT_ALLOC_PERM); | |
+ MANGOS_ASSERT(data); | |
- // unload everything we can | |
- for (tileRefList::iterator itr = newTiles->begin(); itr != newTiles->end(); ) | |
+ fread(data, fileHeader.size, 1, file); | |
+ fclose(file); | |
+ | |
+ dtMeshHeader* header = (dtMeshHeader*)data; | |
+ dtTileRef tileRef = 0; | |
+ | |
+ // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed | |
+ dtStatus dtResult = m_navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef); | |
+ switch(dtResult) | |
+ { | |
+ case DT_SUCCESS: | |
{ | |
- if(DT_SUCCESS == m_navMesh->removeTile(*itr, NULL, NULL)) | |
- itr = newTiles->erase(itr); | |
- else | |
- ++itr; | |
+ m_mmapLoadedTiles.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef)); | |
+ sLog.outDetail("MMAP: Loaded mmtile %03i[%02i,%02i] into %03i[%02i,%02i]", m_mapId, gx, gy, m_mapId, header->x, header->y); | |
} | |
- | |
- // if we got here with newTiles not empty its really bad - but again, we cannot recover | |
- MANGOS_ASSERT(newTiles->empty()); | |
- delete newTiles; | |
+ break; | |
+ case DT_FAILURE_DATA_MAGIC: | |
+ { | |
+ sLog.outError("MMAP: %03u%02i%02i.mmtile has an invalid header", m_mapId, gx, gy); | |
+ dtFree(data); | |
+ } | |
+ break; | |
+ case DT_FAILURE_DATA_VERSION: | |
+ { | |
+ sLog.outError("MMAP: %03u%02i%02i.mmtile was built with Detour v%i, expected v%i",m_mapId, gx, gy, header->version, DT_NAVMESH_VERSION); | |
+ dtFree(data); | |
+ } | |
+ break; | |
+ case DT_FAILURE_OUT_OF_MEMORY: | |
+ case DT_FAILURE: | |
+ default: | |
+ { | |
+ sLog.outError("MMAP: Could not load %03u%02i%02i.mmtile into navmesh", m_mapId, gx, gy); | |
+ dtFree(data); | |
+ } | |
+ break; | |
} | |
+ | |
+ if (fileHeader.mmapVersion != MMAP_VERSION) | |
+ sLog.outDebug("MMAP: %03u%02i%02i.mmtile was built with generator v%i, expected v%i", m_mapId, gx, gy, fileHeader.mmapVersion, MMAP_VERSION); | |
} | |
void TerrainInfo::UnloadNavMesh(int gx, int gy) | |
@@ -132,29 +146,20 @@ void TerrainInfo::UnloadNavMesh(int gx, int gy) | |
return; | |
} | |
- tileRefList* tiles = m_mmapLoadedTiles[packedGridPos]; | |
- for (tileRefList::iterator itr = tiles->begin(); itr != tiles->end(); ) | |
+ dtTileRef tileRef = m_mmapLoadedTiles[packedGridPos]; | |
+ | |
+ // unload, and mark as non loaded | |
+ if(DT_SUCCESS != m_navMesh->removeTile(tileRef, NULL, NULL)) | |
{ | |
- // unload, and mark as non loaded | |
- if(DT_SUCCESS == m_navMesh->removeTile(*itr, NULL, NULL)) | |
- itr = tiles->erase(itr); | |
- else | |
- ++itr; | |
+ // because the Terrain unloads the grid, this is technically a memory leak | |
+ // if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used | |
+ sLog.outError("MMAP: Could not unload %03u%02i%02i.mmtile from navmesh", m_mapId, gx, gy); | |
} | |
- | |
- if (tiles->empty()) | |
- sLog.outDetail("MMAP: Unloaded mmtile %03i[%02i,%02i] from %03i", m_mapId, gx, gy, m_mapId); | |
else | |
{ | |
- // because the Terrain unloads the grid, this is technically a memory leak | |
- // if the grid is later loaded, dtNavMesh::addTile will return errors for the dtTileRefs we were unable to unload | |
- // if we got here, something is really worng - we cannot recover anyway | |
- sLog.outError("MMAP: Could not unload %u tile(s) from navmesh (%03u%02i%02i.mmtile)", tiles->size(), m_mapId, gx, gy); | |
- MANGOS_ASSERT(false); | |
+ m_mmapLoadedTiles.erase(packedGridPos); | |
+ sLog.outDetail("MMAP: Unloaded mmtile %03i[%02i,%02i] from %03i", m_mapId, gx, gy, m_mapId); | |
} | |
- | |
- delete tiles; | |
- m_mmapLoadedTiles.erase(packedGridPos); | |
} | |
dtNavMesh const* TerrainInfo::GetNavMesh() const | |
@@ -162,8 +167,6 @@ dtNavMesh const* TerrainInfo::GetNavMesh() const | |
return m_navMesh; | |
} | |
-/****** pathfinding enabled/disabled ******/ | |
- | |
std::set<uint32> TerrainInfo::s_mmapDisabledIds = std::set<uint32>(); | |
void TerrainInfo::preventPathfindingOnMaps(std::string ignoreMapIds) | |
@@ -187,87 +190,3 @@ bool TerrainInfo::IsPathfindingEnabled() const | |
{ | |
return sWorld.getConfig(CONFIG_BOOL_MMAP_ENABLED) && s_mmapDisabledIds.find(m_mapId) == s_mmapDisabledIds.end(); | |
} | |
- | |
-/****** MmapTileReader ******/ | |
-MmapTileReader::MmapTileReader(uint32 mapId, int32 x, int32 y) | |
- : m_mmapTileFile(NULL), m_currentTile(0), m_mmapFileName(NULL) | |
-{ | |
- // mmaps/0000000.mmtile | |
- uint32 pathLen = sWorld.GetDataPath().length() + strlen("mmaps/%03i%02i%02i.mmtile")+1; | |
- m_mmapFileName = new char[pathLen]; | |
- snprintf(m_mmapFileName, pathLen, (sWorld.GetDataPath()+"mmaps/%03i%02i%02i.mmtile").c_str(), mapId, x, y); | |
- | |
- m_mmapTileFile = fopen(m_mmapFileName, "rb"); | |
- if (!m_mmapTileFile) | |
- return; | |
- | |
- uint32 bytesRead = fread(&m_header, 1, sizeof(mmapTileHeader), m_mmapTileFile); | |
- if (bytesRead != sizeof(mmapTileHeader)) | |
- memset(&m_header, 0, sizeof(mmapTileHeader)); | |
-} | |
- | |
-MmapTileReader::~MmapTileReader() | |
-{ | |
- delete [] m_mmapFileName; | |
- | |
- if (m_mmapTileFile) | |
- fclose(m_mmapTileFile); | |
-} | |
- | |
-bool MmapTileReader::check() | |
-{ | |
- if (!m_mmapTileFile) | |
- { | |
- sLog.outDebug("Could not open mmtile file '%s'", m_mmapFileName); | |
- return false; | |
- } | |
- | |
- if (m_header.mmapMagic != MMAP_MAGIC) | |
- { | |
- sLog.outError("mmtile file '%s' has wrong format", m_mmapFileName); | |
- return false; | |
- } | |
- | |
- if (m_header.dtVersion != DT_NAVMESH_VERSION) | |
- { | |
- sLog.outError("mmtile file '%s' was built with Detour v%i, expected v%", m_mmapFileName, m_header.dtVersion, DT_NAVMESH_VERSION); | |
- return false; | |
- } | |
- | |
- if (m_header.tileCount == 0) | |
- { | |
- sLog.outDebug("mmtile file '%s' contains 0 tiles", m_mmapFileName); | |
- return false; | |
- } | |
- | |
- return true; | |
-} | |
- | |
-bool MmapTileReader::read(unsigned char* &data, uint32 &dataLength) | |
-{ | |
- if (!m_mmapTileFile) | |
- return false; | |
- | |
- uint32 bytesRead = fread(&dataLength, 1, sizeof(uint32), m_mmapTileFile); | |
- if (sizeof(uint32) != bytesRead) | |
- return false; | |
- | |
- // check if we have read all the tiles | |
- if (m_header.tileCount <= m_currentTile) | |
- return false; | |
- | |
- // allocate and read tile data | |
- data = (unsigned char*)dtAlloc(dataLength, DT_ALLOC_PERM); | |
- MANGOS_ASSERT(data); | |
- | |
- bytesRead = fread(data, 1, dataLength, m_mmapTileFile); | |
- if (bytesRead != dataLength) | |
- { | |
- dtFree(data); | |
- return false; | |
- } | |
- | |
- m_currentTile++; | |
- | |
- return true; | |
-} | |
diff --git a/src/game/MoveMap.h b/src/game/MoveMap.h | |
index 2cb4e47..fa0d41a 100644 | |
--- a/src/game/MoveMap.h | |
+++ b/src/game/MoveMap.h | |
@@ -20,10 +20,8 @@ | |
#define _MOVE_MAP_H | |
#include "Platform/Define.h" | |
-#include <list> | |
#include "../../dep/recastnavigation/Detour/Include/DetourAlloc.h" | |
-#include "../../dep/recastnavigation/Detour/Include/DetourNavMesh.h" | |
/* memory management */ | |
@@ -37,40 +35,19 @@ inline void dtCustomFree(void* ptr) | |
delete [] (unsigned char*)ptr; | |
} | |
-/* mmap tile structure */ | |
+/* mmap file info */ | |
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP' | |
-#define MMAP_VERSION 1 | |
+#define MMAP_VERSION 2 | |
struct mmapTileHeader | |
{ | |
uint32 mmapMagic; | |
uint32 dtVersion; | |
uint32 mmapVersion; | |
- uint32 tileCount; | |
+ uint32 size; | |
bool usesHiRes : 1; | |
bool usesLiquids : 1; | |
}; | |
-typedef std::list<dtTileRef> tileRefList; | |
- | |
-class MmapTileReader | |
-{ | |
-public: | |
- MmapTileReader(uint32 mapId, int32 x, int32 y); | |
- ~MmapTileReader(); | |
- | |
- // validates the mmtile file | |
- bool check(); | |
- | |
- // reads and returns the next dtMeshTile data | |
- bool read(unsigned char* &data, uint32 &dataLength); | |
- uint32 getTileCount() { return m_header.tileCount; } | |
-private: | |
- char* m_mmapFileName; | |
- FILE* m_mmapTileFile; | |
- mmapTileHeader m_header; | |
- uint32 m_currentTile; | |
-}; | |
- | |
#endif // _MOVE_MAP_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment