NavMeshGenerator::NavMeshGenerator(rcContext* ctx) : 
	m_ctx(ctx),
	m_keepInterResults(true),
	m_totalBuildTimeMs(0),
	m_solid(0),
	m_chf(0),
	m_cset(0),
	m_pmesh(0),
	m_dmesh(0),
	m_navMesh(0)
{
	m_cellSize = 0.3f;
	m_cellHeight = 0.2f;
	m_agentHeight = 2.0f;
	m_agentRadius = 0.6f;
	m_agentMaxClimb = 0.9f;
	m_agentMaxSlope = 45.0f;
	m_regionMinSize = 8;
	m_regionMergeSize = 20;
	m_edgeMaxLen = 12.0f;
	m_edgeMaxError = 1.3f;
	m_vertsPerPoly = 6.0f;
	m_detailSampleDist = 6.0f;
	m_detailSampleMaxError = 1.0f;

	m_partitionType = 0; //SAMPLE_PARTITION_WATERSHED;
	m_navQuery = dtAllocNavMeshQuery();
	m_crowd = dtAllocCrowd();
}
Example #2
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();
}
Example #3
0
dtCrowdQuery::dtCrowdQuery(unsigned maxAgents, const dtCrowdAgent* agents, const dtCrowdAgentEnvironment* env)
	: m_agents(agents),
	m_maxAgents(maxAgents),
	m_agentsEnv(env)
{
	m_navMeshQuery = dtAllocNavMeshQuery();
}
Example #4
0
	void NavMesh::InitMesh()
	{
		// common setting
		m_cellSize = 0.3f;
		m_cellHeight = 0.2f;
		m_agentHeight = 2.0f;
		m_agentRadius = 0.6f;
		m_agentMaxClimb = 0.9f;
		m_agentMaxSlope = 45.0f;
		m_regionMinSize = 8;
		m_regionMergeSize = 20;
		m_edgeMaxLen = 12.0f;
		m_edgeMaxError = 1.3f;
		m_vertsPerPoly = 6.0f;
		m_detailSampleDist = 6.0f;
		m_detailSampleMaxError = 1.0f;
		//
		m_geom = 0;
		m_navMesh = 0;
		m_navQuery = dtAllocNavMeshQuery();
		m_crowd = dtAllocCrowd();
		m_tileCache = 0;
		m_maxTiles = 0;
		m_maxPolysPerTile = 0;
		m_tileSize = 48;
		m_talloc = new LinearAllocator(32000);
		m_tcomp = new FastLZCompressor;
		m_tmproc = new MeshProcess;
	}
