EXPORT_API dtStatus dtnmBuildSingleTileMesh(dtNavMeshCreateParams* params
        , dtNavMesh** ppNavMesh)
    {
        if (!params)
            return DT_FAILURE + DT_INVALID_PARAM;

		unsigned char* navData = 0;
		int navDataSize = 0;

		if (!dtCreateNavMeshData(params, &navData, &navDataSize))
            return DT_FAILURE + DT_INVALID_PARAM;
		
        dtNavMesh* pNavMesh = dtAllocNavMesh();
		if (!pNavMesh)
		{
            dtFree(navData);
            return DT_FAILURE + DT_OUT_OF_MEMORY;
		}

		dtStatus status = 
            pNavMesh->init(navData, navDataSize, DT_TILE_FREE_DATA);
		if (dtStatusFailed(status))
		{
            dtFreeNavMesh(pNavMesh);
            dtFree(navData);
            return status;
		}

        *ppNavMesh = pNavMesh;

        return DT_SUCCESS;

    }
Exemple #2
0
    NavMeshPtr makeEmptyNavMesh(const Settings& settings)
    {
        // Max tiles and max polys affect how the tile IDs are caculated.
        // There are 22 bits available for identifying a tile and a polygon.
        const int polysAndTilesBits = 22;
        const auto polysBits = getMinValuableBitsNumber(settings.mMaxPolys);

        if (polysBits >= polysAndTilesBits)
            throw InvalidArgument("Too many polygons per tile");

        const auto tilesBits = polysAndTilesBits - polysBits;

        dtNavMeshParams params;
        std::fill_n(params.orig, 3, 0.0f);
        params.tileWidth = settings.mTileSize * settings.mCellSize;
        params.tileHeight = settings.mTileSize * settings.mCellSize;
        params.maxTiles = 1 << tilesBits;
        params.maxPolys = 1 << polysBits;

        NavMeshPtr navMesh(dtAllocNavMesh(), &dtFreeNavMesh);
        const auto status = navMesh->init(&params);

        if (!dtStatusSucceed(status))
            throw NavigatorException("Failed to init navmesh");

        return navMesh;
    }
Exemple #3
0
void CCollideInterface::ActivateMap(uint32 mapid)
{
	m_navmaplock.Acquire();
	std::map<uint32, NavMeshData*>::iterator itr = m_navdata.find(mapid);

	if(itr != m_navdata.end())
		++itr->second->refs;
	else
	{

		//load params
		char filename[1024];
		sprintf(filename, "mmaps/%03i.mmap", mapid);
		FILE* f = fopen(filename, "rb");

		if(f == NULL)
		{
			m_navmaplock.Release();
			return;
		}

		dtNavMeshParams params;
		fread(&params, sizeof(params), 1, f);
		fclose(f);

		NavMeshData* d = new NavMeshData;
		d->mesh = dtAllocNavMesh();
		d->query = dtAllocNavMeshQuery();
		d->mesh->init(&params);
		d->query->init(d->mesh, 1024);
		d->AddRef();
		m_navdata.insert(std::make_pair(mapid, d));
	}
	m_navmaplock.Release();
}
bool OgreDetourTileCache::initTileCache()
{
    // BUILD TileCache
    dtFreeTileCache(m_tileCache);

    dtStatus status;

    m_tileCache = dtAllocTileCache();
    if (!m_tileCache)
    {
        m_recast->m_pLog->logMessage("ERROR: buildTiledNavigation: Could not allocate tile cache.");
        return false;
    }
    status = m_tileCache->init(&m_tcparams, m_talloc, m_tcomp, m_tmproc);
    if (dtStatusFailed(status))
    {
        m_recast->m_pLog->logMessage("ERROR: buildTiledNavigation: Could not init tile cache.");
        return false;
    }

    dtFreeNavMesh(m_recast->m_navMesh);

    m_recast->m_navMesh = dtAllocNavMesh();
    if (!m_recast->m_navMesh)
    {
        m_recast->m_pLog->logMessage("ERROR: buildTiledNavigation: Could not allocate navmesh.");
        return false;
    }


    // Init multi-tile navmesh parameters
    dtNavMeshParams params;
    memset(&params, 0, sizeof(params));
    rcVcopy(params.orig, m_tcparams.orig);   // Set world-space origin of tile grid
    params.tileWidth = m_tileSize*m_tcparams.cs;
    params.tileHeight = m_tileSize*m_tcparams.cs;
    params.maxTiles = m_maxTiles;
    params.maxPolys = m_maxPolysPerTile;

    status = m_recast->m_navMesh->init(&params);
    if (dtStatusFailed(status))
    {
        m_recast->m_pLog->logMessage("ERROR: buildTiledNavigation: Could not init navmesh.");
        return false;
    }

    // Init recast navmeshquery with created navmesh (in OgreRecast component)
    m_recast->m_navQuery = dtAllocNavMeshQuery();
    status = m_recast->m_navQuery->init(m_recast->m_navMesh, 2048);
    if (dtStatusFailed(status))
    {
        m_recast->m_pLog->logMessage("ERROR: buildTiledNavigation: Could not init Detour navmesh query");
        return false;
    }

    return true;
}
Exemple #5
0
dtNavMesh* Sample_TileMesh::loadAll(const char* path)
{
	FILE* fp = fopen(path, "rb");
	if (!fp) return 0;
	
	// Read header.
	NavMeshSetHeader header;
	fread(&header, sizeof(NavMeshSetHeader), 1, fp);
	if (header.magic != NAVMESHSET_MAGIC)
	{
		fclose(fp);
		return 0;
	}
	if (header.version != NAVMESHSET_VERSION)
	{
		fclose(fp);
		return 0;
	}
	
	dtNavMesh* mesh = dtAllocNavMesh();
	if (!mesh)
	{
		fclose(fp);
		return 0;
	}
	dtStatus status = mesh->init(&header.params);
	if (dtStatusFailed(status))
	{
		fclose(fp);
		return 0;
	}
		
	// Read tiles.
	for (int i = 0; i < header.numTiles; ++i)
	{
		NavMeshTileHeader tileHeader;
		fread(&tileHeader, sizeof(tileHeader), 1, fp);
		if (!tileHeader.tileRef || !tileHeader.dataSize)
			break;

		unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
		if (!data) break;
		memset(data, 0, tileHeader.dataSize);
		fread(data, tileHeader.dataSize, 1, fp);
		
		mesh->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0);
	}
	
	fclose(fp);
	
	return mesh;
}
bool Sample_TileMesh::handleBuild()
{
	if (!m_geom || !m_geom->getMesh())
	{
		m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: No vertices and triangles.");
		return false;
	}
	
	dtFreeNavMesh(m_navMesh);
	
	m_navMesh = dtAllocNavMesh();
	if (!m_navMesh)
	{
		m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not allocate navmesh.");
		return false;
	}

	dtNavMeshParams params;
	rcVcopy(params.orig, m_geom->getNavMeshBoundsMin());
	params.tileWidth = m_tileSize*m_cellSize;
	params.tileHeight = m_tileSize*m_cellSize;
	params.maxTiles = m_maxTiles;
	params.maxPolys = m_maxPolysPerTile;
	
	dtStatus status;
	
	status = m_navMesh->init(&params);
	if (dtStatusFailed(status))
	{
		m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init navmesh.");
		return false;
	}
	
	status = m_navQuery->init(m_navMesh, 2048);
	if (dtStatusFailed(status))
	{
		m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init Detour navmesh query");
		return false;
	}
	
	if (m_buildAll)
		buildAllTiles();
	
	if (m_tool)
		m_tool->init(this);
	initToolStates(this);

	return true;
}
Exemple #7
0
   bool NavMesh::createNavMesh(dtNavMeshCreateParams &params)
   {
      unsigned char *tileData = NULL;
      S32 tileDataSize = 0;
      if(!dtCreateNavMeshData(&params, &tileData, &tileDataSize))
      {
         Con::errorf("Could not construct NavMeshData for NavMesh %s", getIdString());
         return false;
      }

      tnm = dtAllocNavMesh();
      if(!tnm)
      {
         Con::errorf("Out of memory allocating dtNavMesh for NavMesh %s", getIdString());
         return false;
      }
      dtStatus s = tnm->init(tileData, tileDataSize, DT_TILE_FREE_DATA);
      if(dtStatusFailed(s))
      {
         Con::errorf("Could not initialise dtNavMesh for NavMesh %s", getIdString());
         return false;
      }

      // Initialise all flags to something helpful.
      for(U32 i = 0; i < tnm->getMaxTiles(); ++i)
      {
         const dtMeshTile* tile = ((const dtNavMesh*)tnm)->getTile(i);
         if(!tile->header) continue;
         const dtPolyRef base = tnm->getPolyRefBase(tile);
         for(U32 j = 0; j < tile->header->polyCount; ++j)
         {
            const dtPolyRef ref = base | j;
            unsigned short f = 0;
            tnm->getPolyFlags(ref, &f);
            tnm->setPolyFlags(ref, f | 1);
         }
      }

      return true;
   }
    EXPORT_API dtStatus dtnmInitTiledNavMesh(dtNavMeshParams* params
        , dtNavMesh** ppNavMesh)
    {
        if (!params)
            return DT_FAILURE + DT_INVALID_PARAM;

        dtNavMesh* pNavMesh = dtAllocNavMesh();
		if (!pNavMesh)
            return DT_FAILURE + DT_OUT_OF_MEMORY;

		dtStatus status = 
            pNavMesh->init(params);
		if (dtStatusFailed(status))
		{
            dtFreeNavMesh(pNavMesh);
            return status;
		}

        *ppNavMesh = pNavMesh;

        return DT_SUCCESS;
    }
