forked from mirror/DotRecast
180 lines
6.8 KiB
C#
180 lines
6.8 KiB
C#
/*
|
|
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using DotRecast.Detour.Dynamic.Colliders;
|
|
using DotRecast.Detour.Dynamic.Io;
|
|
using DotRecast.Recast;
|
|
|
|
namespace DotRecast.Detour.Dynamic
|
|
{
|
|
public class DynamicTile
|
|
{
|
|
public readonly VoxelTile voxelTile;
|
|
public DynamicTileCheckpoint checkpoint;
|
|
public RecastBuilderResult recastResult;
|
|
MeshData meshData;
|
|
private readonly ConcurrentDictionary<long, ICollider> colliders = new ConcurrentDictionary<long, ICollider>();
|
|
private bool dirty = true;
|
|
private long id;
|
|
|
|
public DynamicTile(VoxelTile voxelTile)
|
|
{
|
|
this.voxelTile = voxelTile;
|
|
}
|
|
|
|
public bool Build(RecastBuilder builder, DynamicNavMeshConfig config, Telemetry telemetry)
|
|
{
|
|
if (dirty)
|
|
{
|
|
Heightfield heightfield = BuildHeightfield(config, telemetry);
|
|
RecastBuilderResult r = BuildRecast(builder, config, voxelTile, heightfield, telemetry);
|
|
NavMeshDataCreateParams option = NavMeshCreateParams(voxelTile.tileX, voxelTile.tileZ, voxelTile.cellSize,
|
|
voxelTile.cellHeight, config, r);
|
|
meshData = NavMeshBuilder.CreateNavMeshData(option);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private Heightfield BuildHeightfield(DynamicNavMeshConfig config, Telemetry telemetry)
|
|
{
|
|
ICollection<long> rasterizedColliders = checkpoint != null ? checkpoint.colliders : ImmutableHashSet<long>.Empty;
|
|
Heightfield heightfield = checkpoint != null ? checkpoint.heightfield : voxelTile.Heightfield();
|
|
foreach (var (cid, c) in colliders)
|
|
{
|
|
if (!rasterizedColliders.Contains(cid))
|
|
{
|
|
heightfield.bmax.y = Math.Max(heightfield.bmax.y, c.Bounds()[4] + heightfield.ch * 2);
|
|
c.Rasterize(heightfield, telemetry);
|
|
}
|
|
}
|
|
|
|
if (config.enableCheckpoints)
|
|
{
|
|
checkpoint = new DynamicTileCheckpoint(heightfield, colliders.Keys.ToHashSet());
|
|
}
|
|
|
|
return heightfield;
|
|
}
|
|
|
|
private RecastBuilderResult BuildRecast(RecastBuilder builder, DynamicNavMeshConfig config, VoxelTile vt,
|
|
Heightfield heightfield, Telemetry telemetry)
|
|
{
|
|
RecastConfig rcConfig = new RecastConfig(config.useTiles, config.tileSizeX, config.tileSizeZ, vt.borderSize,
|
|
config.partitionType, vt.cellSize, vt.cellHeight, config.walkableSlopeAngle, true, true, true,
|
|
config.walkableHeight, config.walkableRadius, config.walkableClimb, config.minRegionArea, config.regionMergeArea,
|
|
config.maxEdgeLen, config.maxSimplificationError,
|
|
Math.Min(DynamicNavMesh.MAX_VERTS_PER_POLY, config.vertsPerPoly), true, config.detailSampleDistance,
|
|
config.detailSampleMaxError, null);
|
|
RecastBuilderResult r = builder.Build(vt.tileX, vt.tileZ, null, rcConfig, heightfield, telemetry);
|
|
if (config.keepIntermediateResults)
|
|
{
|
|
recastResult = r;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
public void AddCollider(long cid, ICollider collider)
|
|
{
|
|
colliders[cid] = collider;
|
|
dirty = true;
|
|
}
|
|
|
|
public bool ContainsCollider(long cid)
|
|
{
|
|
return colliders.ContainsKey(cid);
|
|
}
|
|
|
|
public void RemoveCollider(long colliderId)
|
|
{
|
|
if (colliders.TryRemove(colliderId, out var collider))
|
|
{
|
|
dirty = true;
|
|
checkpoint = null;
|
|
}
|
|
}
|
|
|
|
private NavMeshDataCreateParams NavMeshCreateParams(int tilex, int tileZ, float cellSize, float cellHeight,
|
|
DynamicNavMeshConfig config, RecastBuilderResult rcResult)
|
|
{
|
|
PolyMesh m_pmesh = rcResult.GetMesh();
|
|
PolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
|
|
NavMeshDataCreateParams option = new NavMeshDataCreateParams();
|
|
for (int i = 0; i < m_pmesh.npolys; ++i)
|
|
{
|
|
m_pmesh.flags[i] = 1;
|
|
}
|
|
|
|
option.tileX = tilex;
|
|
option.tileZ = tileZ;
|
|
option.verts = m_pmesh.verts;
|
|
option.vertCount = m_pmesh.nverts;
|
|
option.polys = m_pmesh.polys;
|
|
option.polyAreas = m_pmesh.areas;
|
|
option.polyFlags = m_pmesh.flags;
|
|
option.polyCount = m_pmesh.npolys;
|
|
option.nvp = m_pmesh.nvp;
|
|
if (m_dmesh != null)
|
|
{
|
|
option.detailMeshes = m_dmesh.meshes;
|
|
option.detailVerts = m_dmesh.verts;
|
|
option.detailVertsCount = m_dmesh.nverts;
|
|
option.detailTris = m_dmesh.tris;
|
|
option.detailTriCount = m_dmesh.ntris;
|
|
}
|
|
|
|
option.walkableHeight = config.walkableHeight;
|
|
option.walkableRadius = config.walkableRadius;
|
|
option.walkableClimb = config.walkableClimb;
|
|
option.bmin = m_pmesh.bmin;
|
|
option.bmax = m_pmesh.bmax;
|
|
option.cs = cellSize;
|
|
option.ch = cellHeight;
|
|
option.buildBvTree = true;
|
|
|
|
option.offMeshConCount = 0;
|
|
option.offMeshConVerts = new float[0];
|
|
option.offMeshConRad = new float[0];
|
|
option.offMeshConDir = new int[0];
|
|
option.offMeshConAreas = new int[0];
|
|
option.offMeshConFlags = new int[0];
|
|
option.offMeshConUserID = new int[0];
|
|
return option;
|
|
}
|
|
|
|
public void AddTo(NavMesh navMesh)
|
|
{
|
|
if (meshData != null)
|
|
{
|
|
id = navMesh.AddTile(meshData, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
navMesh.RemoveTile(id);
|
|
id = 0;
|
|
}
|
|
}
|
|
}
|
|
} |