Example #5
0
bool nav_mesh::load(const char* file)
{
	mesh_ = loadAll(file);
	if (mesh_ == nullptr)
	{
		return false;
	}

	query_ = dtAllocNavMeshQuery();
	if (query_ == nullptr)
	{
		return false;
	}

	dtStatus status = query_->init(mesh_, 2048);
	if (dtStatusFailed(status))
	{
		return false;
	}

	filter_.setIncludeFlags(SAMPLE_POLYFLAGS_ALL ^ SAMPLE_POLYFLAGS_DISABLED);
	filter_.setExcludeFlags(0);

	filter_.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f);
	filter_.setAreaCost(SAMPLE_POLYAREA_WATER, 10.0f);
	filter_.setAreaCost(SAMPLE_POLYAREA_ROAD, 1.0f);
	filter_.setAreaCost(SAMPLE_POLYAREA_DOOR, 1.0f);
	filter_.setAreaCost(SAMPLE_POLYAREA_GRASS, 2.0f);
	filter_.setAreaCost(SAMPLE_POLYAREA_JUMP, 1.5f);

	return true;
}
JNIEXPORT jlong JNICALL Java_ru_mmocore_external_recastnavigation_detour_NavMeshQuery_createContext
  (JNIEnv *env, jobject)
{
	Classes::initJavaClasses(env);

	dtNavMeshQuery *context = dtAllocNavMeshQuery();

	return reinterpret_cast<jlong>(context);
}
Example #7
0
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;
}
dtNavMeshQuery* PathFinderManager::getNavQuery() {
	dtNavMeshQuery* query = m_navQuery.get();

	if (query == NULL) {
		query = dtAllocNavMeshQuery();
		m_navQuery.set(query);
	}

	return query;
}
Example #9
0
Sample::Sample() :
	m_geom(0),
	m_navMesh(0),
	m_navQuery(0),
	m_navMeshDrawFlags(DU_DRAWNAVMESH_OFFMESHCONS|DU_DRAWNAVMESH_CLOSEDLIST),
	m_tool(0),
	m_ctx(0)
{
	resetCommonSettings();
	m_navQuery = dtAllocNavMeshQuery();
}
Example #10
0
Sample::Sample() :
	m_geom(0),
	m_navMesh(0),
	m_navQuery(0),
	m_crowd(0),
	m_ctx(0)
{
	resetCommonSettings();
	m_navQuery = dtAllocNavMeshQuery();
	m_crowd = dtAllocCrowd();

}
Example #11
0
Sample::Sample() :
	m_geom(0),
	m_navMesh(0),
	m_navQuery(0),
	m_crowd(0),
	m_navMeshDrawFlags(DU_DRAWNAVMESH_OFFMESHCONS|DU_DRAWNAVMESH_CLOSEDLIST),
	m_tool(0),
	m_ctx(0)
{
	resetCommonSettings();
	m_navQuery = dtAllocNavMeshQuery();
	m_crowd = dtAllocCrowd();

	for (int i = 0; i < MAX_TOOLS; i++)
		m_toolStates[i] = 0;
}
Example #12
0
bool dtPathQueue::init(const int maxPathSize, const int maxSearchNodeCount, dtNavMesh* nav)
{
	purge();

	m_navquery = dtAllocNavMeshQuery();
	if (!m_navquery)
		return false;
	if (dtStatusFailed(m_navquery->init(nav, maxSearchNodeCount)))
		return false;
	
	m_maxPathSize = maxPathSize;
	for (int i = 0; i < MAX_QUEUE; ++i)
	{
		m_queue[i].ref = DT_PATHQ_INVALID;
		m_queue[i].path = (dtPolyRef*)dtAlloc(sizeof(dtPolyRef)*m_maxPathSize, DT_ALLOC_PERM);
		if (!m_queue[i].path)
			return false;
	}
	
	m_queueHead = 0;
	
	return true;
}
Example #13
0
bool NavigationMesh::InitializeQuery()
{
    if (!navMesh_ || !node_)
        return false;
    
    if (navMeshQuery_)
        return true;
    
    navMeshQuery_ = dtAllocNavMeshQuery();
    if (!navMeshQuery_)
    {
        LOGERROR("Could not create navigation mesh query");
        return false;
    }
    
    if (dtStatusFailed(navMeshQuery_->init(navMesh_, MAX_POLYS)))
    {
        LOGERROR("Could not init navigation mesh query");
        return false;
    }
    
    return true;
}
Example #14
0
bool NavPath::onAdd()
{
   if(!Parent::onAdd())
      return false;

   if(gEditingMission)
      mNetFlags.set(Ghostable);

   resize();

   addToScene();

   if(isServerObject())
   {
      mQuery = dtAllocNavMeshQuery();
      if(!mQuery)
         return false;
      checkAutoUpdate();
      if(!plan())
         setProcessTick(true);
   }

   return true;
}
Example #15
0
////////////////// PathInfo //////////////////
PathInfo::PathInfo(const Unit* owner, const float destX, const float destY, const float destZ, bool useStraightPath) : m_pathPolyRefs(NULL),
    m_polyLength(0), m_type(PATHFIND_BLANK), m_useStraightPath(useStraightPath), m_sourceUnit(owner),
    m_navMesh(NULL), m_navMeshQuery(NULL)
{
    PathNode endPoint(destX, destY, destZ);
    setEndPosition(endPoint);

    float x,y,z;
    m_sourceUnit->GetPosition(x, y, z);
    PathNode startPoint(x, y, z);
    setStartPosition(startPoint);

    PATH_DEBUG("++ PathInfo::PathInfo for %u \n", m_sourceUnit->GetGUID());

    const Map* map = m_sourceUnit->GetMap();
    if (map->IsPathfindingEnabled())
        m_navMesh = map->GetNavMesh();

    if (m_navMesh)
    {
        m_navMeshQuery = dtAllocNavMeshQuery();
        ASSERT(m_navMeshQuery);
        if(DT_SUCCESS != m_navMeshQuery->init(m_navMesh, MESH_MAX_NODES))
        {
            sLog->outError("%u's PathInfo navMeshQuery failed to init", m_sourceUnit->GetGUID());
            return;
        }

        BuildPolyPath(startPoint, endPoint);
    }
    else
    {
        BuildShortcut();
        m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
    }
}
/// @par
///
/// May be called more than once to purge and re-initialize the crowd.
bool dtCrowd::init(const int maxAgents, const float maxAgentRadius, dtNavMesh* nav)
{
	purge();
	
	m_maxAgents = maxAgents;
	m_maxAgentRadius = maxAgentRadius;

	dtVset(m_ext, m_maxAgentRadius*2.0f,m_maxAgentRadius*1.5f,m_maxAgentRadius*2.0f);
	
	m_grid = dtAllocProximityGrid();
	if (!m_grid)
		return false;
	if (!m_grid->init(m_maxAgents*4, maxAgentRadius*3))
		return false;
	
	m_obstacleQuery = dtAllocObstacleAvoidanceQuery();
	if (!m_obstacleQuery)
		return false;
	if (!m_obstacleQuery->init(6, 8))
		return false;

	// Init obstacle query params.
	memset(m_obstacleQueryParams, 0, sizeof(m_obstacleQueryParams));
	for (int i = 0; i < DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS; ++i)
	{
		dtObstacleAvoidanceParams* params = &m_obstacleQueryParams[i];
		params->velBias = 0.4f;
		params->weightDesVel = 2.0f;
		params->weightCurVel = 0.75f;
		params->weightSide = 0.75f;
		params->weightToi = 2.5f;
		params->horizTime = 2.5f;
		params->gridSize = 33;
		params->adaptiveDivs = 7;
		params->adaptiveRings = 2;
		params->adaptiveDepth = 5;
	}
	
	// Allocate temp buffer for merging paths.
	m_maxPathResult = 256;
	m_pathResult = (dtPolyRef*)dtAlloc(sizeof(dtPolyRef)*m_maxPathResult, DT_ALLOC_PERM);
	if (!m_pathResult)
		return false;
	
	if (!m_pathq.init(m_maxPathResult, MAX_PATHQUEUE_NODES, nav))
		return false;
	
	m_agents = (dtCrowdAgent*)dtAlloc(sizeof(dtCrowdAgent)*m_maxAgents, DT_ALLOC_PERM);
	if (!m_agents)
		return false;
	
	m_activeAgents = (dtCrowdAgent**)dtAlloc(sizeof(dtCrowdAgent*)*m_maxAgents, DT_ALLOC_PERM);
	if (!m_activeAgents)
		return false;

	m_agentAnims = (dtCrowdAgentAnimation*)dtAlloc(sizeof(dtCrowdAgentAnimation)*m_maxAgents, DT_ALLOC_PERM);
	if (!m_agentAnims)
		return false;
	
	for (int i = 0; i < m_maxAgents; ++i)
	{
		new(&m_agents[i]) dtCrowdAgent();
		m_agents[i].active = 0;
		if (!m_agents[i].corridor.init(m_maxPathResult))
			return false;
	}

	for (int i = 0; i < m_maxAgents; ++i)
	{
		m_agentAnims[i].active = 0;
	}

	// The navquery is mostly used for local searches, no need for large node pool.
	m_navquery = dtAllocNavMeshQuery();
	if (!m_navquery)
		return false;
	if (dtStatusFailed(m_navquery->init(nav, MAX_COMMON_NODES)))
		return false;
	
	return true;
}
Example #17
0
qboolean BotSetupNav( const botClass_t *botClass, qhandle_t *navHandle )
{
	cvar_t *maxNavNodes = Cvar_Get( "bot_maxNavNodes", "4096", CVAR_ARCHIVE | CVAR_LATCH );

	if ( !numNavData )
	{
		vec3_t clearVec = { 0, 0, 0 };

		dtAllocSetCustom( dtAllocCustom, dtFreeCustom );

		for ( int i = 0; i < MAX_CLIENTS; i++ )
		{
			// should only init the corridor once
			if ( !agents[ i ].corridor.getPath() )
			{
				if ( !agents[ i ].corridor.init( MAX_BOT_PATH ) )
				{
					return qfalse;
				}
			}

			agents[ i ].corridor.reset( 0, clearVec );
			agents[ i ].clientNum = i;
			agents[ i ].needReplan = true;
			agents[ i ].nav = NULL;
			agents[ i ].offMesh = false;
			memset( agents[ i ].routeResults, 0, sizeof( agents[ i ].routeResults ) );
		}
#ifndef DEDICATED
		NavEditInit();
#endif
	}

	if ( numNavData == MAX_NAV_DATA )
	{
		Com_Printf( "^3ERROR: maximum number of navigation meshes exceeded\n" );
		return qfalse;
	}

	NavData_t *nav = &BotNavData[ numNavData ];
	const char *filename = botClass->name;

	if ( !BotLoadNavMesh( filename, *nav ) )
	{
		BotShutdownNav();
		return qfalse;
	}

	Q_strncpyz( nav->name, botClass->name, sizeof( nav->name ) );
	nav->query = dtAllocNavMeshQuery();

	if ( !nav->query )
	{
		Com_Printf( "Could not allocate Detour Navigation Mesh Query for navmesh %s\n", filename );
		BotShutdownNav();
		return qfalse;
	}

	if ( dtStatusFailed( nav->query->init( nav->mesh, maxNavNodes->integer ) ) )
	{
		Com_Printf( "Could not init Detour Navigation Mesh Query for navmesh %s\n", filename );
		BotShutdownNav();
		return qfalse;
	}

	nav->filter.setIncludeFlags( botClass->polyFlagsInclude );
	nav->filter.setExcludeFlags( botClass->polyFlagsExclude );
	*navHandle = numNavData;
	numNavData++;
	return qtrue;
}
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;
}
Example #19
0
/// @par
///
/// May be called more than once to purge and re-initialize the crowd.
bool dtCrowd::init(const int maxAgents, const float maxAgentRadius, dtNavMesh* nav)
{
	purge();
	
	m_maxAgents = maxAgents;
	m_maxAgentRadius = maxAgentRadius;
	m_numActiveAgents = 0;

	dtVset(m_ext, m_maxAgentRadius*2.0f,m_maxAgentRadius*1.5f,m_maxAgentRadius*2.0f);
	
	m_grid = dtAllocProximityGrid();
	if (!m_grid)
		return false;
	if (!m_grid->init(m_maxAgents*4, maxAgentRadius*3))
		return false;

	// [UE4] moved avoidance query init to separate function

	// Allocate temp buffer for merging paths.
	m_maxPathResult = 256;
	m_pathResult = (dtPolyRef*)dtAlloc(sizeof(dtPolyRef)*m_maxPathResult, DT_ALLOC_PERM);
	if (!m_pathResult)
		return false;
	
	if (!m_pathq.init(m_maxPathResult, MAX_PATHQUEUE_NODES, nav))
		return false;
	
	m_agents = (dtCrowdAgent*)dtAlloc(sizeof(dtCrowdAgent)*m_maxAgents, DT_ALLOC_PERM);
	if (!m_agents)
		return false;
	
	m_activeAgents = (dtCrowdAgent**)dtAlloc(sizeof(dtCrowdAgent*)*m_maxAgents, DT_ALLOC_PERM);
	if (!m_activeAgents)
		return false;

	m_agentAnims = (dtCrowdAgentAnimation*)dtAlloc(sizeof(dtCrowdAgentAnimation)*m_maxAgents, DT_ALLOC_PERM);
	if (!m_agentAnims)
		return false;
	
	for (int i = 0; i < m_maxAgents; ++i)
	{
		new(&m_agents[i]) dtCrowdAgent();
		m_agents[i].active = 0;
		if (!m_agents[i].corridor.init(m_maxPathResult))
			return false;
	}

	for (int i = 0; i < m_maxAgents; ++i)
	{
		m_agentAnims[i].active = 0;
	}

	for (int i = 0; i < DT_MAX_AREAS; i++)
	{
		m_raycastFilter.setAreaCost(i, DT_UNWALKABLE_POLY_COST);
	}

	// The navquery is mostly used for local searches, no need for large node pool.
	m_navquery = dtAllocNavMeshQuery();
	if (!m_navquery)
		return false;
	if (dtStatusFailed(m_navquery->init(nav, MAX_COMMON_NODES)))
		return false;
	
	return true;
}
Example #20
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;
}
Example #21
0
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;
}
Example #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;
}
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;
}
Example #24
0
	bool NavMeshLoader::load_cai(const char* path) {
		FILE* fp = fopen(path, "rb");
		if (!fp) return false;

		// Read header.
		NavMeshSetHeader_CAI header;
		size_t readLen = fread(&header, sizeof(NavMeshSetHeader_CAI), 1, fp);
		if (readLen != 1)
		{
			fclose(fp);
			return false;
		}

		if (header.version != NAVMESHSET_VERSION)
		{
			fclose(fp);
			return false;
		}

		dtNavMesh* mesh = dtAllocNavMesh();
		if (!mesh)
		{
			fclose(fp);
			return false;
		}
		dtStatus status = mesh->init(&header.params);
		if (dtStatusFailed(status))
		{
			fclose(fp);
			return false;
		}

		// Read tiles.
		for (int i = 0; i < header.tileCount; ++i)
		{
			NavMeshTileHeader tileHeader;
			readLen = fread(&tileHeader, sizeof(tileHeader), 1, fp);
			if (readLen != 1)
			{
				fclose(fp);
				return false;
			}

			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);
			readLen = fread(data, tileHeader.dataSize, 1, fp);
			if (readLen != 1)
			{
				fclose(fp);
				return false;
			}

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

		fclose(fp);
		m_navMesh = mesh;
		m_navQuery = dtAllocNavMeshQuery();

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

		return true;
	}