void Sample_TempObstacles::loadAll(const char* path)
{
    FILE* fp = fopen(path, "rb");
    if (!fp) return;

    // Read header.
    TileCacheSetHeader header;
    fread(&header, sizeof(TileCacheSetHeader), 1, fp);
    if (header.magic != TILECACHESET_MAGIC)
    {
        fclose(fp);
        return;
    }
    if (header.version != TILECACHESET_VERSION)
    {
        fclose(fp);
        return;
    }

    m_navMesh = dtAllocNavMesh();
    if (!m_navMesh)
    {
        fclose(fp);
        return;
    }
    dtStatus status = m_navMesh->init(&header.meshParams);
    if (dtStatusFailed(status))
    {
        fclose(fp);
        return;
    }

    m_tileCache = dtAllocTileCache();
    if (!m_tileCache)
    {
        fclose(fp);
        return;
    }
    status = m_tileCache->init(&header.cacheParams, m_talloc, m_tcomp, m_tmproc);
    if (dtStatusFailed(status))
    {
        fclose(fp);
        return;
    }

    // Read tiles.
    for (int i = 0; i < header.numTiles; ++i)
    {
        TileCacheTileHeader tileHeader;
        fread(&tileHeader, sizeof(tileHeader), 1, fp);
        if (!tileHeader.tileRef || !tileHeader.dataSize)
            break;

        unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
        if (!data) break;
        memset(data, 0, tileHeader.dataSize);
        fread(data, tileHeader.dataSize, 1, fp);

        dtCompressedTileRef tile = 0;
        m_tileCache->addTile(data, tileHeader.dataSize, DT_COMPRESSEDTILE_FREE_DATA, &tile);

        if (tile)
            m_tileCache->buildNavMeshTile(tile, m_navMesh);
    }

    fclose(fp);
}
bool Sample_TileMesh::handleLoadSubTiles()
{
    if (!m_geom || !m_geom->getMesh())
    {
        m_ctx->log(RC_LOG_ERROR, "buildNavigation: Input mesh is not specified.");
        return false;
    }

    cleanup();

    const char* meshFilePath = m_geom->getMesh()->getFileName();
    char charBuff[4];
    memset(charBuff, 0, sizeof(charBuff));
    memcpy(charBuff, &meshFilePath[10], sizeof(char) * 3);
    int mapId = atoi(charBuff);
    // load and init dtNavMesh - read parameters from file
    int pathLen = strlen("Meshes/%03i.mmap") + 1;
    char *fileName = new char[pathLen];
    snprintf(fileName, pathLen, "Meshes/%03i.mmap", mapId);
    FILE* file = fopen(fileName, "rb");
    if (!file)
    {
        delete[] fileName;
        return false;
    }
    dtNavMeshParams params;
    int count = fread(&params, sizeof(dtNavMeshParams), 1, file);
    fclose(file);
    if (count != 1)
    {
        delete[] fileName;
        return false;
    }
    params.maxTiles = 25 * 25 * 9;

    dtNavMesh* mesh = dtAllocNavMesh();
    if (dtStatusFailed(mesh->init(&params)))
    {
        dtFreeNavMesh(mesh);
        delete[] fileName;
        return false;
    }
    delete[] fileName;

    memset(charBuff, 0, sizeof(charBuff));
    memcpy(charBuff, &meshFilePath[13], sizeof(char) * 2);
    int x = atoi(charBuff);
    memset(charBuff, 0, sizeof(charBuff));
    memcpy(charBuff, &meshFilePath[15], sizeof(char) * 2);
    int y = atoi(charBuff);

    for (int subRow = 0; subRow < 25; subRow++)
    {
        for (int subCol = 0; subCol < 25; subCol++)
        {
            // load this tile :: Meshes/MMMXXYY.mmtile
            pathLen = strlen("Meshes/%03i%02i%02i_____%02i%02i.mmtile") + 1;
            fileName = new char[pathLen];
            snprintf(fileName, pathLen, "Meshes/%03i%02i%02i_____%02i%02i.mmtile", mapId, x, y, subRow, subCol);

            file = fopen(fileName, "rb");
            if (!file)
            {
                delete[] fileName;
                continue;
            }
            delete[] fileName;

            // read header
            MmapTileHeader fileHeader;
            if (fread(&fileHeader, sizeof(MmapTileHeader), 1, file) != 1 || fileHeader.mmapMagic != MMAP_MAGIC)
            {
                fclose(file);
                continue;
            }

            unsigned char* data = (unsigned char*)dtAlloc(fileHeader.size, DT_ALLOC_PERM);

            size_t result = fread(data, fileHeader.size, 1, file);
            if (!result)
            {
                fclose(file);
                continue;
            }

            // Fix x/y
            dtMeshHeader* header = (dtMeshHeader*)data;
            header->x = header->x * 25 + subRow;
            header->y = header->y * 25 + subCol;

            fclose(file);

            dtTileRef tileRef = 0;

            // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed
            if (!dtStatusSucceed(mesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef)))
            {
                dtFree(data);
                continue;
            }
        }
    }

    m_navMesh = mesh;
    dtStatus status = m_navQuery->init(m_navMesh, 2048);
    if (dtStatusFailed(status))
    {
        m_ctx->log(RC_LOG_ERROR, "Could not init Detour navmesh query");
        return false;
    }

    if (m_tool)
        m_tool->init(this);
    initToolStates(this);

    return true;
}
bool Sample_TempObstacles::handleBuild()
{
    dtStatus status;

    if (!m_geom || !m_geom->getMesh())
    {
        m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: No vertices and triangles.");
        return false;
    }

    m_tmproc->init(m_geom);

    // Init cache
    const float* bmin = m_geom->getNavMeshBoundsMin();
    const float* bmax = m_geom->getNavMeshBoundsMax();
    int gw = 0, gh = 0;
    rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh);
    const int ts = (int)m_tileSize;
    const int tw = (gw + ts-1) / ts;
    const int th = (gh + ts-1) / ts;

    // Generation params.
    rcConfig cfg;
    memset(&cfg, 0, sizeof(cfg));
    cfg.cs = m_cellSize;
    cfg.ch = m_cellHeight;
    cfg.walkableSlopeAngle = m_agentMaxSlope;
    cfg.walkableHeight = (int)ceilf(m_agentHeight / cfg.ch);
    cfg.walkableClimb = (int)floorf(m_agentMaxClimb / cfg.ch);
    cfg.walkableRadius = (int)ceilf(m_agentRadius / cfg.cs);
    cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize);
    cfg.maxSimplificationError = m_edgeMaxError;
    cfg.minRegionArea = (int)rcSqr(m_regionMinSize);		// Note: area = size*size
    cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize);	// Note: area = size*size
    cfg.maxVertsPerPoly = (int)m_vertsPerPoly;
    cfg.tileSize = (int)m_tileSize;
    cfg.borderSize = cfg.walkableRadius + 3; // Reserve enough padding.
    cfg.width = cfg.tileSize + cfg.borderSize*2;
    cfg.height = cfg.tileSize + cfg.borderSize*2;
    cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist;
    cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError;
    rcVcopy(cfg.bmin, bmin);
    rcVcopy(cfg.bmax, bmax);

    // Tile cache params.
    dtTileCacheParams tcparams;
    memset(&tcparams, 0, sizeof(tcparams));
    rcVcopy(tcparams.orig, bmin);
    tcparams.cs = m_cellSize;
    tcparams.ch = m_cellHeight;
    tcparams.width = (int)m_tileSize;
    tcparams.height = (int)m_tileSize;
    tcparams.walkableHeight = m_agentHeight;
    tcparams.walkableRadius = m_agentRadius;
    tcparams.walkableClimb = m_agentMaxClimb;
    tcparams.maxSimplificationError = m_edgeMaxError;
    tcparams.maxTiles = tw*th*EXPECTED_LAYERS_PER_TILE;
    tcparams.maxObstacles = 128;

    dtFreeTileCache(m_tileCache);

    m_tileCache = dtAllocTileCache();
    if (!m_tileCache)
    {
        m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not allocate tile cache.");
        return false;
    }
    status = m_tileCache->init(&tcparams, m_talloc, m_tcomp, m_tmproc);
    if (dtStatusFailed(status))
    {
        m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init tile cache.");
        return false;
    }

    dtFreeNavMesh(m_navMesh);

    m_navMesh = dtAllocNavMesh();
    if (!m_navMesh)
    {
        m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not allocate navmesh.");
        return false;
    }

    dtNavMeshParams params;
    memset(&params, 0, sizeof(params));
    rcVcopy(params.orig, bmin);
    params.tileWidth = m_tileSize*m_cellSize;
    params.tileHeight = m_tileSize*m_cellSize;
    params.maxTiles = m_maxTiles;
    params.maxPolys = m_maxPolysPerTile;

    status = m_navMesh->init(&params);
    if (dtStatusFailed(status))
    {
        m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init navmesh.");
        return false;
    }

    status = m_navQuery->init(m_navMesh, 2048);
    if (dtStatusFailed(status))
    {
        m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init Detour navmesh query");
        return false;
    }


    // Preprocess tiles.

    m_ctx->resetTimers();

    m_cacheLayerCount = 0;
    m_cacheCompressedSize = 0;
    m_cacheRawSize = 0;

    for (int y = 0; y < th; ++y)
    {
        for (int x = 0; x < tw; ++x)
        {
            TileCacheData tiles[MAX_LAYERS];
            memset(tiles, 0, sizeof(tiles));
            int ntiles = rasterizeTileLayers(m_ctx, m_geom, x, y, cfg, tiles, MAX_LAYERS);

            for (int i = 0; i < ntiles; ++i)
            {
                TileCacheData* tile = &tiles[i];
                status = m_tileCache->addTile(tile->data, tile->dataSize, DT_COMPRESSEDTILE_FREE_DATA, 0);
                if (dtStatusFailed(status))
                {
                    dtFree(tile->data);
                    tile->data = 0;
                    continue;
                }

                m_cacheLayerCount++;
                m_cacheCompressedSize += tile->dataSize;
                m_cacheRawSize += calcLayerBufferSize(tcparams.width, tcparams.height);
            }
        }
    }

    // Build initial meshes
    m_ctx->startTimer(RC_TIMER_TOTAL);
    for (int y = 0; y < th; ++y)
        for (int x = 0; x < tw; ++x)
            m_tileCache->buildNavMeshTilesAt(x,y, m_navMesh);
    m_ctx->stopTimer(RC_TIMER_TOTAL);

    m_cacheBuildTimeMs = m_ctx->getAccumulatedTime(RC_TIMER_TOTAL)/1000.0f;
    m_cacheBuildMemUsage = m_talloc->high;


    const dtNavMesh* nav = m_navMesh;
    int navmeshMemUsage = 0;
    for (int i = 0; i < nav->getMaxTiles(); ++i)
    {
        const dtMeshTile* tile = nav->getTile(i);
        if (tile->header)
            navmeshMemUsage += tile->dataSize;
    }
    printf("navmeshMemUsage = %.1f kB", navmeshMemUsage/1024.0f);


    if (m_tool)
        m_tool->init(this);
    initToolStates(this);

    return true;
}
Exemple #12
0
bool BotLoadNavMesh( const char *filename, NavData_t &nav )
{
	char mapname[ MAX_QPATH ];
	char filePath[ MAX_QPATH ];
	char gameName[ MAX_STRING_CHARS ];
	fileHandle_t f = 0;

	BotLoadOffMeshConnections( filename, &nav );

	Cvar_VariableStringBuffer( "mapname", mapname, sizeof( mapname ) );
	Cvar_VariableStringBuffer( "fs_game", gameName, sizeof( gameName ) );
	Com_sprintf( filePath, sizeof( filePath ), "maps/%s-%s.navMesh", mapname, filename );
	Com_Printf( " loading navigation mesh file '%s'...\n", filePath );

	int len = FS_FOpenFileRead( filePath, &f, qtrue );

	if ( !f )
	{
		Com_Printf( S_COLOR_RED "ERROR: Cannot open Navigaton Mesh file\n" );
		return false;
	}

	if ( len < 0 )
	{
		Com_Printf( S_COLOR_RED "ERROR: Negative Length for Navigation Mesh file\n" );
		return false;
	}

	NavMeshSetHeader header;
	
	FS_Read( &header, sizeof( header ), f );

	SwapNavMeshSetHeader( header );

	if ( header.magic != NAVMESHSET_MAGIC )
	{
		Com_Printf( S_COLOR_RED "ERROR: File is wrong magic\n" );
		FS_FCloseFile( f );
		return false;
	}

	if ( header.version != NAVMESHSET_VERSION )
	{
		Com_Printf( S_COLOR_RED "ERROR: File is wrong version found: %d want: %d\n", header.version, NAVMESHSET_VERSION );
		FS_FCloseFile( f );
		return false;
	}

	nav.mesh = dtAllocNavMesh();

	if ( !nav.mesh )
	{
		Com_Printf( S_COLOR_RED "ERROR: Unable to allocate nav mesh\n" );
		FS_FCloseFile( f );
		return false;
	}

	dtStatus status = nav.mesh->init( &header.params );

	if ( dtStatusFailed( status ) )
	{
		Com_Printf( S_COLOR_RED "ERROR: Could not init navmesh\n" );
		dtFreeNavMesh( nav.mesh );
		nav.mesh = NULL;
		FS_FCloseFile( f );
		return false;
	}

	nav.cache = dtAllocTileCache();

	if ( !nav.cache )
	{
		Com_Printf( S_COLOR_RED "ERROR: Could not allocate tile cache\n" );
		dtFreeNavMesh( nav.mesh );
		nav.mesh = NULL;
		FS_FCloseFile( f );
		return false;
	}

	status = nav.cache->init( &header.cacheParams, &alloc, &comp, &nav.process );

	if ( dtStatusFailed( status ) )
	{
		Com_Printf( S_COLOR_RED "ERROR: Could not init tile cache\n" );
		dtFreeNavMesh( nav.mesh );
		dtFreeTileCache( nav.cache );
		nav.mesh = NULL;
		nav.cache = NULL;
		FS_FCloseFile( f );
		return false;
	}

	for ( int i = 0; i < header.numTiles; i++ )
	{
		NavMeshTileHeader tileHeader;

		FS_Read( &tileHeader, sizeof( tileHeader ), f );

		SwapNavMeshTileHeader( tileHeader );

		if ( !tileHeader.tileRef || !tileHeader.dataSize )
		{
			Com_Printf( S_COLOR_RED "ERROR: NUll Tile in navmesh\n" );
			dtFreeNavMesh( nav.mesh );
			dtFreeTileCache( nav.cache );
			nav.cache = NULL;
			nav.mesh = NULL;
			FS_FCloseFile( f );
			return false;
		}

		unsigned char *data = ( unsigned char * ) dtAlloc( tileHeader.dataSize, DT_ALLOC_PERM );

		if ( !data )
		{
			Com_Printf( S_COLOR_RED "ERROR: Failed to allocate memory for tile data\n" );
			dtFreeNavMesh( nav.mesh );
			dtFreeTileCache( nav.cache );
			nav.cache = NULL;
			nav.mesh = NULL;
			FS_FCloseFile( f );
			return false;
		}

		memset( data, 0, tileHeader.dataSize );

		FS_Read( data, tileHeader.dataSize, f );

		if ( LittleLong( 1 ) != 1 )
		{
			dtTileCacheHeaderSwapEndian( data, tileHeader.dataSize );
		}

		dtCompressedTileRef tile = 0;
		dtStatus status = nav.cache->addTile( data, tileHeader.dataSize, DT_TILE_FREE_DATA, &tile );

		if ( dtStatusFailed( status ) )
		{
			Com_Printf( S_COLOR_RED "ERROR: Failed to add tile to navmesh\n" );
			dtFree( data );
			dtFreeTileCache( nav.cache );
			dtFreeNavMesh( nav.mesh );
			nav.cache = NULL;
			nav.mesh = NULL;
			FS_FCloseFile( f );
			return false;
		}

		if ( tile )
		{
			nav.cache->buildNavMeshTile( tile, nav.mesh );
		}
	}

	FS_FCloseFile( f );
	return true;
}
//-------------------------------------------------------------------------------------
bool NavMeshHandle::_create(int layer, const std::string& resPath, const std::string& res, NavMeshHandle* pNavMeshHandle)
{
	KBE_ASSERT(pNavMeshHandle);
	FILE* fp = fopen(res.c_str(), "rb");
	if (!fp)
	{
		ERROR_MSG(fmt::format("NavMeshHandle::create: open({}) is error!\n", 
			Resmgr::getSingleton().matchRes(res)));

		return false;
	}
	
	DEBUG_MSG(fmt::format("NavMeshHandle::create: ({}), layer={}\n", 
		res, layer));

	bool safeStorage = true;
	int pos = 0;
	int size = sizeof(NavMeshSetHeader);
	
	fseek(fp, 0, SEEK_END); 
	size_t flen = ftell(fp); 
	fseek(fp, 0, SEEK_SET); 

	uint8* data = new uint8[flen];
	if(data == NULL)
	{
		ERROR_MSG(fmt::format("NavMeshHandle::create: open({}), memory(size={}) error!\n", 
			Resmgr::getSingleton().matchRes(res), flen));

		fclose(fp);
		SAFE_RELEASE_ARRAY(data);
		return false;
	}

	size_t readsize = fread(data, 1, flen, fp);
	if(readsize != flen)
	{
		ERROR_MSG(fmt::format("NavMeshHandle::create: open({}), read(size={} != {}) error!\n", 
			Resmgr::getSingleton().matchRes(res), readsize, flen));

		fclose(fp);
		SAFE_RELEASE_ARRAY(data);
		return false;
	}

	if (readsize < sizeof(NavMeshSetHeader))
	{
		ERROR_MSG(fmt::format("NavMeshHandle::create: open({}), NavMeshSetHeader is error!\n", 
			Resmgr::getSingleton().matchRes(res)));

		fclose(fp);
		SAFE_RELEASE_ARRAY(data);
		return false;
	}

	NavMeshSetHeader header;
	memcpy(&header, data, size);

	pos += size;

	if (header.version != NavMeshHandle::RCN_NAVMESH_VERSION)
	{
		ERROR_MSG(fmt::format("NavMeshHandle::create: navmesh version({}) is not match({})!\n", 
			header.version, ((int)NavMeshHandle::RCN_NAVMESH_VERSION)));

		fclose(fp);
		SAFE_RELEASE_ARRAY(data);
		return false;
	}

	dtNavMesh* mesh = dtAllocNavMesh();
	if (!mesh)
	{
		ERROR_MSG("NavMeshHandle::create: dtAllocNavMesh is failed!\n");
		fclose(fp);
		SAFE_RELEASE_ARRAY(data);
		return false;
	}

	dtStatus status = mesh->init(&header.params);
	if (dtStatusFailed(status))
	{
		ERROR_MSG(fmt::format("NavMeshHandle::create: mesh init is error({})!\n", status));
		fclose(fp);
		SAFE_RELEASE_ARRAY(data);
		return false;
	}

	// Read tiles.
	bool success = true;
	for (int i = 0; i < header.tileCount; ++i)
	{
		NavMeshTileHeader tileHeader;
		size = sizeof(NavMeshTileHeader);
		memcpy(&tileHeader, &data[pos], size);
		pos += size;

		size = tileHeader.dataSize;
		if (!tileHeader.tileRef || !tileHeader.dataSize)
		{
			success = false;
			status = DT_FAILURE + DT_INVALID_PARAM;
			break;
		}
		
		unsigned char* tileData = 
			(unsigned char*)dtAlloc(size, DT_ALLOC_PERM);
		if (!tileData)
		{
			success = false;
			status = DT_FAILURE + DT_OUT_OF_MEMORY;
			break;
		}
		memcpy(tileData, &data[pos], size);
		pos += size;

		status = mesh->addTile(tileData
			, size
			, (safeStorage ? DT_TILE_FREE_DATA : 0)
			, tileHeader.tileRef
			, 0);

		if (dtStatusFailed(status))
		{
			success = false;
			break;
		}
	}

	fclose(fp);
	SAFE_RELEASE_ARRAY(data);

	if (!success)
	{
		ERROR_MSG(fmt::format("NavMeshHandle::create:  error({})!\n", status));
		dtFreeNavMesh(mesh);
		return false;
	}

	dtNavMeshQuery* pMavmeshQuery = new dtNavMeshQuery();

	pMavmeshQuery->init(mesh, 1024);
	pNavMeshHandle->resPath = resPath;
	pNavMeshHandle->navmeshLayer[layer].pNavmeshQuery = pMavmeshQuery;
	pNavMeshHandle->navmeshLayer[layer].pNavmesh = mesh;
	
	uint32 tileCount = 0;
	uint32 nodeCount = 0;
	uint32 polyCount = 0;
	uint32 vertCount = 0;
	uint32 triCount = 0;
	uint32 triVertCount = 0;
	uint32 dataSize = 0;

	const dtNavMesh* navmesh = mesh;
	for (int32 i = 0; i < navmesh->getMaxTiles(); ++i)
	{
		const dtMeshTile* tile = navmesh->getTile(i);
		if (!tile || !tile->header)
			continue;

		tileCount ++;
		nodeCount += tile->header->bvNodeCount;
		polyCount += tile->header->polyCount;
		vertCount += tile->header->vertCount;
		triCount += tile->header->detailTriCount;
		triVertCount += tile->header->detailVertCount;
		dataSize += tile->dataSize;

		// DEBUG_MSG(fmt::format("NavMeshHandle::create: verts({}, {}, {})\n", tile->verts[0], tile->verts[1], tile->verts[2]));
	}

	DEBUG_MSG(fmt::format("\t==> tiles loaded: {}\n", tileCount));
	DEBUG_MSG(fmt::format("\t==> BVTree nodes: {}\n", nodeCount));
	DEBUG_MSG(fmt::format("\t==> {} polygons ({} vertices)\n", polyCount, vertCount));
	DEBUG_MSG(fmt::format("\t==> {} triangles ({} vertices)\n", triCount, triVertCount));
	DEBUG_MSG(fmt::format("\t==> {:.2f} MB of data (not including pointers)\n", (((float)dataSize / sizeof(unsigned char)) / 1048576)));
	
	return true;
}
Exemple #14
0
dtNavMesh* buildMesh(InputGeom* geom, WCellBuildContext* wcellContext, int numCores)
{
	dtNavMesh* mesh = 0;

	if (!geom || !geom->getMesh())
	{
		CleanupAfterBuild();
		wcellContext->log(RC_LOG_ERROR, "buildTiledNavigation: No vertices and triangles.");
		return 0;
	}
	
	mesh = dtAllocNavMesh();
	if (!mesh)
	{
		CleanupAfterBuild();
		wcellContext->log(RC_LOG_ERROR, "buildTiledNavigation: Could not allocate navmesh.");
		return 0;
	}

	// setup some default parameters
	rcConfig cfg;
	memset(&cfg, 0, sizeof(rcConfig));
	const float agentHeight = 2.1f;				// most character toons are about this tall
	const float agentRadius = 0.6f;				// most character toons are about this big around
	const float agentClimb = 1.0f;				// character toons can step up this far. Seems ridiculously high ...
	const float tileSize = 1600.0f/3.0f/16.0f;	// The size of one chunk

	cfg.cs = 0.1f;										// cell size is a sort of resolution -> the bigger the faster
	cfg.ch = 0.05f;										// cell height -> distance from mesh to ground, if too low, recast will not build essential parts of the mesh for some reason
	cfg.walkableSlopeAngle = 50.0f;						// max climbable slope, bigger values won't make much of a change
	cfg.walkableHeight = (int)ceilf(agentHeight/cfg.ch);// minimum space to ceiling
	cfg.walkableClimb = (int)floorf(agentClimb/cfg.ch); // how high the agent can climb in one step
	cfg.walkableRadius = (int)ceilf(agentRadius/cfg.cs);// minimum distance to objects
	cfg.tileSize = (int)(tileSize/cfg.cs + 0.5f);
	cfg.maxEdgeLen = cfg.tileSize/2;;
	cfg.borderSize = cfg.walkableRadius + 3;
	cfg.width = cfg.tileSize + cfg.borderSize*2;
	cfg.height = cfg.tileSize + cfg.borderSize*2;	
	cfg.maxSimplificationError = 1.3f;
	cfg.minRegionArea = (int)rcSqr(8);		// Note: area = size*size
	cfg.mergeRegionArea = (int)rcSqr(20);	// Note: area = size*size
	cfg.maxVertsPerPoly = 3;
	cfg.detailSampleDist = cfg.cs * 9;
	cfg.detailSampleMaxError = cfg.ch * 1.0f;

	// default calculations - for some reason not included in basic recast
	const float* bmin = geom->getMeshBoundsMin();
	const float* bmax = geom->getMeshBoundsMax();
	
	int gw = 0, gh = 0;
	rcCalcGridSize(bmin, bmax, cfg.cs, &gw, &gh);
	const int ts = cfg.tileSize;
	const int tw = (gw + ts-1) / ts;
	const int th = (gh + ts-1) / ts;

	// Max tiles and max polys affect how the tile IDs are caculated.
	// There are 22 bits available for identifying a tile and a polygon.
	int tileBits = rcMin((int)ilog2(nextPow2(tw*th)), 14);
	if (tileBits > 14) tileBits = 14;
	int polyBits = 22 - tileBits;
	int maxTiles = 1 << tileBits;
	int maxPolysPerTile = 1 << polyBits;

	dtNavMeshParams params;
	rcVcopy(params.orig, geom->getMeshBoundsMin());
	params.tileWidth = cfg.tileSize * cfg.cs;
	params.tileHeight = cfg.tileSize * cfg.cs;
	params.maxTiles = maxTiles;
	params.maxPolys = maxPolysPerTile;
	
	dtStatus status;
	
	status = mesh->init(&params);
	if (dtStatusFailed(status))
	{
		CleanupAfterBuild();
		wcellContext->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init navmesh.");
		return 0;
	}
	
	// start building
	const float tcs = cfg.tileSize*cfg.cs;
	wcellContext->startTimer(RC_TIMER_TEMP);
	
	TileAdder Adder;

	dispatcher.Reset();
	dispatcher.maxHeight = th;
	dispatcher.maxWidth = tw;

	int numThreads = 0;
	numThreads = std::min(2*numCores, 8);

	boost::thread *threads[8];
	for(int i = 0; i < numThreads; ++i)
	{
		QuadrantTiler newTiler;
		newTiler.geom = geom;
		newTiler.cfg = cfg;
		newTiler.ctx = *wcellContext;
		boost::thread newThread(boost::ref(newTiler));
		threads[i] = &newThread;
	}
	
	Adder.mesh = mesh;
	Adder.numThreads = numThreads;
	boost::thread AdderThread(boost::ref(Adder));
	
	AdderThread.join();

	// Start the build process.	
	wcellContext->stopTimer(RC_TIMER_TEMP);

	return mesh;
}
DetourInterface::DetourInterface(rcPolyMesh* polyMesh,rcPolyMeshDetail* detailMesh,rcdtConfig& config)
	: _navMesh(nullptr),
	  _navQuery(nullptr),
	  _isMeshBuilt(false)
{
	detourCleanup();

	unsigned char* navData = 0;
	int navDataSize = 0;

	if(config.recastConfig->maxVertsPerPoly > DT_VERTS_PER_POLYGON)
	{
		return;
	}

#if defined(DEBUG) || defined(_DEBUG)
	std::cout << "Detour - Stage 1" << std::endl;
#endif

	for(int i = 0; i < polyMesh->npolys; ++i)
	{
		if(polyMesh->areas[i] == RC_WALKABLE_AREA)
		{
			polyMesh->areas[i] = DT_PA_GROUND;
			polyMesh->flags[i] = DT_PF_WALK;
		}
	}

	dtNavMeshCreateParams params;
	memset(&params,0,sizeof(params));
	params.verts = polyMesh->verts;
	params.vertCount = polyMesh->nverts;
	params.polys = polyMesh->polys;
	params.polyAreas = polyMesh->areas;
	params.polyFlags = polyMesh->flags;
	params.polyCount = polyMesh->npolys;
	params.nvp = polyMesh->nvp;
	params.detailMeshes = detailMesh->meshes;
	params.detailVerts = detailMesh->verts;
	params.detailVertsCount = detailMesh->nverts;
	params.detailTris = detailMesh->tris;
	params.detailTriCount = detailMesh->ntris;

	//offmesh connections are not implemented. I don't even know what they are!
	params.offMeshConCount = 0;

	params.walkableHeight = config.userConfig->getAgentHeight();
	params.walkableRadius = config.userConfig->getAgentRadius();
	params.walkableClimb = config.userConfig->getAgentMaxClimb();
	params.buildBvTree = true;

	rcVcopy(params.bmin, config.recastConfig->bmin);
	rcVcopy(params.bmax, config.recastConfig->bmax);
	params.cs = config.recastConfig->cs;
	params.ch = config.recastConfig->ch;

#if defined(DEBUG) || defined(_DEBUG)
	std::cout << "Detour - Stage 2" << std::endl;
#endif

	if(!dtCreateNavMeshData(&params,&navData,&navDataSize))
	{
		std::cout << "Error! Detour - could not build navmesh!" << std::endl;
		std::cout << " - " << params.cs << std::endl;
		std::cout << " - " << params.ch << std::endl;
		std::cout << " - " << params.walkableRadius << std::endl;
		//_isMeshBuilt = false;
		return;
	}

#if defined(DEBUG) || defined(_DEBUG)
	std::cout << "Detour - Stage 3" << std::endl;
#endif

	_navMesh = dtAllocNavMesh();
	if(!_navMesh)
	{
		dtFree(_navMesh);
		std::cout << "Error! Detour - could not create Detour navmesh!" << std::endl;
		return;
	}

#if defined(DEBUG) || defined(_DEBUG)
	std::cout << "Detour - Stage 4" << std::endl;
#endif

	dtStatus status;
	status = _navMesh->init(navData,navDataSize,DT_TILE_FREE_DATA);
	if(dtStatusFailed(status))
	{
		dtFree(navData);
		std::cout << "Error! Could not initialize Detour NavMesh." << std::endl;
		return;
	}

#if defined(DEBUG) || defined(_DEBUG)
	std::cout << "Detour - Stage 5" << std::endl;
#endif

	_navQuery = dtAllocNavMeshQuery();
	status = _navQuery->init(_navMesh,2048);
	if(dtStatusFailed(status))
	{
		std::cout << "Error! Detour - could not initialize Detour navmesh query." << std::endl;
		return;
	}

	_isMeshBuilt = true;
}
void NavigationMesh::SetNavigationDataAttr(PODVector<unsigned char> value)
{
    ReleaseNavigationMesh();
    
    if (value.Empty())
        return;
    
    MemoryBuffer buffer(value);
    
    boundingBox_ = buffer.ReadBoundingBox();
    numTilesX_ = buffer.ReadInt();
    numTilesZ_ = buffer.ReadInt();

    dtNavMeshParams params;
    rcVcopy(params.orig, &boundingBox_.min_.x_);
    params.tileWidth = buffer.ReadFloat();
    params.tileHeight = buffer.ReadFloat();
    params.maxTiles = buffer.ReadInt();
    params.maxPolys = buffer.ReadInt();
    
    navMesh_ = dtAllocNavMesh();
    if (!navMesh_)
    {
        LOGERROR("Could not allocate navigation mesh");
        return;
    }
    
    if (dtStatusFailed(navMesh_->init(&params)))
    {
        LOGERROR("Could not initialize navigation mesh");
        ReleaseNavigationMesh();
        return;
    }
    
    unsigned numTiles = 0;
    
    while (!buffer.IsEof())
    {
        /*int x =*/ buffer.ReadInt();
        /*int z =*/ buffer.ReadInt();
        /*dtTileRef tileRef =*/ buffer.ReadUInt();
        unsigned navDataSize = buffer.ReadUInt();
        
        unsigned char* navData = (unsigned char*)dtAlloc(navDataSize, DT_ALLOC_PERM);
        if (!navData)
        {
            LOGERROR("Could not allocate data for navigation mesh tile");
            return;
        }
        
        buffer.Read(navData, navDataSize);
        if (dtStatusFailed(navMesh_->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, 0)))
        {
            LOGERROR("Failed to add navigation mesh tile");
            dtFree(navData);
            return;
        }
        else
            ++numTiles;
    }
    
    LOGDEBUG("Created navigation mesh with " + String(numTiles) + " tiles from serialized data");
}
bool OgreDetourTileCache::loadAll(Ogre::String filename)
{
       FILE* fp = fopen(filename.data(), "rb");
       if (!fp) {
           Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). Could not open file.");
           return false;
       }

       // Read header.
       TileCacheSetHeader header;
       fread(&header, sizeof(TileCacheSetHeader), 1, fp);
       if (header.magic != TILECACHESET_MAGIC)
       {
           fclose(fp);
           Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). File does not appear to contain valid tilecache data.");
           return false;
       }
       if (header.version != TILECACHESET_VERSION)
       {
           fclose(fp);
           Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). File contains a different version of the tilecache data format ("+Ogre::StringConverter::toString(header.version)+" instead of "+Ogre::StringConverter::toString(TILECACHESET_VERSION)+").");
           return false;
       }

       m_recast->m_navMesh = dtAllocNavMesh();
       if (!m_recast->m_navMesh)
       {
           fclose(fp);
           Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). Could not allocate navmesh.");
           return false;
       }
       dtStatus status = m_recast->m_navMesh->init(&header.meshParams);
       if (dtStatusFailed(status))
       {
           fclose(fp);
           Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). Could not init navmesh.");
           return false;
       }

       m_tileCache = dtAllocTileCache();
       if (!m_tileCache)
       {
           fclose(fp);
           Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). Could not allocate tilecache.");
           return false;
       }
       status = m_tileCache->init(&header.cacheParams, m_talloc, m_tcomp, m_tmproc);
       if (dtStatusFailed(status))
       {
           fclose(fp);
           Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). Could not init tilecache.");
           return false;
       }

       memcpy(&m_cfg, &header.recastConfig, sizeof(rcConfig));

       // Read tiles.
       for (int i = 0; i < header.numTiles; ++i)
       {
               TileCacheTileHeader tileHeader;
               fread(&tileHeader, sizeof(tileHeader), 1, fp);
               if (!tileHeader.tileRef || !tileHeader.dataSize)
                       break;

               unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
               if (!data) break;
               memset(data, 0, tileHeader.dataSize);
               fread(data, tileHeader.dataSize, 1, fp);

               dtCompressedTileRef tile = 0;
               m_tileCache->addTile(data, tileHeader.dataSize, DT_COMPRESSEDTILE_FREE_DATA, &tile);

               if (tile)
                       m_tileCache->buildNavMeshTile(tile, m_recast->m_navMesh);
       }

       fclose(fp);


       // Init recast navmeshquery with created navmesh (in OgreRecast component)
       m_recast->m_navQuery = dtAllocNavMeshQuery();
       m_recast->m_navQuery->init(m_recast->m_navMesh, 2048);


       // Config
       // TODO handle this nicer, also inputGeom is not inited, making some functions crash
       m_cellSize = m_cfg.cs;
       m_tileSize = m_cfg.tileSize;

       // cache bounding box
       const float* bmin = m_cfg.bmin;
       const float* bmax = m_cfg.bmax;

       // Copy loaded config back to recast module
       memcpy(&m_recast->m_cfg, &m_cfg, sizeof(rcConfig));

       m_tileSize = m_cfg.tileSize;
       m_cellSize = m_cfg.cs;
       m_tcparams = header.cacheParams;

       // Determine grid size (number of tiles) based on bounding box and grid cell size
       int gw = 0, gh = 0;
       rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh);   // Calculates total size of voxel grid
       const int ts = m_tileSize;
       const int tw = (gw + ts-1) / ts;    // Tile width
       const int th = (gh + ts-1) / ts;    // Tile height
       m_tw = tw;
       m_th = th;


       Ogre::LogManager::getSingletonPtr()->logMessage("Total Voxels: "+Ogre::StringConverter::toString(gw) + " x " + Ogre::StringConverter::toString(gh));
       Ogre::LogManager::getSingletonPtr()->logMessage("Tilesize: "+Ogre::StringConverter::toString(m_tileSize)+"  Cellsize: "+Ogre::StringConverter::toString(m_cellSize));
       Ogre::LogManager::getSingletonPtr()->logMessage("Tiles: "+Ogre::StringConverter::toString(m_tw)+" x "+Ogre::StringConverter::toString(m_th));


       // Max tiles and max polys affect how the tile IDs are caculated.
       // There are 22 bits available for identifying a tile and a polygon.
       int tileBits = rcMin((int)dtIlog2(dtNextPow2(tw*th*EXPECTED_LAYERS_PER_TILE)), 14);
       if (tileBits > 14) tileBits = 14;
       int polyBits = 22 - tileBits;
       m_maxTiles = 1 << tileBits;
       m_maxPolysPerTile = 1 << polyBits;
       Ogre::LogManager::getSingletonPtr()->logMessage("Max Tiles: " + Ogre::StringConverter::toString(m_maxTiles));
       Ogre::LogManager::getSingletonPtr()->logMessage("Max Polys: " + Ogre::StringConverter::toString(m_maxPolysPerTile));
       // End config ////

       buildInitialNavmesh();
       return true;
}
Exemple #18
0
	bool NavMesh::BuildMesh()
	{
		dtStatus status;
		if (!m_geom || !m_geom->getMesh()) return false;
		m_tmproc->init(m_geom);
		// Init cache
		const float* bmin = m_geom->getMeshBoundsMin();
		const float* bmax = m_geom->getMeshBoundsMax();
		int gw = 0, gh = 0;
		rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh);
		const int ts = (int)m_tileSize;
		const int tw = (gw + ts-1) / ts;
		const int th = (gh + ts-1) / ts;
		// Generation params.
		rcConfig cfg;
		memset(&cfg, 0, sizeof(cfg));
		cfg.cs = m_cellSize;
		cfg.ch = m_cellHeight;
		cfg.walkableSlopeAngle = m_agentMaxSlope;
		cfg.walkableHeight = (int)ceilf(m_agentHeight / cfg.ch);
		cfg.walkableClimb = (int)floorf(m_agentMaxClimb / cfg.ch);
		cfg.walkableRadius = (int)ceilf(m_agentRadius / cfg.cs);
		cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize);
		cfg.maxSimplificationError = m_edgeMaxError;
		cfg.minRegionArea = (int)rcSqr(m_regionMinSize);		// Note: area = size*size
		cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize);	// Note: area = size*size
		cfg.maxVertsPerPoly = (int)m_vertsPerPoly;
		cfg.tileSize = (int)m_tileSize;
		cfg.borderSize = cfg.walkableRadius + 3; // Reserve enough padding.
		cfg.width = cfg.tileSize + cfg.borderSize*2;
		cfg.height = cfg.tileSize + cfg.borderSize*2;
		cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist;
		cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError;
		rcVcopy(cfg.bmin, bmin);
		rcVcopy(cfg.bmax, bmax);
		// Tile cache params.
		dtTileCacheParams tcparams;
		memset(&tcparams, 0, sizeof(tcparams));
		rcVcopy(tcparams.orig, bmin);
		tcparams.cs = m_cellSize;
		tcparams.ch = m_cellHeight;
		tcparams.width = (int)m_tileSize;
		tcparams.height = (int)m_tileSize;
		tcparams.walkableHeight = m_agentHeight;
		tcparams.walkableRadius = m_agentRadius;
		tcparams.walkableClimb = m_agentMaxClimb;
		tcparams.maxSimplificationError = m_edgeMaxError;
		tcparams.maxTiles = tw*th*EXPECTED_LAYERS_PER_TILE;
		tcparams.maxObstacles = 128;

		dtFreeTileCache(m_tileCache);

		m_tileCache = dtAllocTileCache();
		if (!m_tileCache) return false;
		status = m_tileCache->init(&tcparams, m_talloc, m_tcomp, m_tmproc);
		if (dtStatusFailed(status)) return false;

		dtFreeNavMesh(m_navMesh);

		m_navMesh = dtAllocNavMesh();
		if (!m_navMesh) return false;

		dtNavMeshParams params;
		memset(&params, 0, sizeof(params));
		rcVcopy(params.orig, m_geom->getMeshBoundsMin());
		params.tileWidth = m_tileSize*m_cellSize;
		params.tileHeight = m_tileSize*m_cellSize;
		params.maxTiles = m_maxTiles;
		params.maxPolys = m_maxPolysPerTile;

		status = m_navMesh->init(&params);
		if (dtStatusFailed(status)) return false;

		status = m_navQuery->init(m_navMesh, 2048);
		if (dtStatusFailed(status)) return false;

		for (int y = 0; y < th; ++y)
		{
			for (int x = 0; x < tw; ++x)
			{
				TileCacheData tiles[MAX_LAYERS];
				memset(tiles, 0, sizeof(tiles));
				int n = rasterizeTileLayers(m_geom, x, y, cfg, tiles, MAX_LAYERS);
				for (int i = 0; i < n; ++i)
				{
					TileCacheData* tile = &tiles[i];
					status = m_tileCache->addTile(tile->data, tile->dataSize, DT_COMPRESSEDTILE_FREE_DATA, 0);
					if (dtStatusFailed(status))
					{
						dtFree(tile->data);
						tile->data = 0;
						continue;
					}
				}
			}
		}
		for (int y = 0; y < th; ++y)
			for (int x = 0; x < tw; ++x)
				m_tileCache->buildNavMeshTilesAt(x,y, m_navMesh);
	}
