예제 #1
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;
}
예제 #2
0
int main()
{
	rcAllocSetCustom(allocCustom<rcAllocHint>, freeCustom);
	dtAllocSetCustom(allocCustom<dtAllocHint>, freeCustom);

	BuildContext ctx;
	InputGeom geom;

	geom.load(&ctx, "./geomset.txt");

	ArMeshDataBuilder builder(&ctx, &geom, meshProcess);

	builder.setAgentMaxClimb(1.8f);

	ArMeshDataPtr data = builder.build();

	if (!data)
	{
		ctx.log(RC_LOG_ERROR, "Build ArMeshData failed.");
		return -1;
	}

	ctx.log(RC_LOG_PROGRESS, "Total build time: %d ms", ctx.getAccumulatedTime(RC_TIMER_TOTAL));

	if (!save(&ctx, data))
	{
		return -1;
	}

	FILE* in = fopen("./all_tiles_navmesh.bin", "rb");

	if (!in)
	{
		ctx.log(RC_LOG_ERROR, "Open all_tiles_navmesh.bin failed.");
		return -1;
	}

	ArMeshDataFileReader reader(in);

	if (!reader.serialize(*data))
	{
		ctx.log(RC_LOG_ERROR, "Read ArMeshData failed.");
		fclose(in);
		return -1;
	}

	fclose(in);

	ArMesh mesh;
	ArMeshImporter importer(mesh);

	if (!importer.serialize(*data))
	{
		ctx.log(RC_LOG_ERROR, "Import ArMeshData failed.");
		return -1;
	}
	
	ArQuery query;

	if (dtStatusFailed(query.init(&mesh, 2048)))
	{
		ctx.log(RC_LOG_ERROR, "Init ArQuery failed.");
		return -1;
	}

	float sp[3];
	
	printf("start: ");
	scanf("%f%f%f", sp, sp + 1, sp + 2);

	float ep[3];

	printf("end:   ");
	scanf("%f%f%f", ep, ep + 1, ep + 2);

	float ext[3] = {2, 4, 2};
	dtQueryFilter filter;

	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);

	dtPolyRef sr;

	query.backend()->findNearestPoly(sp, ext, &filter, &sr, 0);

	dtPolyRef er;

	query.backend()->findNearestPoly(ep, ext, &filter, &er, 0);

	dtPolyRef polys[256];
	int npolys;

	query.backend()->findPath(sr, er, sp, ep, &filter, polys, &npolys, 256);

	float path[256 * 3];
	dtPolyRef pathPolys[256];
	unsigned char pathFlags[256];
	int pathLen;

	query.backend()->findStraightPath(sp, ep, polys, npolys, path, pathFlags, pathPolys, &pathLen, 256, 0);

	printf("path:\n%d\n", pathLen);

	for (int i = 0; i < pathLen; ++i)
	{
		printf("%f %f %f\n", path[i * 3], path[i * 3 + 1], path[i * 3 + 2]);
	}

	if (!exportMesh(&ctx, mesh))
	{
		return -1;
	}

	return 0;
}