bool NavMesher::Build()
{
  // ******* Only for OBJ Loading ****
 cleanup();
 const char * filepath = "../../media/models/";
 if (!m_geom || !m_geom->loadMesh(filepath))
 {
  delete m_geom;
  m_geom = 0;
  
  m_ctx->log(RC_LOG_ERROR, "Geom load log %s:");
 }
 assert(m_geom);
 if (!m_geom || !m_geom->getMesh())
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Input mesh is not specified.");
  return false;
 }
 if(m_geom->getMesh()->getTriCount() <= 0 || m_geom->getMesh()->getVertCount()<=0)
  Ogre::Exception(0,Ogre::String("Bad verts or Triangle count. Verts: "+
  StringConverter::toString( m_geom->getMesh()->getVertCount()) + "/n"
  + "Triangles :" +StringConverter::toString(m_geom->getMesh()->getTriCount())),"NavMesher::Build");
 
 //reset timer
 Ogre::Timer tm;
 tm.reset();
 unsigned long stime = tm.getMicroseconds();
 //clear existing
 Clear();
  // ******* Only for OBJ Loading ****
 const float* bmin = m_geom->getMeshBoundsMin();
 const float* bmax = m_geom->getMeshBoundsMax();
 const float* verts = m_geom->getMesh()->getVerts();
 const int nverts = m_geom->getMesh()->getVertCount();
 const int *tris = m_geom->getMesh()->getTris();
 const int ntris = m_geom->getMesh()->getTriCount();

 if(sizeof(tris) <= 0 || ntris <= 0) {
  return false;
 }
 //
 // Step 1. Initialize build config.
 //
 
 // Init build configuration from GUI
 memset(&m_cfg, 0, sizeof(m_cfg));
 m_cfg.cs = m_cellSize;
 m_cfg.ch = m_cellHeight;
 m_cfg.walkableSlopeAngle = m_agentMaxSlope;
 m_cfg.walkableHeight = (int)ceilf(m_agentHeight / m_cfg.ch);
 m_cfg.walkableClimb = (int)floorf(m_agentMaxClimb / m_cfg.ch);
 m_cfg.walkableRadius = (int)ceilf(m_agentRadius / m_cfg.cs);
 m_cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize);
 m_cfg.maxSimplificationError = m_edgeMaxError;
 m_cfg.minRegionArea = (int)rcSqr(m_regionMinSize);  // Note: area = size*size
 m_cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize); // Note: area = size*size
 m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly;
 m_cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist;
 m_cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError;
 
 // Set the area where the navigation will be build.
 // Here the bounds of the input mesh are used, but the
 // area could be specified by an user defined box, etc.
 rcVcopy(m_cfg.bmin, bmin);
 rcVcopy(m_cfg.bmax, bmax);
 rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height);
 // Reset build times gathering.
 m_ctx->resetTimers();
 // Start the build process. 
 m_ctx->startTimer(RC_TIMER_TOTAL);
 
 m_ctx->log(RC_LOG_PROGRESS, "Building navigation:");
 m_ctx->log(RC_LOG_PROGRESS, " - %d x %d cells", m_cfg.width, m_cfg.height);
 m_ctx->log(RC_LOG_PROGRESS, " - %.1fK verts, %.1fK tris", nverts/1000.0f, ntris/1000.0f);
 
 //
 // Step 2. Rasterize input polygon soup.
 //
 
 // Allocate voxel heightfield where we rasterize our input data to.
 m_solid = rcAllocHeightfield();
 if (!m_solid)
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'.");
  return false;
 }
 if (!rcCreateHeightfield(m_ctx, *m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch))
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not create solid heightfield.");
  return false;
 }
 
 // Allocate array that can hold triangle area types.
 // If you have multiple meshes you need to process, allocate
 // and array which can hold the max number of triangles you need to process.
 m_triareas = new unsigned char[ntris];
 if (!m_triareas)
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'm_triareas' (%d).", ntris);
  return false;
 }
 
 // Find triangles which are walkable based on their slope and rasterize them.
 // If your input data is multiple meshes, you can transform them here, calculate
 // the are type for each of the meshes and rasterize them.
 memset(m_triareas, 0, ntris*sizeof(unsigned char));
 rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, m_triareas);
 rcRasterizeTriangles(m_ctx, verts, nverts, tris, m_triareas, ntris, *m_solid, m_cfg.walkableClimb);
 if (!m_keepInterResults)
 {
  delete [] m_triareas;
  m_triareas = 0;
 }
 
 //
 // Step 3. Filter walkables surfaces.
 //
 
 // Once all geoemtry is rasterized, we do initial pass of filtering to
 // remove unwanted overhangs caused by the conservative rasterization
 // as well as filter spans where the character cannot possibly stand.
 rcFilterLowHangingWalkableObstacles(m_ctx, m_cfg.walkableClimb, *m_solid);
 rcFilterLedgeSpans(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid);
 rcFilterWalkableLowHeightSpans(m_ctx, m_cfg.walkableHeight, *m_solid);

 //
 // Step 4. Partition walkable surface to simple regions.
 //
 // Compact the heightfield so that it is faster to handle from now on.
 // This will result more cache coherent data as well as the neighbours
 // between walkable cells will be calculated.
 m_chf = rcAllocCompactHeightfield();
 if (!m_chf)
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'.");
  return false;
 }
 if (!rcBuildCompactHeightfield(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid, *m_chf))
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build compact data.");
  return false;
 }
 
 if (!m_keepInterResults)
 {
  rcFreeHeightField(m_solid);
  m_solid = 0;
 }
  
 // Erode the walkable area by agent radius.
 if (!rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, *m_chf))
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not erode.");
  return false;
 }
 // (Optional) Mark areas.
 const ConvexVolume* vols = m_geom->getConvexVolumes();
 for (int i  = 0; i < m_geom->getConvexVolumeCount(); ++i)
  rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned char)vols[i].area, *m_chf);
 
 if (m_monotonePartitioning)
 {
  // Partition the walkable surface into simple regions without holes.
  // Monotone partitioning does not need distancefield.
  if (!rcBuildRegionsMonotone(m_ctx, *m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
  {
   m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build regions.");
   return false;
  }
 }
 else
 {
  // Prepare for region partitioning, by calculating distance field along the walkable surface.
  if (!rcBuildDistanceField(m_ctx, *m_chf))
  {
   m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build distance field.");
   return false;
  }
  // Partition the walkable surface into simple regions without holes.
  if (!rcBuildRegions(m_ctx, *m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
  {
   m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build regions.");
   return false;
  }
 }
 //
 // Step 5. Trace and simplify region contours.
 //
 
 // Create contours.
 m_cset = rcAllocContourSet();
 if (!m_cset)
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'.");
  return false;
 }
 if (!rcBuildContours(m_ctx, *m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *m_cset))
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not create contours.");
  return false;
 }
 
 //
 // Step 6. Build polygons mesh from contours.
 //
 
 // Build polygon navmesh from the contours.
 m_pmesh = rcAllocPolyMesh();
 if (!m_pmesh)
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmesh'.");
  return false;
 }
 if (!rcBuildPolyMesh(m_ctx, *m_cset, m_cfg.maxVertsPerPoly, *m_pmesh))
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not triangulate contours.");
  return false;
 }
 
 //
 // Step 7. Create detail mesh which allows to access approximate height on each polygon.
 //
 
 m_dmesh = rcAllocPolyMeshDetail();
 if (!m_dmesh)
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmdtl'.");
  return false;
 }
 if (!rcBuildPolyMeshDetail(m_ctx, *m_pmesh, *m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, *m_dmesh))
 {
  m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build detail mesh.");
  return false;
 }
 if (!m_keepInterResults)
 {
  rcFreeCompactHeightfield(m_chf);
  m_chf = 0;
  rcFreeContourSet(m_cset);
  m_cset = 0;
 }

 // At this point the navigation mesh data is ready, you can access it from m_pmesh.
 // See rcDebugDrawPolyMesh or dtCreateNavMeshData as examples how to access the data.
 
 //
 // (Optional) Step 8. Create Detour data from Recast poly mesh.
 //
 
 // The GUI may allow more max points per polygon than Detour can handle.
 // Only build the detour navmesh if we do not exceed the limit.
 unsigned char* navData = 0;
 int navDataSize = 0;
 // Update poly flags from areas.

 for (int i = 0; i < m_pmesh->npolys; ++i)
 {
  if (m_pmesh->areas[i] == RC_WALKABLE_AREA)
   m_pmesh->areas[i] = SAMPLE_POLYAREA_GROUND;
   
  if (m_pmesh->areas[i] == SAMPLE_POLYAREA_GROUND ||
   m_pmesh->areas[i] == SAMPLE_POLYAREA_GRASS ||
   m_pmesh->areas[i] == SAMPLE_POLYAREA_ROAD)
  {
   m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK;
  }
  else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_WATER)
  {
   m_pmesh->flags[i] = SAMPLE_POLYFLAGS_SWIM;
  }
  else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_DOOR)
  {
   m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR;
  }
 }

 memset(&m_params, 0, sizeof(m_params));
 m_params.verts = m_pmesh->verts;
 m_params.vertCount = m_pmesh->nverts;
 m_params.polys = m_pmesh->polys;
 m_params.polyAreas = m_pmesh->areas;
 m_params.polyFlags = m_pmesh->flags;
 m_params.polyCount = m_pmesh->npolys;
 m_params.nvp = m_pmesh->nvp;
 m_params.detailMeshes = m_dmesh->meshes;
 m_params.detailVerts = m_dmesh->verts;
 m_params.detailVertsCount = m_dmesh->nverts;
 m_params.detailTris = m_dmesh->tris;
 m_params.detailTriCount = m_dmesh->ntris;
 m_params.walkableHeight = m_agentHeight;
 m_params.walkableRadius = m_agentRadius;
 m_params.walkableClimb = m_agentMaxClimb;
 rcVcopy(m_params.bmin, m_pmesh->bmin);
 rcVcopy(m_params.bmax, m_pmesh->bmax);
 m_params.cs = m_cfg.cs;
 m_params.ch = m_cfg.ch;
 m_params.buildBvTree = true;
 if (!dtCreateNavMeshData(&m_params, &navData, &navDataSize)) {
   m_ctx->log(RC_LOG_ERROR, "Could not build Detour navmesh.");
  return false;
 }
 
 m_navMesh = dtAllocNavMesh();
 if (!m_navMesh) {
  delete [] navData;
   m_ctx->log(RC_LOG_ERROR, "Could not create Detour navmesh");
  return false;
 }
 m_navQuery = dtAllocNavMeshQuery(); 
 dtStatus status = m_navQuery->init(m_navMesh, 2048);
   if (dtStatusFailed(status)) {
           m_ctx->log(RC_LOG_ERROR, "Could not init Detour navmesh query");
           return false;
   }
 if (!m_navMesh->init(navData, navDataSize, true)) {
  delete [] navData;
   m_ctx->log(RC_LOG_ERROR, "Could not init Detour navmesh");
  return false;
 }
 //take time
 stime = tm.getMicroseconds() - stime;
 DrawDebug();
 return true;
}
/*!
	Build a NAVIGATION mesh from an OBJ mesh index. Usually this OBJMESH is either a collision map
	or a mesh that have been built especially for navigation.
	
	\param[in,out] navigation A valid NAVIGATION structure pointer.
	\param[in] obj A valid OBJ structure pointer.
	\param[in] mesh_index The mesh index of the OBJMESH to use to create the NAVIGATION mesh.
	
	\return Return 1 if the NAVIGATION mesh have been generated successfully, else this function will return 0.
*/
unsigned char NAVIGATION_build( NAVIGATION *navigation, OBJ *obj, unsigned int mesh_index )
{
	unsigned int i = 0,
				 j = 0,
				 k = 0,
				 triangle_count = 0;
	
	int *indices = NULL;
	
	OBJMESH *objmesh = &obj->objmesh[ mesh_index ];
	
	vec3 *vertex_array = ( vec3 * ) malloc( objmesh->n_objvertexdata * sizeof( vec3 ) ),
		 *vertex_start = vertex_array;

	rcHeightfield *rcheightfield;
	
	rcCompactHeightfield *rccompactheightfield;
	
	rcContourSet *rccontourset;

	rcPolyMesh *rcpolymesh;
	
	rcPolyMeshDetail *rcpolymeshdetail;
	
	
	while( i != objmesh->n_objvertexdata )
	{ 
		memcpy( vertex_array,
				&obj->indexed_vertex[ objmesh->objvertexdata[ i ].vertex_index ],
				sizeof( vec3 ) );
				
		vec3_to_recast( vertex_array );
		
		++vertex_array;						
		++i;
	}
	
	
	i = 0;
	while( i != objmesh->n_objtrianglelist )
	{
		triangle_count += objmesh->objtrianglelist[ i ].n_indice_array;
	
		indices = ( int * ) realloc( indices, triangle_count * sizeof( int ) );
	
		j = 0;
		while( j != objmesh->objtrianglelist[ i ].n_indice_array )
		{
			indices[ k ] = objmesh->objtrianglelist[ i ].indice_array[ j ];
		
			++k;
			++j;
		}

		++i;
	}
	
	triangle_count /= 3;
	
	rcConfig rcconfig;

	memset( &rcconfig, 0, sizeof( rcConfig ) );
	
	rcconfig.cs						= navigation->navigationconfiguration.cell_size;
	rcconfig.ch						= navigation->navigationconfiguration.cell_height;
	rcconfig.walkableHeight			= ( int )ceilf ( navigation->navigationconfiguration.agent_height / rcconfig.ch );
	rcconfig.walkableRadius			= ( int )ceilf ( navigation->navigationconfiguration.agent_radius / rcconfig.cs );
	rcconfig.walkableClimb			= ( int )floorf( navigation->navigationconfiguration.agent_max_climb / rcconfig.ch );
	rcconfig.walkableSlopeAngle		= navigation->navigationconfiguration.agent_max_slope;
	rcconfig.minRegionSize			= ( int )rcSqr( navigation->navigationconfiguration.region_min_size );
	rcconfig.mergeRegionSize		= ( int )rcSqr( navigation->navigationconfiguration.region_merge_size );
	rcconfig.maxEdgeLen				= ( int )( navigation->navigationconfiguration.edge_max_len / rcconfig.cs );
	rcconfig.maxSimplificationError = navigation->navigationconfiguration.edge_max_error;
	rcconfig.maxVertsPerPoly		= ( int )navigation->navigationconfiguration.vert_per_poly;
	rcconfig.detailSampleDist		= rcconfig.cs * navigation->navigationconfiguration.detail_sample_dst;
	rcconfig.detailSampleMaxError   = rcconfig.ch * navigation->navigationconfiguration.detail_sample_max_error;
			
	
	rcCalcBounds( ( float * )vertex_start,
				  objmesh->n_objvertexdata,
				  rcconfig.bmin,
				  rcconfig.bmax );
	
	
	rcCalcGridSize(  rcconfig.bmin,
					 rcconfig.bmax,
					 rcconfig.cs,
					&rcconfig.width,
					&rcconfig.height );


	rcheightfield = rcAllocHeightfield();

	rcCreateHeightfield( *rcheightfield,
						  rcconfig.width,
						  rcconfig.height,
						  rcconfig.bmin,
						  rcconfig.bmax,
						  rcconfig.cs,
						  rcconfig.ch );


	navigation->triangle_flags = new unsigned char[ triangle_count ];
	
	memset( navigation->triangle_flags, 0, triangle_count * sizeof( unsigned char ) );
	
	rcMarkWalkableTriangles( rcconfig.walkableSlopeAngle,
							 ( float * )vertex_start,
							 objmesh->n_objvertexdata,
							 indices,
							 triangle_count,
							 navigation->triangle_flags );
	

	rcRasterizeTriangles( ( float * )vertex_start,
						  objmesh->n_objvertexdata,
						  indices,
						  navigation->triangle_flags,
						  triangle_count,
						 *rcheightfield,
						  rcconfig.walkableClimb );


	delete []navigation->triangle_flags;
	navigation->triangle_flags = NULL;

	free( vertex_start );
	free( indices      );
	

	rcFilterLowHangingWalkableObstacles(  rcconfig.walkableClimb,
										 *rcheightfield );
	
	
	rcFilterLedgeSpans(  rcconfig.walkableHeight,
						 rcconfig.walkableClimb,
						*rcheightfield );
	
	
	rcFilterWalkableLowHeightSpans(  rcconfig.walkableHeight,
									*rcheightfield );

	
	rccompactheightfield = rcAllocCompactHeightfield();

	rcBuildCompactHeightfield( rcconfig.walkableHeight,
							   rcconfig.walkableClimb,
							   RC_WALKABLE,
							   *rcheightfield,
							   *rccompactheightfield );

	rcFreeHeightField( rcheightfield );
	rcheightfield = NULL;

	rcErodeArea( RC_WALKABLE_AREA,
				 rcconfig.walkableRadius,
				 *rccompactheightfield );


	rcBuildDistanceField( *rccompactheightfield );


	rcBuildRegions( *rccompactheightfield,
					 rcconfig.borderSize,
					 rcconfig.minRegionSize,
					 rcconfig.mergeRegionSize );


	rccontourset = rcAllocContourSet();

	rcBuildContours( *rccompactheightfield,
					  rcconfig.maxSimplificationError,
					  rcconfig.maxEdgeLen,
					 *rccontourset );


	rcpolymesh = rcAllocPolyMesh();
	
	rcBuildPolyMesh( *rccontourset,
					  rcconfig.maxVertsPerPoly,
					 *rcpolymesh );


	rcpolymeshdetail = rcAllocPolyMeshDetail();

	rcBuildPolyMeshDetail( *rcpolymesh,
						   *rccompactheightfield,
							rcconfig.detailSampleDist,
							rcconfig.detailSampleMaxError,
						   *rcpolymeshdetail );


	rcFreeCompactHeightfield( rccompactheightfield );
	rccompactheightfield = NULL;
	
	rcFreeContourSet( rccontourset );
	rccontourset = NULL;


	if( rcconfig.maxVertsPerPoly <= DT_VERTS_PER_POLYGON )
	{
		dtNavMeshCreateParams dtnavmeshcreateparams;
		
		unsigned char *nav_data = NULL;
		
		int nav_data_size = 0;
	
		i = 0;
		while( i != rcpolymesh->npolys )
		{
			if( rcpolymesh->areas[ i ] == RC_WALKABLE_AREA )
			{
				rcpolymesh->areas[ i ] = 0;
				rcpolymesh->flags[ i ] = 0x01;
			}
							
			++i;
		}


		memset( &dtnavmeshcreateparams, 0, sizeof( dtNavMeshCreateParams ) );
		
		dtnavmeshcreateparams.verts			   = rcpolymesh->verts;
		dtnavmeshcreateparams.vertCount		   = rcpolymesh->nverts;
		dtnavmeshcreateparams.polys			   = rcpolymesh->polys;
		dtnavmeshcreateparams.polyAreas		   = rcpolymesh->areas;
		dtnavmeshcreateparams.polyFlags		   = rcpolymesh->flags;
		dtnavmeshcreateparams.polyCount		   = rcpolymesh->npolys;
		dtnavmeshcreateparams.nvp			   = rcpolymesh->nvp;
		
		dtnavmeshcreateparams.detailMeshes	   = rcpolymeshdetail->meshes;
		dtnavmeshcreateparams.detailVerts	   = rcpolymeshdetail->verts;
		dtnavmeshcreateparams.detailVertsCount = rcpolymeshdetail->nverts;
		dtnavmeshcreateparams.detailTris       = rcpolymeshdetail->tris;
		dtnavmeshcreateparams.detailTriCount   = rcpolymeshdetail->ntris;
		
		dtnavmeshcreateparams.walkableHeight   = navigation->navigationconfiguration.agent_height;
		dtnavmeshcreateparams.walkableRadius   = navigation->navigationconfiguration.agent_radius;
		dtnavmeshcreateparams.walkableClimb    = navigation->navigationconfiguration.agent_max_climb;
		
		rcVcopy( dtnavmeshcreateparams.bmin, rcpolymesh->bmin );
		rcVcopy( dtnavmeshcreateparams.bmax, rcpolymesh->bmax );
		
		dtnavmeshcreateparams.cs = rcconfig.cs;
		dtnavmeshcreateparams.ch = rcconfig.ch;
		
		
		dtCreateNavMeshData( &dtnavmeshcreateparams,
							 &nav_data,
							 &nav_data_size );
		
		if( !nav_data ) return 0;
		
		navigation->dtnavmesh = dtAllocNavMesh();
		
		navigation->dtnavmesh->init( nav_data,
									 nav_data_size,
									 DT_TILE_FREE_DATA,
									 NAVIGATION_MAX_NODE );
		
		rcFreePolyMesh( rcpolymesh );
		rcpolymesh = NULL;
		
		rcFreePolyMeshDetail( rcpolymeshdetail );
		rcpolymeshdetail = NULL;
		
		return 1;
	}
	
	return 0;
}
bool NavMeshGenerator::handleBuild(const Array2D<int>& tab)
{

	cleanup();
	
	//
	// Step 1. Initialize build config.
	//
	
	// Init build configuration from GUI
	memset(&m_cfg, 0, sizeof(m_cfg));

	const int voxels_per_tile = 3; //3
	
	m_cfg.width = tab.size().x*3*voxels_per_tile;
	m_cfg.height = tab.size().x*3*voxels_per_tile;

	m_cfg.cs = pixels_per_tile/float(voxels_per_tile);
	m_cfg.walkableRadius = voxels_per_tile == 1 ? 0 : 1;
	m_cfg.maxEdgeLen = 0;//20; // 
	m_cfg.maxSimplificationError = 0.f; // 0 or 1, no need because we are working on tiles
	m_cfg.minRegionArea = 64;//(int)rcSqr(m_regionMinSize);		// Note: area = size*size
	m_cfg.mergeRegionArea = 10000;//(int)rcSqr(m_regionMergeSize);	// Note: area = size*size
	m_cfg.maxVertsPerPoly = 4;//(int)m_vertsPerPoly;

	
	m_cfg.ch = 0.2f; // < height info, not used
	m_cfg.detailSampleDist = 20.f; // < height info, not used
	m_cfg.detailSampleMaxError = 0.2f; // < height info, not used
	m_cfg.walkableSlopeAngle = 0; // < height info, not used
	m_cfg.walkableHeight = 0; // < height info, not used
	m_cfg.walkableClimb = 0; // < height info, not used
	 

	// Set the area where the navigation will be build.
	m_cfg.bmin[0] = 0;
	m_cfg.bmin[1] = 0;
	m_cfg.bmin[2] = 0;

	m_cfg.bmax[0] = tab.size().x*3*pixels_per_tile;
	m_cfg.bmax[1] = 3;
	m_cfg.bmax[2] = tab.size().y*3*pixels_per_tile;


	// Reset build times gathering.
	m_ctx->resetTimers();

	// Start the build process.	
	m_ctx->startTimer(RC_TIMER_TOTAL);
	
	m_ctx->log(RC_LOG_PROGRESS, "Building navigation:");
	m_ctx->log(RC_LOG_PROGRESS, " - %d x %d cells", m_cfg.width, m_cfg.height);
	
	//
	// Step 2. Create Heightfield
	//
	
	// Allocate voxel heightfield
	m_solid = rcAllocHeightfield();
	if (!m_solid)
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'.");
		return false;
	}
	if (!rcCreateHeightfield(m_ctx, *m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch))
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not create solid heightfield.");
		return false;
	}
	

	for(int i = 0; i < m_solid->width; ++i) {
		for(int j = 0; j < m_solid->height; ++j) {
			bool colide = tab(int(i*tab.size().x/m_solid->width)  , int(j*tab.size().y/m_solid->height)) != 0 ;
			rcAddSpan(NULL, 
				*m_solid, i, j, 0, 
				colide ? 10: 0, colide ? RC_NULL_AREA : RC_WALKABLE_AREA, 1);
		}
	}
	
	//
	// Step 3. Filter walkables surfaces.
	//----> Not done for 2D


	//
	// Step 4. Partition walkable surface to simple regions.
	//

	// Compact the heightfield so that it is faster to handle from now on.
	// This will result more cache coherent data as well as the neighbours
	// between walkable cells will be calculated.
	m_chf = rcAllocCompactHeightfield();
	if (!m_chf)
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'.");
		return false;
	}
	if (!rcBuildCompactHeightfield(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid, *m_chf))
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build compact data.");
		return false;
	}
	
	if (!m_keepInterResults)
	{
		rcFreeHeightField(m_solid);
		m_solid = 0;
	}
		
	// Erode the walkable area by agent radius.
	if (!rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, *m_chf))
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not erode.");
		return false;
	}

	// (Optional) Mark areas.
	/*const ConvexVolume* vols = m_geom->getConvexVolumes();
	for (int i  = 0; i < m_geom->getConvexVolumeCount(); ++i)
	rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned char)vols[i].area, *m_chf);
	*/
	
	// Partition the heightfield so that we can use simple algorithm later to triangulate the walkable areas.
	// There are 3 martitioning methods, each with some pros and cons:
	// 1) Watershed partitioning
	//   - the classic Recast partitioning
	//   - creates the nicest tessellation
	//   - usually slowest
	//   - partitions the heightfield into nice regions without holes or overlaps
	//   - the are some corner cases where this method creates produces holes and overlaps
	//      - holes may appear when a small obstacles is close to large open area (triangulation can handle this)
	//      - overlaps may occur if you have narrow spiral corridors (i.e stairs), this make triangulation to fail
	//   * generally the best choice if you precompute the nacmesh, use this if you have large open areas
	// 2) Monotone partioning
	//   - fastest
	//   - partitions the heightfield into regions without holes and overlaps (guaranteed)
	//   - creates long thin polygons, which sometimes causes paths with detours
	//   * use this if you want fast navmesh generation
	// 3) Layer partitoining
	//   - quite fast
	//   - partitions the heighfield into non-overlapping regions
	//   - relies on the triangulation code to cope with holes (thus slower than monotone partitioning)
	//   - produces better triangles than monotone partitioning
	//   - does not have the corner cases of watershed partitioning
	//   - can be slow and create a bit ugly tessellation (still better than monotone)
	//     if you have large open areas with small obstacles (not a problem if you use tiles)
	//   * good choice to use for tiled navmesh with medium and small sized tiles
	
	if (true) //m_partitionType == SAMPLE_PARTITION_WATERSHED)
	{
		// Prepare for region partitioning, by calculating distance field along the walkable surface.
		if (!rcBuildDistanceField(m_ctx, *m_chf))
		{
			m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build distance field.");
			return false;
		}
		
		// Partition the walkable surface into simple regions without holes.
		if (!rcBuildRegions(m_ctx, *m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
		{
			m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build watershed regions.");
			return false;
		}
	}
	else if (false)//m_partitionType == SAMPLE_PARTITION_MONOTONE)
	{
		// Partition the walkable surface into simple regions without holes.
		// Monotone partitioning does not need distancefield.
		if (!rcBuildRegionsMonotone(m_ctx, *m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
		{
			m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build monotone regions.");
			return false;
		}
	}
	else // SAMPLE_PARTITION_LAYERS
	{
		// Partition the walkable surface into simple regions without holes.
		if (!rcBuildLayerRegions(m_ctx, *m_chf, 0, m_cfg.minRegionArea))
		{
			m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build layer regions.");
			return false;
		}
	}
	
	//
	// Step 5. Trace and simplify region contours.
	//
	
	// Create contours.
	m_cset = rcAllocContourSet();
	if (!m_cset)
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'.");
		return false;
	}
	if (!rcBuildContours(m_ctx, *m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *m_cset))
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not create contours.");
		return false;
	}
	
	//
	// Step 6. Build polygons mesh from contours.
	//
	
	// Build polygon navmesh from the contours.
	m_pmesh = rcAllocPolyMesh();
	if (!m_pmesh)
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmesh'.");
		return false;
	}
	if (!rcBuildPolyMesh(m_ctx, *m_cset, m_cfg.maxVertsPerPoly, *m_pmesh))
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not triangulate contours.");
		return false;
	}
	
	//
	// Step 7. Create detail mesh which allows to access approximate height on each polygon.
	//
	
	m_dmesh = rcAllocPolyMeshDetail();
	if (!m_dmesh)
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmdtl'.");
		return false;
	}

	if (!rcBuildPolyMeshDetail(m_ctx, *m_pmesh, *m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, *m_dmesh))
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build detail mesh.");
		return false;
	}

	if (!m_keepInterResults)
	{
		rcFreeCompactHeightfield(m_chf);
		m_chf = 0;
		rcFreeContourSet(m_cset);
		m_cset = 0;
	}

	// At this point the navigation mesh data is ready, you can access it from m_pmesh.
	// See duDebugDrawPolyMesh or dtCreateNavMeshData as examples how to access the data.
	
	//
	// (Optional) Step 8. Create Detour data from Recast poly mesh.
	//
	
	// The GUI may allow more max points per polygon than Detour can handle.
	// Only build the detour navmesh if we do not exceed the limit.
	if (m_cfg.maxVertsPerPoly <= DT_VERTS_PER_POLYGON)
	{
		unsigned char* navData = 0;
		int navDataSize = 0;

		// Update poly flags from areas.
		for (int i = 0; i < m_pmesh->npolys; ++i)
		{
			//if (m_pmesh->areas[i] == RC_WALKABLE_AREA)
			//	m_pmesh->areas[i] = SAMPLE_POLYAREA_GROUND;
				
			if (m_pmesh->areas[i] == RC_WALKABLE_AREA)
			{
				m_pmesh->flags[i] = 1;
			}
			else {
				m_pmesh->flags[i] = 0;
			}
		}
		

		dtNavMeshCreateParams params;
		memset(&params, 0, sizeof(params));
		params.verts = m_pmesh->verts;
		params.vertCount = m_pmesh->nverts;
		params.polys = m_pmesh->polys;
		params.polyAreas = m_pmesh->areas;
		params.polyFlags = m_pmesh->flags;
		params.polyCount = m_pmesh->npolys;
		params.nvp = m_pmesh->nvp;
		params.detailMeshes = m_dmesh->meshes;
		params.detailVerts = m_dmesh->verts;
		params.detailVertsCount = m_dmesh->nverts;
		params.detailTris = m_dmesh->tris;
		params.detailTriCount = m_dmesh->ntris;
		params.offMeshConCount = 0;
		/*
		unused since offMeshConCount is null
		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.walkableHeight = m_agentHeight;
		params.walkableRadius = m_agentRadius;
		params.walkableClimb = m_agentMaxClimb;
		rcVcopy(params.bmin, m_pmesh->bmin);
		rcVcopy(params.bmax, m_pmesh->bmax);
		params.cs = m_cfg.cs;
		params.ch = m_cfg.ch;
		params.buildBvTree = true;
		
		if (!dtCreateNavMeshData(&params, &navData, &navDataSize))
		{
			m_ctx->log(RC_LOG_ERROR, "Could not build Detour navmesh.");
			return false;
		}
		
		m_navMesh = dtAllocNavMesh();
		if (!m_navMesh)
		{
			dtFree(navData);
			m_ctx->log(RC_LOG_ERROR, "Could not create Detour navmesh");
			return false;
		}
		
		dtStatus status;
		
		status = m_navMesh->init(navData, navDataSize, DT_TILE_FREE_DATA);
		if (dtStatusFailed(status))
		{
			dtFree(navData);
			m_ctx->log(RC_LOG_ERROR, "Could not init Detour navmesh");
			return false;
		}
		
		status = m_navQuery->init(m_navMesh, 2048);
		if (dtStatusFailed(status))
		{
			m_ctx->log(RC_LOG_ERROR, "Could not init Detour navmesh query");
			return false;
		}
	}
	
	m_ctx->stopTimer(RC_TIMER_TOTAL);

	// Show performance stats.

	m_ctx->log(RC_LOG_PROGRESS, ">> Polymesh: %d vertices  %d polygons", m_pmesh->nverts, m_pmesh->npolys);
	


	return true;
}
Exemple #22
0
bool OgreRecast::NavMeshBuild(InputGeom* input)
{
    // TODO: clean up unused variables


   m_pLog->logMessage("NavMeshBuild Start");


   //
   // Step 1. Initialize build config.
   //

   // Reset build times gathering.
   m_ctx->resetTimers();

   // Start the build process.
   m_ctx->startTimer(RC_TIMER_TOTAL);






   //
   // Step 2. Rasterize input polygon soup.
   //

   InputGeom *inputGeom = input;
   rcVcopy(m_cfg.bmin, inputGeom->getMeshBoundsMin());
   rcVcopy(m_cfg.bmax, inputGeom->getMeshBoundsMax());
   rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height);

   int nverts = inputGeom->getVertCount();
   int ntris = inputGeom->getTriCount();
   Ogre::Vector3 min; FloatAToOgreVect3(inputGeom->getMeshBoundsMin(), min);
   Ogre::Vector3 max; FloatAToOgreVect3(inputGeom->getMeshBoundsMax(), max);

   //Ogre::LogManager::getSingletonPtr()->logMessage("Bounds: "+Ogre::StringConverter::toString(min) + "   "+ Ogre::StringConverter::toString(max));


   m_pLog->logMessage("Building navigation:");
   m_pLog->logMessage(" - " + Ogre::StringConverter::toString(m_cfg.width) + " x " + Ogre::StringConverter::toString(m_cfg.height) + " cells");
   m_pLog->logMessage(" - " + Ogre::StringConverter::toString(nverts/1000.0f) + " K verts, " + Ogre::StringConverter::toString(ntris/1000.0f) + " K tris");

   // Allocate voxel heightfield where we rasterize our input data to.
   m_solid = rcAllocHeightfield();
   if (!m_solid)
   {
      m_pLog->logMessage("ERROR: buildNavigation: Out of memory 'solid'.");
      return false;
   }
   if (!rcCreateHeightfield(m_ctx, *m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch))
   {
      m_pLog->logMessage("ERROR: buildNavigation: Could not create solid heightfield. Possibly it requires too much memory, try setting a higher cellSize and cellHeight value.");
      return false;
   }
   
   // Allocate array that can hold triangle area types.
   // If you have multiple meshes you need to process, allocate
   // an array which can hold the max number of triangles you need to process.
   m_triareas = new unsigned char[ntris];
   if (!m_triareas)
   {
       m_pLog->logMessage("ERROR: buildNavigation: Out of memory 'm_triareas' ("+Ogre::StringConverter::toString(ntris)+").");
      return false;
   }
   
   // Find triangles which are walkable based on their slope and rasterize them.
   // If your input data is multiple meshes, you can transform them here, calculate
   // the are type for each of the meshes and rasterize them.
   memset(m_triareas, 0, ntris*sizeof(unsigned char));
   rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, inputGeom->getVerts(), inputGeom->getVertCount(), inputGeom->getTris(), inputGeom->getTriCount(), m_triareas);
   rcRasterizeTriangles(m_ctx, inputGeom->getVerts(), inputGeom->getVertCount(), inputGeom->getTris(), m_triareas, inputGeom->getTriCount(), *m_solid, m_cfg.walkableClimb);

   if (!m_keepInterResults)
   {
      delete [] m_triareas;
      m_triareas = 0;
   }





   //
   // Step 3. Filter walkables surfaces.
   //
   
   // Once all geoemtry is rasterized, we do initial pass of filtering to
   // remove unwanted overhangs caused by the conservative rasterization
   // as well as filter spans where the character cannot possibly stand.
   rcFilterLowHangingWalkableObstacles(m_ctx, m_cfg.walkableClimb, *m_solid);
   rcFilterLedgeSpans(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid);
   rcFilterWalkableLowHeightSpans(m_ctx, m_cfg.walkableHeight, *m_solid);








   //
   // Step 4. Partition walkable surface to simple regions.
   //

   // Compact the heightfield so that it is faster to handle from now on.
   // This will result more cache coherent data as well as the neighbours
   // between walkable cells will be calculated.
   m_chf = rcAllocCompactHeightfield();
   if (!m_chf)
   {
      m_pLog->logMessage("ERROR: buildNavigation: Out of memory 'chf'.");
      return false;
   }
   if (!rcBuildCompactHeightfield(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid, *m_chf))
   {
      m_pLog->logMessage("ERROR: buildNavigation: Could not build compact data.");
      return false;
   }
   
   if (!m_keepInterResults)
   {
      rcFreeHeightField(m_solid);
      m_solid = 0;
   }


   // Erode the walkable area by agent radius.
   if (!rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, *m_chf))
   {
      m_pLog->logMessage("ERROR: buildNavigation: Could not erode walkable areas.");
      return false;
   }

// TODO implement
   // (Optional) Mark areas.
   //const ConvexVolume* vols = m_geom->getConvexVolumes();
   //for (int i  = 0; i < m_geom->getConvexVolumeCount(); ++i)
   //   rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned char)vols[i].area, *m_chf);


   // Prepare for region partitioning, by calculating distance field along the walkable surface.
   if (!rcBuildDistanceField(m_ctx, *m_chf))
   {
      m_pLog->logMessage("ERROR: buildNavigation: Could not build distance field.");
      return false;
   }

   // Partition the walkable surface into simple regions without holes.
   if (!rcBuildRegions(m_ctx, *m_chf, m_cfg.borderSize, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
   {
      m_pLog->logMessage("ERROR: buildNavigation: Could not build regions.");
      return false;
   }








   //
   // Step 5. Trace and simplify region contours.
   //
   
   // Create contours.
   m_cset = rcAllocContourSet();
   if (!m_cset)
   {
      m_pLog->logMessage("ERROR: buildNavigation: Out of memory 'cset'.");
      return false;
   }
   if (!rcBuildContours(m_ctx, *m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *m_cset))
   {
      m_pLog->logMessage("ERROR: buildNavigation: Could not create contours.");
      return false;
   }

   if (m_cset->nconts == 0)
   {
       // In case of errors see: http://groups.google.com/group/recastnavigation/browse_thread/thread/a6fbd509859a12c8
       // You should probably tweak the parameters
           m_pLog->logMessage("ERROR: No contours created (Recast)!");
    }





   //
   // Step 6. Build polygons mesh from contours.
   //
   
   // Build polygon navmesh from the contours.
   m_pmesh = rcAllocPolyMesh();
   if (!m_pmesh)
   {
      m_pLog->logMessage("ERROR: buildNavigation: Out of memory 'pmesh'.");
      return false;
   }
   if (!rcBuildPolyMesh(m_ctx, *m_cset, m_cfg.maxVertsPerPoly, *m_pmesh))
   {
       // Try modifying the parameters. I experienced this error when setting agentMaxClimb too high.
      m_pLog->logMessage("ERROR: buildNavigation: Could not triangulate contours.");
      return false;
   }
   








   //
   // Step 7. Create detail mesh which allows to access approximate height on each polygon.
   //
   
   m_dmesh = rcAllocPolyMeshDetail();
   if (!m_dmesh)
   {
      m_pLog->logMessage("ERROR: buildNavigation: Out of memory 'pmdtl'.");
      return false;
   }

   if (!rcBuildPolyMeshDetail(m_ctx, *m_pmesh, *m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, *m_dmesh))
   {
      m_pLog->logMessage("ERROR: buildNavigation: Could not build detail mesh.");
      return false;
   }

   if (!m_keepInterResults)
   {
      rcFreeCompactHeightfield(m_chf);
      m_chf = 0;
      rcFreeContourSet(m_cset);
      m_cset = 0;
   }

   // At this point the navigation mesh data is ready, you can access it from m_pmesh.
   // See duDebugDrawPolyMesh or dtCreateNavMeshData as examples how to access the data.
   







   //
   // (Optional) Step 8. Create Detour data from Recast poly mesh.
   //
   
   // The GUI may allow more max points per polygon than Detour can handle.
   // Only build the detour navmesh if we do not exceed the limit.


   if (m_cfg.maxVertsPerPoly <= DT_VERTS_PER_POLYGON)
   {
      m_pLog->logMessage("Detour 1000");

      unsigned char* navData = 0;
      int navDataSize = 0;

      
      // Update poly flags from areas.
      for (int i = 0; i < m_pmesh->npolys; ++i)
      {
         if (m_pmesh->areas[i] == RC_WALKABLE_AREA)
         {
            m_pmesh->areas[i] = SAMPLE_POLYAREA_GROUND;
            m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK;
         }
      }
      

      // Set navmesh params
      dtNavMeshCreateParams params;
      memset(&params, 0, sizeof(params));
      params.verts = m_pmesh->verts;
      params.vertCount = m_pmesh->nverts;
      params.polys = m_pmesh->polys;
      params.polyAreas = m_pmesh->areas;
      params.polyFlags = m_pmesh->flags;
      params.polyCount = m_pmesh->npolys;
      params.nvp = m_pmesh->nvp;
      params.detailMeshes = m_dmesh->meshes;
      params.detailVerts = m_dmesh->verts;
      params.detailVertsCount = m_dmesh->nverts;
      params.detailTris = m_dmesh->tris;
      params.detailTriCount = m_dmesh->ntris;

      // no off mesh connections yet
      m_offMeshConCount=0 ;
      params.offMeshConVerts = m_offMeshConVerts ;
      params.offMeshConRad = m_offMeshConRads ;
      params.offMeshConDir = m_offMeshConDirs ;
      params.offMeshConAreas = m_offMeshConAreas ;
      params.offMeshConFlags = m_offMeshConFlags ;
      params.offMeshConUserID = m_offMeshConId ;
      params.offMeshConCount = m_offMeshConCount ;

      params.walkableHeight = m_agentHeight;
      params.walkableRadius = m_agentRadius;
      params.walkableClimb = m_agentMaxClimb;
      rcVcopy(params.bmin, m_pmesh->bmin);
      rcVcopy(params.bmax, m_pmesh->bmax);
      params.cs = m_cfg.cs;
      params.ch = m_cfg.ch;

      
      m_pLog->logMessage("Detour 2000");

      if (!dtCreateNavMeshData(&params, &navData, &navDataSize))
      {
         m_pLog->logMessage("ERROR: Could not build Detour navmesh.");
         return false;
      }

      m_pLog->logMessage("Detour 3000");
      
      m_navMesh = dtAllocNavMesh();
      if (!m_navMesh)
      {
         dtFree(navData);
         m_pLog->logMessage("ERROR: Could not create Detour navmesh");
         return false;
      }

      m_pLog->logMessage("Detour 4000");
      
      dtStatus status;
      
      status = m_navMesh->init(navData, navDataSize, DT_TILE_FREE_DATA);
      if (dtStatusFailed(status))
      {
         dtFree(navData);
         m_pLog->logMessage("ERROR: Could not init Detour navmesh");
         return false;
      }

      m_pLog->logMessage("Detour 5000");
      
      m_navQuery = dtAllocNavMeshQuery();
      status = m_navQuery->init(m_navMesh, 2048);

      m_pLog->logMessage("Detour 5500");

      if (dtStatusFailed(status))
      {
         m_pLog->logMessage("ERROR: Could not init Detour navmesh query");
         return false;
      }

      m_pLog->logMessage("Detour 6000");
   }
   
   m_ctx->stopTimer(RC_TIMER_TOTAL);

   
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


   // cleanup stuff we don't need
//   delete [] rc_verts ;
//   delete [] rc_tris ;
//   delete [] rc_trinorms ;

   //CreateRecastPolyMesh(*m_pmesh) ;   // Debug render it

   m_pLog->logMessage("NavMeshBuild End");
   return true;
}
Exemple #23
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CRecastMesh::Build( CMapMesh *pMapMesh )
{
	double fStartTime = Plat_FloatTime();

	Reset(); // Clean any existing data

	BuildContext ctx;

	ctx.enableLog( true );

	dtStatus status;
	
	V_memset(&m_cfg, 0, sizeof(m_cfg));

	// Init cache
	rcCalcBounds( pMapMesh->GetVerts(), pMapMesh->GetNumVerts(), m_cfg.bmin, m_cfg.bmax );
	rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height);
	int gw = 0, gh = 0;
	rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cellSize, &gw, &gh);
	const int ts = (int)m_tileSize;
	const int tw = (gw + ts-1) / ts;
	const int th = (gh + ts-1) / ts;

	// Max tiles and max polys affect how the tile IDs are caculated.
	// There are 22 bits available for identifying a tile and a polygon.
	int tileBits = rcMin((int)dtIlog2(dtNextPow2(tw*th*EXPECTED_LAYERS_PER_TILE)), 14);
	if (tileBits > 14) tileBits = 14;
	int polyBits = 22 - tileBits;
	m_maxTiles = 1 << tileBits;
	m_maxPolysPerTile = 1 << polyBits;

	// Generation params.
	m_cfg.cs = m_cellSize;
	m_cfg.ch = m_cellHeight;
	m_cfg.walkableSlopeAngle = m_agentMaxSlope;
	m_cfg.walkableHeight = (int)ceilf(m_agentHeight / m_cfg.ch);
	m_cfg.walkableClimb = (int)floorf(m_agentMaxClimb / m_cfg.ch);
	m_cfg.walkableRadius = (int)ceilf(m_agentRadius / m_cfg.cs);
	m_cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize);
	m_cfg.maxSimplificationError = m_edgeMaxError;
	m_cfg.minRegionArea = (int)rcSqr(m_regionMinSize);		// Note: area = size*size
	m_cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize);	// Note: area = size*size
	m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly;
	m_cfg.tileSize = (int)m_tileSize;
	m_cfg.borderSize = m_cfg.walkableRadius + 3; // Reserve enough padding.
	m_cfg.width = m_cfg.tileSize + m_cfg.borderSize*2;
	m_cfg.height = m_cfg.tileSize + m_cfg.borderSize*2;
	m_cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist;
	m_cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError;
	
	// Tile cache params.
	dtTileCacheParams tcparams;
	memset(&tcparams, 0, sizeof(tcparams));
	rcVcopy(tcparams.orig, m_cfg.bmin);
	tcparams.cs = m_cellSize;
	tcparams.ch = m_cellHeight;
	tcparams.width = (int)m_tileSize;
	tcparams.height = (int)m_tileSize;
	tcparams.walkableHeight = m_agentHeight;
	tcparams.walkableRadius = m_agentRadius;
	tcparams.walkableClimb = m_agentMaxClimb;
	tcparams.maxSimplificationError = m_edgeMaxError;
	tcparams.maxTiles = tw*th*EXPECTED_LAYERS_PER_TILE;
	tcparams.maxObstacles = 2048;

	dtFreeTileCache(m_tileCache);

	m_tileCache = dtAllocTileCache();
	if (!m_tileCache)
	{
		ctx.log(RC_LOG_ERROR, "buildTiledNavigation: Could not allocate tile cache.");
		return false;
	}
	status = m_tileCache->init(&tcparams, m_talloc, m_tcomp, m_tmproc);
	if (dtStatusFailed(status))
	{
		ctx.log(RC_LOG_ERROR, "buildTiledNavigation: Could not init tile cache.");
		return false;
	}
	
	dtFreeNavMesh(m_navMesh);
	
	m_navMesh = dtAllocNavMesh();
	if (!m_navMesh)
	{
		ctx.log(RC_LOG_ERROR, "buildTiledNavigation: Could not allocate navmesh.");
		return false;
	}

	dtNavMeshParams params;
	memset(&params, 0, sizeof(params));
	rcVcopy(params.orig, m_cfg.bmin);
	params.tileWidth = m_tileSize*m_cellSize;
	params.tileHeight = m_tileSize*m_cellSize;
	params.maxTiles = m_maxTiles;
	params.maxPolys = m_maxPolysPerTile;
	
	status = m_navMesh->init(&params);
	if (dtStatusFailed(status))
	{
		ctx.log(RC_LOG_ERROR, "buildTiledNavigation: Could not init navmesh.");
		return false;
	}
	
	status = m_navQuery->init( m_navMesh, RECAST_NAVQUERY_MAXNODES );
	if (dtStatusFailed(status))
	{
		ctx.log(RC_LOG_ERROR, "buildTiledNavigation: Could not init Detour navmesh query");
		return false;
	}
	

	// Preprocess tiles.
	
	ctx.resetTimers();
	
	m_cacheLayerCount = 0;
	m_cacheCompressedSize = 0;
	m_cacheRawSize = 0;
	
	for (int y = 0; y < th; ++y)
	{
		for (int x = 0; x < tw; ++x)
		{
			TileCacheData tiles[MAX_LAYERS];
			memset(tiles, 0, sizeof(tiles));
			int ntiles = rasterizeTileLayers(&ctx, pMapMesh, x, y, m_cfg, tiles, MAX_LAYERS);

			for (int i = 0; i < ntiles; ++i)
			{
				TileCacheData* tile = &tiles[i];
				status = m_tileCache->addTile(tile->data, tile->dataSize, DT_COMPRESSEDTILE_FREE_DATA, 0);
				if (dtStatusFailed(status))
				{
					dtFree(tile->data);
					tile->data = 0;
					continue;
				}
				
				m_cacheLayerCount++;
				m_cacheCompressedSize += tile->dataSize;
				m_cacheRawSize += calcLayerBufferSize(tcparams.width, tcparams.height);
			}
		}
	}

	// Build initial meshes
	ctx.startTimer(RC_TIMER_TOTAL);
	for (int y = 0; y < th; ++y)
		for (int x = 0; x < tw; ++x)
			m_tileCache->buildNavMeshTilesAt(x,y, m_navMesh);
	ctx.stopTimer(RC_TIMER_TOTAL);
	
	m_cacheBuildTimeMs = ctx.getAccumulatedTime(RC_TIMER_TOTAL)/1000.0f;
	m_cacheBuildMemUsage = ((LinearAllocator *)m_talloc)->high;
	

	const dtNavMesh* nav = m_navMesh;
	int navmeshMemUsage = 0;
	for (int i = 0; i < nav->getMaxTiles(); ++i)
	{
		const dtMeshTile* tile = nav->getTile(i);
		if (tile->header)
			navmeshMemUsage += tile->dataSize;
	}

	DevMsg( "CRecastMesh: Generated navigation mesh %s in %f seconds\n", m_Name.Get(), Plat_FloatTime() - fStartTime );

	return true;
}
bool NavigationMesh::Build()
{
    PROFILE(BuildNavigationMesh);
    
    // Release existing navigation data and zero the bounding box
    ReleaseNavigationMesh();
    
    if (!node_)
        return false;
    
    if (!node_->GetWorldScale().Equals(Vector3::ONE))
        LOGWARNING("Navigation mesh root node has scaling. Agent parameters may not work as intended");
    
    Vector<NavigationGeometryInfo> geometryList;
    CollectGeometries(geometryList);
    
    if (geometryList.Empty())
        return true; // Nothing to do
    
    // Build the combined bounding box
    for (unsigned i = 0; i < geometryList.Size(); ++i)
        boundingBox_.Merge(geometryList[i].boundingBox_);
    
    // Expand bounding box by padding
    boundingBox_.min_ -= padding_;
    boundingBox_.max_ += padding_;
    
    {
        PROFILE(BuildNavigationMesh);
        
        // Calculate number of tiles
        int gridW = 0, gridH = 0;
        float tileEdgeLength = (float)tileSize_ * cellSize_;
        rcCalcGridSize(&boundingBox_.min_.x_, &boundingBox_.max_.x_, cellSize_, &gridW, &gridH);
        numTilesX_ = (gridW + tileSize_ - 1) / tileSize_;
        numTilesZ_ = (gridH + tileSize_ - 1) / tileSize_;
        
        // Calculate max. number of tiles and polygons, 22 bits available to identify both tile & polygon within tile
        unsigned maxTiles = NextPowerOfTwo(numTilesX_ * numTilesZ_);
        unsigned tileBits = 0;
        unsigned temp = maxTiles;
        while (temp > 1)
        {
            temp >>= 1;
            ++tileBits;
        }
        
        unsigned maxPolys = 1 << (22 - tileBits);
        
        dtNavMeshParams params;
        rcVcopy(params.orig, &boundingBox_.min_.x_);
        params.tileWidth = tileEdgeLength;
        params.tileHeight = tileEdgeLength;
        params.maxTiles = maxTiles;
        params.maxPolys = maxPolys;
        
        navMesh_ = dtAllocNavMesh();
        if (!navMesh_)
        {
            LOGERROR("Could not allocate navigation mesh");
            return false;
        }
        
        if (dtStatusFailed(navMesh_->init(&params)))
        {
            LOGERROR("Could not initialize navigation mesh");
            ReleaseNavigationMesh();
            return false;
        }
        
        // Build each tile
        unsigned numTiles = 0;
        
        for (int z = 0; z < numTilesZ_; ++z)
        {
            for (int x = 0; x < numTilesX_; ++x)
            {
                if (BuildTile(geometryList, x, z))
                    ++numTiles;
            }
        }
        
        LOGDEBUG("Built navigation mesh with " + String(numTiles) + " tiles");
        return true;
    }
}
Exemple #25
0
bool CNavMesh::load(char* path)
{
  this->path = path;
  this->unload();

  m_navMesh = new dtNavMesh();

  FILE* fp = fopen(path, "rb");

  if (!fp)
  {
    ShowError("CNavMesh::load Error loading navmesh (%s)\n", path);
    return false;
  }

  // Read header.
  NavMeshSetHeader header;
  fread(&header, sizeof(NavMeshSetHeader), 1, fp);
  if (header.magic != NAVMESHSET_MAGIC)
  {
    fclose(fp);
    return false;
  }
  if (header.version != NAVMESHSET_VERSION)
  {
    fclose(fp);
    return false;
  }

  m_navMesh = dtAllocNavMesh();
  if (!m_navMesh)
  {
    fclose(fp);
    return false;
  }

  dtStatus status = m_navMesh->init(&header.params);
  if (dtStatusFailed(status))
  {
    ShowError("CNavMesh::load Could not initialize detour for (%s)", path);
    outputError(status);
	fclose(fp);
    return false;
  }

  // Read tiles.
  for (int i = 0; i < header.numTiles; ++i)
  {
    NavMeshTileHeader tileHeader;
    fread(&tileHeader, sizeof(tileHeader), 1, fp);
    if (!tileHeader.tileRef || !tileHeader.dataSize)
            break;

    unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
    if (!data) break;
    memset(data, 0, tileHeader.dataSize);
    fread(data, tileHeader.dataSize, 1, fp);

    m_navMesh->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0);

  }

  fclose(fp);

  m_navMeshQuery = new dtNavMeshQuery();

  // init detour nav mesh path finder
  status = m_navMeshQuery->init(m_navMesh, MAX_NAV_POLYS);

  if(dtStatusFailed(status))
  {
    ShowError("CNavMesh::load Error loading navmeshquery (%s)\n", path);
    outputError(status);
    return false;
  }

  return true;
}
Exemple #26
0
bool NavMesh::loadNavMeshFile()
{
    auto data = FileUtils::getInstance()->getDataFromFile(_navFilePath);
    if (data.isNull()) return false;

    // Read header.
    unsigned int offset = 0;
    TileCacheSetHeader header = *((TileCacheSetHeader*)(data.getBytes() + offset));
    offset += sizeof(TileCacheSetHeader);
    if (header.magic != TILECACHESET_MAGIC)
    {
        return false;
    }
    if (header.version != TILECACHESET_VERSION)
    {
        return false;
    }

    _navMesh = dtAllocNavMesh();
    if (!_navMesh)
    {
        return false;
    }
    dtStatus status = _navMesh->init(&header.meshParams);
    if (dtStatusFailed(status))
    {
        return false;
    }

    _tileCache = dtAllocTileCache();
    if (!_tileCache)
    {
        return false;
    }

    _allocator = new LinearAllocator(32000);
    _compressor = new FastLZCompressor;
    _meshProcess = new MeshProcess(_geomData);
    status = _tileCache->init(&header.cacheParams, _allocator, _compressor, _meshProcess);

    if (dtStatusFailed(status))
    {
        return false;
    }

    // Read tiles.
    for (int i = 0; i < header.numTiles; ++i)
    {
        TileCacheTileHeader tileHeader = *((TileCacheTileHeader*)(data.getBytes() + offset));
        offset += sizeof(TileCacheTileHeader);
        if (!tileHeader.tileRef || !tileHeader.dataSize)
            break;

        unsigned char* tileData = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
        if (!tileData) break;
        memcpy(tileData, (data.getBytes() + offset), tileHeader.dataSize);
        offset += tileHeader.dataSize;

        dtCompressedTileRef tile = 0;
        _tileCache->addTile(tileData, tileHeader.dataSize, DT_COMPRESSEDTILE_FREE_DATA, &tile);

        if (tile)
            _tileCache->buildNavMeshTile(tile, _navMesh);
    }

    //create crowed
    _crowed = dtAllocCrowd();
    _crowed->init(MAX_AGENTS, header.cacheParams.walkableRadius, _navMesh);

    //create NavMeshQuery
    _navMeshQuery = dtAllocNavMeshQuery();
    _navMeshQuery->init(_navMesh, 2048);

    _agentList.assign(MAX_AGENTS, nullptr);
    _obstacleList.assign(header.cacheParams.maxObstacles, nullptr);
    //duDebugDrawNavMesh(&_debugDraw, *_navMesh, DU_DRAWNAVMESH_OFFMESHCONS);
    return true;
}
    void MapBuilder::buildNavMesh(uint32 mapID, dtNavMesh* &navMesh)
    {
        std::set<uint32>* tiles = getTileList(mapID);

        // old code for non-statically assigned bitmask sizes:
        ///*** calculate number of bits needed to store tiles & polys ***/
        //int tileBits = dtIlog2(dtNextPow2(tiles->size()));
        //if (tileBits < 1) tileBits = 1;                                     // need at least one bit!
        //int polyBits = sizeof(dtPolyRef)*8 - SALT_MIN_BITS - tileBits;

        int polyBits = STATIC_POLY_BITS;

        int maxTiles = tiles->size();
        int maxPolysPerTile = 1 << polyBits;

        /***          calculate bounds of map         ***/

        uint32 tileXMin = 64, tileYMin = 64, tileXMax = 0, tileYMax = 0, tileX, tileY;
        for (std::set<uint32>::iterator it = tiles->begin(); it != tiles->end(); ++it)
        {
            StaticMapTree::unpackTileID(*it, tileX, tileY);

            if (tileX > tileXMax)
                tileXMax = tileX;
            else if (tileX < tileXMin)
                tileXMin = tileX;

            if (tileY > tileYMax)
                tileYMax = tileY;
            else if (tileY < tileYMin)
                tileYMin = tileY;
        }

        // use Max because '32 - tileX' is negative for values over 32
        float bmin[3], bmax[3];
        getTileBounds(tileXMax, tileYMax, NULL, 0, bmin, bmax);

        /***       now create the navmesh       ***/

        // navmesh creation params
        dtNavMeshParams navMeshParams;
        memset(&navMeshParams, 0, sizeof(dtNavMeshParams));
        navMeshParams.tileWidth = GRID_SIZE;
        navMeshParams.tileHeight = GRID_SIZE;
        rcVcopy(navMeshParams.orig, bmin);
        navMeshParams.maxTiles = maxTiles;
        navMeshParams.maxPolys = maxPolysPerTile;

        navMesh = dtAllocNavMesh();
        printf("[Map %04u] Creating navMesh...\n", mapID);
        if (!navMesh->init(&navMeshParams))
        {
            printf("[Map %04u] Failed creating navmesh!                \n", mapID);
            return;
        }

        char fileName[25];
        sprintf(fileName, "mmaps/%04u.mmap", mapID);

        FILE* file = fopen(fileName, "wb");
        if (!file)
        {
            dtFreeNavMesh(navMesh);
            char message[1024];
            sprintf(message, "[Map %04u] Failed to open %s for writing!\n", mapID, fileName);
            perror(message);
            return;
        }

        // now that we know navMesh params are valid, we can write them to file
        fwrite(&navMeshParams, sizeof(dtNavMeshParams), 1, file);
        fclose(file);
    }
Exemple #28
0
//-------------------------------------------------------------------------------------
NavMeshHandle* NavMeshEx::loadNavmesh(std::string name)
{
	if(name == "")
		return NULL;

	KBEngine::thread::ThreadGuard tg(&mutex_); 
	std::string path = Resmgr::getSingleton().matchRes("spaces/" + name + "/" + name + ".navmesh_srv");

	if(navmeshs_.find(name) != navmeshs_.end())
	{
		return NULL;
	}

	FILE* fp = fopen(path.c_str(), "rb");
	if (!fp)
	{
		ERROR_MSG(boost::format("NavMeshEx::loadNavmesh: open(%1%) is error!\n") % path);
		return NULL;
	}

	bool safeStorage = true;
    int pos = 0;
    int size = sizeof(NavMeshSetHeader);
	
	fseek(fp, 0, SEEK_END); 
	size_t flen = ftell(fp); 
	fseek(fp, 0, SEEK_SET); 

	uint8* data = new uint8[flen];
	if(data == NULL)
	{
		ERROR_MSG(boost::format("NavMeshEx::loadNavmesh: open(%1%), memory(size=%2%) error!\n") % path % flen);
		fclose(fp);
		SAFE_RELEASE_ARRAY(data);
		return NULL;
	}

	size_t readsize = fread(data, 1, flen, fp);
	if(readsize != flen)
	{
		ERROR_MSG(boost::format("NavMeshEx::loadNavmesh: open(%1%), read(size=%2% != %3%) error!\n") % path % readsize % flen);
		fclose(fp);
		SAFE_RELEASE_ARRAY(data);
		return NULL;
	}

    if (readsize < sizeof(NavMeshSetHeader))
	{
		ERROR_MSG(boost::format("NavMeshEx::loadNavmesh: open(%1%), NavMeshSetHeader is error!\n") % path);
		fclose(fp);
		SAFE_RELEASE_ARRAY(data);
		return NULL;
	}

    NavMeshSetHeader header;
	memcpy(&header, data, size);

    pos += size;

    if (header.version != RCN_NAVMESH_VERSION)
    {
		ERROR_MSG(boost::format("NavMeshEx::loadNavmesh: version(%1%) is not match(%2%)!\n") % header.version % RCN_NAVMESH_VERSION);
		fclose(fp);
		SAFE_RELEASE_ARRAY(data);
        return NULL;
    }

    dtNavMesh* mesh = dtAllocNavMesh();
    if (!mesh)
    {
		ERROR_MSG("NavMeshEx::loadNavmesh: dtAllocNavMesh is failed!\n");
		fclose(fp);
		SAFE_RELEASE_ARRAY(data);
        return NULL;
    }

    dtStatus status = mesh->init(&header.params);
    if (dtStatusFailed(status))
    {
		ERROR_MSG(boost::format("NavMeshEx::loadNavmesh: mesh init is error(%1%)!\n") % status);
		fclose(fp);
		SAFE_RELEASE_ARRAY(data);
	    return NULL;
    }

    // Read tiles.
    bool success = true;
    for (int i = 0; i < header.tileCount; ++i)
    {
	    NavMeshTileHeader tileHeader;
        size = sizeof(NavMeshTileHeader);
	    memcpy(&tileHeader, &data[pos], size);
        pos += size;

        size = tileHeader.dataSize;
		if (!tileHeader.tileRef || !tileHeader.dataSize)
        {
            success = false;
            status = DT_FAILURE + DT_INVALID_PARAM;
		    break;
        }
		
	    unsigned char* tileData = 
            (unsigned char*)dtAlloc(size, DT_ALLOC_PERM);
	    if (!tileData)
        {
            success = false;
            status = DT_FAILURE + DT_OUT_OF_MEMORY;
            break;
        }
        memcpy(tileData, &data[pos], size);
        pos += size;

	    status = mesh->addTile(tileData
            , size
			, (safeStorage ? DT_TILE_FREE_DATA : 0)
            , tileHeader.tileRef
            , 0);

        if (dtStatusFailed(status))
        {
            success = false;
            break;
        }
    }

	fclose(fp);
	SAFE_RELEASE_ARRAY(data);

    if (!success)
    {
		ERROR_MSG(boost::format("NavMeshEx::loadNavmesh:  error(%1%)!\n") % status);
        dtFreeNavMesh(mesh);
		return NULL;
    }

	NavMeshHandle* pNavMeshHandle = new NavMeshHandle();
	pNavMeshHandle->navmesh = mesh;
	pNavMeshHandle->navmeshQuery = new dtNavMeshQuery();
	pNavMeshHandle->navmeshQuery->init(mesh, 1024);
	pNavMeshHandle->name = name;
	navmeshs_[name] = pNavMeshHandle;

    uint32 tileCount = 0;
    uint32 nodeCount = 0;
    uint32 polyCount = 0;
    uint32 vertCount = 0;
    uint32 triCount = 0;
    uint32 triVertCount = 0;
    uint32 dataSize = 0;

	const dtNavMesh* navmesh = mesh;
    for (int32 i = 0; i < navmesh->getMaxTiles(); ++i)
    {
        const dtMeshTile* tile = navmesh->getTile(i);
        if (!tile || !tile->header)
            continue;

        tileCount ++;
        nodeCount += tile->header->bvNodeCount;
        polyCount += tile->header->polyCount;
        vertCount += tile->header->vertCount;
        triCount += tile->header->detailTriCount;
        triVertCount += tile->header->detailVertCount;
        dataSize += tile->dataSize;

		// DEBUG_MSG(boost::format("NavMeshEx::loadNavmesh: verts(%1%, %2%, %3%)\n") % tile->verts[0] % tile->verts[1] % tile->verts[2]);
    }

	DEBUG_MSG(boost::format("NavMeshEx::loadNavmesh: (%1%)\n") % name);
	DEBUG_MSG(boost::format("\t==> tiles loaded: %1%\n") % tileCount);
	DEBUG_MSG(boost::format("\t==> BVTree nodes: %1%\n") % nodeCount);
    DEBUG_MSG(boost::format("\t==> %1% polygons (%2% vertices)\n") % polyCount % vertCount);
    DEBUG_MSG(boost::format("\t==> %1% triangles (%2% vertices)\n") % triCount % triVertCount);
    DEBUG_MSG(boost::format("\t==> %.2f MB of data (not including pointers)\n") % (((float)dataSize / sizeof(unsigned char)) / 1048576));
	return pNavMeshHandle;
}
    void MapBuilder::buildNavMesh(int mapID, dtNavMesh*& navMesh, dtNavMeshParams*& navMeshParams)
    {
        bool isFirstNavMesh = navMeshParams ? false : true;

        if (isFirstNavMesh)
        {
            set<uint32>* tiles = getTileList(mapID);
            int polyBits = DT_POLY_BITS;
            int maxTiles = tiles->size();
            int maxPolysPerTile = 1 << polyBits;

            /***          calculate bounds of map         ***/
            uint32 tileXMin = 64, tileYMin = 64, tileXMax = 0, tileYMax = 0, tileX, tileY;
            for (set<uint32>::iterator it = tiles->begin(); it != tiles->end(); ++it)
            {
                StaticMapTree::unpackTileID((*it), tileX, tileY);

                if (tileX > tileXMax)
                    { tileXMax = tileX; }
                else if (tileX < tileXMin)
                    { tileXMin = tileX; }

                if (tileY > tileYMax)
                    { tileYMax = tileY; }
                else if (tileY < tileYMin)
                    { tileYMin = tileY; }
            }

            // use Max because '32 - tileX' is negative for values over 32
            float bmin[3], bmax[3];
            getTileBounds(tileXMax, tileYMax, NULL, 0, bmin, bmax);

            /***       now create the navmesh       ***/
            // navmesh creation params
            navMeshParams = new dtNavMeshParams();
            memset(navMeshParams, 0, sizeof(dtNavMeshParams));
            navMeshParams->tileWidth = GRID_SIZE;
            navMeshParams->tileHeight = GRID_SIZE;
            rcVcopy(navMeshParams->orig, bmin);
            navMeshParams->maxTiles = maxTiles;
            navMeshParams->maxPolys = maxPolysPerTile;
        }

        navMesh = dtAllocNavMesh();
        if (!navMesh->init(navMeshParams))
        {
            printf("Failed creating navmesh!                \n");
            return;
        }

        if (isFirstNavMesh)
        {
            char fileName[25];
            sprintf(fileName, "mmaps/%03u.mmap", mapID);

            FILE* file = fopen(fileName, "wb");
            if (!file)
            {
                dtFreeNavMesh(navMesh);
                char message[1024];
                sprintf(message, "Failed to open %s for writing!\n", fileName);
                perror(message);
                return;
            }
            // now that we know navMesh params are valid, we can write them to file
            fwrite(navMeshParams, sizeof(dtNavMeshParams), 1, file);
            fclose(file);
        }
    }
bool Sample_SoloMesh::handleBuild()
{
	if (!m_geom || !m_geom->getMesh())
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Input mesh is not specified.");
		return false;
	}
	
	cleanup();
	
	const float* bmin = m_geom->getMeshBoundsMin();
	const float* bmax = m_geom->getMeshBoundsMax();
	const float* verts = m_geom->getMesh()->getVerts();
	const int nverts = m_geom->getMesh()->getVertCount();
	const int* tris = m_geom->getMesh()->getTris();
	const int ntris = m_geom->getMesh()->getTriCount();
	
	//
	// Step 1. Initialize build config.
	//
	
	// Init build configuration from GUI
	memset(&m_cfg, 0, sizeof(m_cfg));
	m_cfg.cs = m_cellSize;
	m_cfg.ch = m_cellHeight;
	m_cfg.walkableSlopeAngle = m_agentMaxSlope;
	m_cfg.walkableHeight = (int)ceilf(m_agentHeight / m_cfg.ch);
	m_cfg.walkableClimb = (int)floorf(m_agentMaxClimb / m_cfg.ch);
	m_cfg.walkableRadius = (int)ceilf(m_agentRadius / m_cfg.cs);
	m_cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize);
	m_cfg.maxSimplificationError = m_edgeMaxError;
	m_cfg.minRegionArea = (int)rcSqr(m_regionMinSize);		// Note: area = size*size
	m_cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize);	// Note: area = size*size
	m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly;
	m_cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist;
	m_cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError;
	
	// Set the area where the navigation will be build.
	// Here the bounds of the input mesh are used, but the
	// area could be specified by an user defined box, etc.
	rcVcopy(m_cfg.bmin, bmin);
	rcVcopy(m_cfg.bmax, bmax);
	rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height);

	// Reset build times gathering.
	m_ctx->resetTimers();

	// Start the build process.	
	m_ctx->startTimer(RC_TIMER_TOTAL);
	
	m_ctx->log(RC_LOG_PROGRESS, "Building navigation:");
	m_ctx->log(RC_LOG_PROGRESS, " - %d x %d cells", m_cfg.width, m_cfg.height);
	m_ctx->log(RC_LOG_PROGRESS, " - %.1fK verts, %.1fK tris", nverts/1000.0f, ntris/1000.0f);
	
	//
	// Step 2. Rasterize input polygon soup.
	//
	
	// Allocate voxel heightfield where we rasterize our input data to.
	m_solid = rcAllocHeightfield();
	if (!m_solid)
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'.");
		return false;
	}
	if (!rcCreateHeightfield(m_ctx, *m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch))
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not create solid heightfield.");
		return false;
	}
	
	// Allocate array that can hold triangle area types.
	// If you have multiple meshes you need to process, allocate
	// and array which can hold the max number of triangles you need to process.
	m_triareas = new unsigned char[ntris];
	if (!m_triareas)
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'm_triareas' (%d).", ntris);
		return false;
	}
	
	// Find triangles which are walkable based on their slope and rasterize them.
	// If your input data is multiple meshes, you can transform them here, calculate
	// the are type for each of the meshes and rasterize them.
	memset(m_triareas, 0, ntris*sizeof(unsigned char));
	rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, m_triareas);
	rcRasterizeTriangles(m_ctx, verts, nverts, tris, m_triareas, ntris, *m_solid, m_cfg.walkableClimb);

	if (!m_keepInterResults)
	{
		delete [] m_triareas;
		m_triareas = 0;
	}
	
	//
	// Step 3. Filter walkables surfaces.
	//
	
	// Once all geoemtry is rasterized, we do initial pass of filtering to
	// remove unwanted overhangs caused by the conservative rasterization
	// as well as filter spans where the character cannot possibly stand.
	rcFilterLowHangingWalkableObstacles(m_ctx, m_cfg.walkableClimb, *m_solid);
	rcFilterLedgeSpans(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid);
	rcFilterWalkableLowHeightSpans(m_ctx, m_cfg.walkableHeight, *m_solid);


	//
	// Step 4. Partition walkable surface to simple regions.
	//

	// Compact the heightfield so that it is faster to handle from now on.
	// This will result more cache coherent data as well as the neighbours
	// between walkable cells will be calculated.
	m_chf = rcAllocCompactHeightfield();
	if (!m_chf)
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'.");
		return false;
	}
	if (!rcBuildCompactHeightfield(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid, *m_chf))
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build compact data.");
		return false;
	}
	
	if (!m_keepInterResults)
	{
		rcFreeHeightField(m_solid);
		m_solid = 0;
	}
		
	// Erode the walkable area by agent radius.
	if (!rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, *m_chf))
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not erode.");
		return false;
	}

	// (Optional) Mark areas.
	const ConvexVolume* vols = m_geom->getConvexVolumes();
	for (int i  = 0; i < m_geom->getConvexVolumeCount(); ++i)
		rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned char)vols[i].area, *m_chf);

	
	// Partition the heightfield so that we can use simple algorithm later to triangulate the walkable areas.
	// There are 3 martitioning methods, each with some pros and cons:
	// 1) Watershed partitioning
	//   - the classic Recast partitioning
	//   - creates the nicest tessellation
	//   - usually slowest
	//   - partitions the heightfield into nice regions without holes or overlaps
	//   - the are some corner cases where this method creates produces holes and overlaps
	//      - holes may appear when a small obstacles is close to large open area (triangulation can handle this)
	//      - overlaps may occur if you have narrow spiral corridors (i.e stairs), this make triangulation to fail
	//   * generally the best choice if you precompute the nacmesh, use this if you have large open areas
	// 2) Monotone partioning
	//   - fastest
	//   - partitions the heightfield into regions without holes and overlaps (guaranteed)
	//   - creates long thin polygons, which sometimes causes paths with detours
	//   * use this if you want fast navmesh generation
	// 3) Layer partitoining
	//   - quite fast
	//   - partitions the heighfield into non-overlapping regions
	//   - relies on the triangulation code to cope with holes (thus slower than monotone partitioning)
	//   - produces better triangles than monotone partitioning
	//   - does not have the corner cases of watershed partitioning
	//   - can be slow and create a bit ugly tessellation (still better than monotone)
	//     if you have large open areas with small obstacles (not a problem if you use tiles)
	//   * good choice to use for tiled navmesh with medium and small sized tiles
	
	if (m_partitionType == SAMPLE_PARTITION_WATERSHED)
	{
		// Prepare for region partitioning, by calculating distance field along the walkable surface.
		if (!rcBuildDistanceField(m_ctx, *m_chf))
		{
			m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build distance field.");
			return false;
		}
		
		// Partition the walkable surface into simple regions without holes.
		if (!rcBuildRegions(m_ctx, *m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
		{
			m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build watershed regions.");
			return false;
		}
	}
	else if (m_partitionType == SAMPLE_PARTITION_MONOTONE)
	{
		// Partition the walkable surface into simple regions without holes.
		// Monotone partitioning does not need distancefield.
		if (!rcBuildRegionsMonotone(m_ctx, *m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
		{
			m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build monotone regions.");
			return false;
		}
	}
	else // SAMPLE_PARTITION_LAYERS
	{
		// Partition the walkable surface into simple regions without holes.
		if (!rcBuildLayerRegions(m_ctx, *m_chf, 0, m_cfg.minRegionArea))
		{
			m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build layer regions.");
			return false;
		}
	}
	
	//
	// Step 5. Trace and simplify region contours.
	//
	
	// Create contours.
	m_cset = rcAllocContourSet();
	if (!m_cset)
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'.");
		return false;
	}
	if (!rcBuildContours(m_ctx, *m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *m_cset))
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not create contours.");
		return false;
	}
	
	//
	// Step 6. Build polygons mesh from contours.
	//
	
	// Build polygon navmesh from the contours.
	m_pmesh = rcAllocPolyMesh();
	if (!m_pmesh)
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmesh'.");
		return false;
	}
	if (!rcBuildPolyMesh(m_ctx, *m_cset, m_cfg.maxVertsPerPoly, *m_pmesh))
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not triangulate contours.");
		return false;
	}
	
	//
	// Step 7. Create detail mesh which allows to access approximate height on each polygon.
	//
	
	m_dmesh = rcAllocPolyMeshDetail();
	if (!m_dmesh)
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmdtl'.");
		return false;
	}

	if (!rcBuildPolyMeshDetail(m_ctx, *m_pmesh, *m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, *m_dmesh))
	{
		m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build detail mesh.");
		return false;
	}

	if (!m_keepInterResults)
	{
		rcFreeCompactHeightfield(m_chf);
		m_chf = 0;
		rcFreeContourSet(m_cset);
		m_cset = 0;
	}

	// At this point the navigation mesh data is ready, you can access it from m_pmesh.
	// See duDebugDrawPolyMesh or dtCreateNavMeshData as examples how to access the data.
	
	//
	// (Optional) Step 8. Create Detour data from Recast poly mesh.
	//
	
	// The GUI may allow more max points per polygon than Detour can handle.
	// Only build the detour navmesh if we do not exceed the limit.
	if (m_cfg.maxVertsPerPoly <= DT_VERTS_PER_POLYGON)
	{
		unsigned char* navData = 0;
		int navDataSize = 0;

		// Update poly flags from areas.
		for (int i = 0; i < m_pmesh->npolys; ++i)
		{
			if (m_pmesh->areas[i] == RC_WALKABLE_AREA)
				m_pmesh->areas[i] = SAMPLE_POLYAREA_GROUND;
				
			if (m_pmesh->areas[i] == SAMPLE_POLYAREA_GROUND ||
				m_pmesh->areas[i] == SAMPLE_POLYAREA_GRASS ||
				m_pmesh->areas[i] == SAMPLE_POLYAREA_ROAD)
			{
				m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK;
			}
			else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_WATER)
			{
				m_pmesh->flags[i] = SAMPLE_POLYFLAGS_SWIM;
			}
			else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_DOOR)
			{
				m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR;
			}
		}


		dtNavMeshCreateParams params;
		memset(&params, 0, sizeof(params));
		params.verts = m_pmesh->verts;
		params.vertCount = m_pmesh->nverts;
		params.polys = m_pmesh->polys;
		params.polyAreas = m_pmesh->areas;
		params.polyFlags = m_pmesh->flags;
		params.polyCount = m_pmesh->npolys;
		params.nvp = m_pmesh->nvp;
		params.detailMeshes = m_dmesh->meshes;
		params.detailVerts = m_dmesh->verts;
		params.detailVertsCount = m_dmesh->nverts;
		params.detailTris = m_dmesh->tris;
		params.detailTriCount = m_dmesh->ntris;
		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();
		params.walkableHeight = m_agentHeight;
		params.walkableRadius = m_agentRadius;
		params.walkableClimb = m_agentMaxClimb;
		rcVcopy(params.bmin, m_pmesh->bmin);
		rcVcopy(params.bmax, m_pmesh->bmax);
		params.cs = m_cfg.cs;
		params.ch = m_cfg.ch;
		params.buildBvTree = true;
		
		if (!dtCreateNavMeshData(&params, &navData, &navDataSize))
		{
			m_ctx->log(RC_LOG_ERROR, "Could not build Detour navmesh.");
			return false;
		}
		
		m_navMesh = dtAllocNavMesh();
		if (!m_navMesh)
		{
			dtFree(navData);
			m_ctx->log(RC_LOG_ERROR, "Could not create Detour navmesh");
			return false;
		}
		
		dtStatus status;
		
		status = m_navMesh->init(navData, navDataSize, DT_TILE_FREE_DATA);
		if (dtStatusFailed(status))
		{
			dtFree(navData);
			m_ctx->log(RC_LOG_ERROR, "Could not init Detour navmesh");
			return false;
		}
		
		status = m_navQuery->init(m_navMesh, 2048);
		if (dtStatusFailed(status))
		{
			m_ctx->log(RC_LOG_ERROR, "Could not init Detour navmesh query");
			return false;
		}
	}
	
	m_ctx->stopTimer(RC_TIMER_TOTAL);

	// Show performance stats.
	duLogBuildTimes(*m_ctx, m_ctx->getAccumulatedTime(RC_TIMER_TOTAL));
	m_ctx->log(RC_LOG_PROGRESS, ">> Polymesh: %d vertices  %d polygons", m_pmesh->nverts, m_pmesh->npolys);
	
	m_totalBuildTimeMs = m_ctx->getAccumulatedTime(RC_TIMER_TOTAL)/1000.0f;
	
	if (m_tool)
		m_tool->init(this);
	initToolStates(this);

	return true;
}