added DtNavMesh.Init()

This commit is contained in:
ikpil 2024-05-12 22:05:19 +09:00
parent 40306a5302
commit 47be4eca70
18 changed files with 108 additions and 69 deletions

View File

@ -8,9 +8,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added ### Added
- Added RcSpans UnitTest - Added RcSpans UnitTest
- Added DtNavMesh.Init() interface
### Fixed ### Fixed
### Changed ### Changed
- RcRecast, DtDetour
### Removed ### Removed
### Special Thanks ### Special Thanks
- [@Doprez](https://github.com/Doprez) - [@Doprez](https://github.com/Doprez)

View File

@ -224,9 +224,13 @@ namespace DotRecast.Detour.Dynamic
{ {
if (_dirty) if (_dirty)
{ {
DtNavMesh navMesh = new DtNavMesh(navMeshParams, MAX_VERTS_PER_POLY); DtNavMesh navMesh = new DtNavMesh();
navMesh.Init(navMeshParams, MAX_VERTS_PER_POLY);
foreach (var t in _tiles.Values) foreach (var t in _tiles.Values)
{
t.AddTo(navMesh); t.AddTo(navMesh);
}
_navMesh = navMesh; _navMesh = navMesh;
_dirty = false; _dirty = false;

View File

@ -168,12 +168,12 @@ namespace DotRecast.Detour.Dynamic
option.buildBvTree = true; option.buildBvTree = true;
option.offMeshConCount = 0; option.offMeshConCount = 0;
option.offMeshConVerts = new float[0]; option.offMeshConVerts = Array.Empty<float>();
option.offMeshConRad = new float[0]; option.offMeshConRad = Array.Empty<float>();
option.offMeshConDir = new int[0]; option.offMeshConDir = Array.Empty<int>();
option.offMeshConAreas = new int[0]; option.offMeshConAreas = Array.Empty<int>();
option.offMeshConFlags = new int[0]; option.offMeshConFlags = Array.Empty<int>();
option.offMeshConUserID = new int[0]; option.offMeshConUserID = Array.Empty<int>();
return option; return option;
} }
@ -181,7 +181,7 @@ namespace DotRecast.Detour.Dynamic
{ {
if (meshData != null) if (meshData != null)
{ {
id = navMesh.AddTile(meshData, 0, 0); navMesh.AddTile(meshData, 0, 0, out var id);
} }
else else
{ {

View File

@ -1,6 +1,5 @@
using DotRecast.Core; using DotRecast.Core;
using DotRecast.Core.Numerics; using DotRecast.Core.Numerics;
using DotRecast.Recast; using DotRecast.Recast;
namespace DotRecast.Detour.Extras.Jumplink namespace DotRecast.Detour.Extras.Jumplink
@ -36,7 +35,14 @@ namespace DotRecast.Detour.Extras.Jumplink
option.cs = r.Mesh.cs; option.cs = r.Mesh.cs;
option.ch = r.Mesh.ch; option.ch = r.Mesh.ch;
option.buildBvTree = true; option.buildBvTree = true;
return new DtNavMeshQuery(new DtNavMesh(DtNavMeshBuilder.CreateNavMeshData(option), option.nvp, 0)); var mesh = new DtNavMesh();
var status = mesh.Init(DtNavMeshBuilder.CreateNavMeshData(option), option.nvp, 0);
if (status.Failed())
{
return null;
}
return new DtNavMeshQuery(mesh);
} }

View File

@ -78,7 +78,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
int nodeCount = buffer.GetInt(); int nodeCount = buffer.GetInt();
DtPoly[] nodes = new DtPoly[nodeCount]; DtPoly[] nodes = new DtPoly[nodeCount];
DtPolyDetail[] detailNodes = new DtPolyDetail[nodeCount]; DtPolyDetail[] detailNodes = new DtPolyDetail[nodeCount];
float[] detailVerts = new float[0]; float[] detailVerts = Array.Empty<float>();
int[] detailTris = new int[4 * nodeCount]; int[] detailTris = new int[4 * nodeCount];
int vertMask = GetVertMask(vertsCount); int vertMask = GetVertMask(vertsCount);
float ymin = float.PositiveInfinity; float ymin = float.PositiveInfinity;

View File

@ -65,10 +65,11 @@ namespace DotRecast.Detour.Extras.Unity.Astar
option.orig.X = -0.5f * graphMeta.forcedBoundsSize.x + graphMeta.forcedBoundsCenter.x; option.orig.X = -0.5f * graphMeta.forcedBoundsSize.x + graphMeta.forcedBoundsCenter.x;
option.orig.Y = -0.5f * graphMeta.forcedBoundsSize.y + graphMeta.forcedBoundsCenter.y; option.orig.Y = -0.5f * graphMeta.forcedBoundsSize.y + graphMeta.forcedBoundsCenter.y;
option.orig.Z = -0.5f * graphMeta.forcedBoundsSize.z + graphMeta.forcedBoundsCenter.z; option.orig.Z = -0.5f * graphMeta.forcedBoundsSize.z + graphMeta.forcedBoundsCenter.z;
DtNavMesh mesh = new DtNavMesh(option, 3); DtNavMesh mesh = new DtNavMesh();
mesh.Init(option, 3);
foreach (DtMeshData t in graphMeshData.tiles) foreach (DtMeshData t in graphMeshData.tiles)
{ {
mesh.AddTile(t, 0, 0); mesh.AddTile(t, 0, 0, out _);
} }
meshes[graphIndex] = mesh; meshes[graphIndex] = mesh;

View File

@ -672,7 +672,7 @@ namespace DotRecast.Detour.TileCache
// Add new tile, or leave the location empty. if (navData) { // Let the // Add new tile, or leave the location empty. if (navData) { // Let the
if (meshData != null) if (meshData != null)
{ {
m_navmesh.AddTile(meshData, 0, 0); m_navmesh.AddTile(meshData, 0, 0, out var result);
} }
} }

View File

@ -69,7 +69,8 @@ namespace DotRecast.Detour.TileCache.Io
header.numTiles = bb.GetInt(); header.numTiles = bb.GetInt();
header.meshParams = paramReader.Read(bb); header.meshParams = paramReader.Read(bb);
header.cacheParams = ReadCacheParams(bb, cCompatibility); header.cacheParams = ReadCacheParams(bb, cCompatibility);
DtNavMesh mesh = new DtNavMesh(header.meshParams, maxVertPerPoly); DtNavMesh mesh = new DtNavMesh();
mesh.Init(header.meshParams, maxVertPerPoly);
IRcCompressor comp = _compFactory.Create(cCompatibility ? 0 : 1); IRcCompressor comp = _compFactory.Create(cCompatibility ? 0 : 1);
DtTileCacheStorageParams storageParams = new DtTileCacheStorageParams(bb.Order(), cCompatibility); DtTileCacheStorageParams storageParams = new DtTileCacheStorageParams(bb.Order(), cCompatibility);
DtTileCache tc = new DtTileCache(header.cacheParams, storageParams, mesh, comp, meshProcessor); DtTileCache tc = new DtTileCache(header.cacheParams, storageParams, mesh, comp, meshProcessor);

View File

@ -29,29 +29,23 @@ namespace DotRecast.Detour
public class DtNavMesh public class DtNavMesh
{ {
private readonly DtNavMeshParams m_params; //< Current initialization params. TODO: do not store this info twice. private DtNavMeshParams m_params; //< Current initialization params. TODO: do not store this info twice.
private readonly RcVec3f m_orig; // < Origin of the tile (0,0) private RcVec3f m_orig; // < Origin of the tile (0,0)
private readonly float m_tileWidth; // < Dimensions of each tile. private float m_tileWidth; // < Dimensions of each tile.
private readonly float m_tileHeight; // < Dimensions of each tile. private float m_tileHeight; // < Dimensions of each tile.
private readonly int m_maxTiles; // < Max number of tiles. private int m_maxTiles; // < Max number of tiles.
private readonly int m_tileLutMask; // < Tile hash lookup mask. private int m_tileLutMask; // < Tile hash lookup mask.
private readonly Dictionary<int, List<DtMeshTile>> m_posLookup; //< Tile hash lookup. private Dictionary<int, List<DtMeshTile>> m_posLookup; //< Tile hash lookup.
private readonly LinkedList<DtMeshTile> m_nextFree; //< Freelist of tiles. private LinkedList<DtMeshTile> m_nextFree; //< Freelist of tiles.
private readonly DtMeshTile[] m_tiles; //< List of tiles. private DtMeshTile[] m_tiles; //< List of tiles.
/** The maximum number of vertices per navigation polygon. */ /** The maximum number of vertices per navigation polygon. */
private readonly int m_maxVertPerPoly; private int m_maxVertPerPoly;
private int m_tileCount; private int m_tileCount;
public DtNavMesh(DtMeshData data, int maxVertsPerPoly, int flags) public DtStatus Init(DtNavMeshParams option, int maxVertsPerPoly)
: this(GetNavMeshParams(data), maxVertsPerPoly)
{
AddTile(data, flags, 0);
}
public DtNavMesh(DtNavMeshParams option, int maxVertsPerPoly)
{ {
m_params = option; m_params = option;
m_orig = option.orig; m_orig = option.orig;
@ -70,6 +64,18 @@ namespace DotRecast.Detour
m_tiles[i].salt = 1; m_tiles[i].salt = 1;
m_nextFree.AddLast(m_tiles[i]); m_nextFree.AddLast(m_tiles[i]);
} }
return DtStatus.DT_SUCCESS;
}
public DtStatus Init(DtMeshData data, int maxVertsPerPoly, int flags)
{
var option = GetNavMeshParams(data);
DtStatus status = Init(option, maxVertsPerPoly);
if (status.Failed())
return status;
return AddTile(data, flags, 0, out _);
} }
private static DtNavMeshParams GetNavMeshParams(DtMeshData data) private static DtNavMeshParams GetNavMeshParams(DtMeshData data)
@ -328,31 +334,21 @@ namespace DotRecast.Detour
} }
} }
public long UpdateTile(DtMeshData data, int flags) public DtStatus UpdateTile(DtMeshData data, int flags)
{ {
long refs = GetTileRefAt(data.header.x, data.header.y, data.header.layer); long refs = GetTileRefAt(data.header.x, data.header.y, data.header.layer);
refs = RemoveTile(refs); refs = RemoveTile(refs);
return AddTile(data, flags, refs); return AddTile(data, flags, refs, out _);
} }
/// Adds a tile to the navigation mesh.
/// @param[in] data Data for the new tile mesh. (See: #dtCreateNavMeshData)
/// @param[in] dataSize Data size of the new tile mesh.
/// @param[in] flags Tile flags. (See: #dtTileFlags)
/// @param[in] lastRef The desired reference for the tile. (When reloading a
/// tile.) [opt] [Default: 0]
/// @param[out] result The tile reference. (If the tile was succesfully
/// added.) [opt]
/// @return The status flags for the operation.
/// @par /// @par
/// ///
/// The add operation will fail if the data is in the wrong format, the /// The add operation will fail if the data is in the wrong format, the allocated tile
/// allocated tile
/// space is full, or there is a tile already at the specified reference. /// space is full, or there is a tile already at the specified reference.
/// ///
/// The lastRef parameter is used to restore a tile with the same tile /// The lastRef parameter is used to restore a tile with the same tile
/// reference it had previously used. In this case the #long's for the /// reference it had previously used. In this case the #dtPolyRef's for the
/// tile will be restored to the same values they were before the tile was /// tile will be restored to the same values they were before the tile was
/// removed. /// removed.
/// ///
/// The nav mesh assumes exclusive access to the data passed and will make /// The nav mesh assumes exclusive access to the data passed and will make
@ -361,15 +357,24 @@ namespace DotRecast.Detour
/// removed from this nav mesh. /// removed from this nav mesh.
/// ///
/// @see dtCreateNavMeshData, #removeTile /// @see dtCreateNavMeshData, #removeTile
public long AddTile(DtMeshData data, int flags, long lastRef) /// Adds a tile to the navigation mesh.
/// @param[in] data Data for the new tile mesh. (See: #dtCreateNavMeshData)
/// @param[in] dataSize Data size of the new tile mesh.
/// @param[in] flags Tile flags. (See: #dtTileFlags)
/// @param[in] lastRef The desired reference for the tile. (When reloading a tile.) [opt] [Default: 0]
/// @param[out] result The tile reference. (If the tile was succesfully added.) [opt]
/// @return The status flags for the operation.
public DtStatus AddTile(DtMeshData data, int flags, long lastRef, out long result)
{ {
result = 0;
// Make sure the data is in right format. // Make sure the data is in right format.
DtMeshHeader header = data.header; DtMeshHeader header = data.header;
// Make sure the location is free. // Make sure the location is free.
if (GetTileAt(header.x, header.y, header.layer) != null) if (GetTileAt(header.x, header.y, header.layer) != null)
{ {
throw new Exception("Tile already exists"); return DtStatus.DT_FAILURE | DtStatus.DT_ALREADY_OCCUPIED;
} }
// Allocate a tile. // Allocate a tile.
@ -392,7 +397,7 @@ namespace DotRecast.Detour
int tileIndex = DecodePolyIdTile(lastRef); int tileIndex = DecodePolyIdTile(lastRef);
if (tileIndex >= m_maxTiles) if (tileIndex >= m_maxTiles)
{ {
throw new Exception("Tile index too high"); return DtStatus.DT_FAILURE | DtStatus.DT_OUT_OF_MEMORY;
} }
// Try to find the specific tile id from the free list. // Try to find the specific tile id from the free list.
@ -401,7 +406,7 @@ namespace DotRecast.Detour
if (!m_nextFree.Remove(target)) if (!m_nextFree.Remove(target))
{ {
// Could not find the correct location. // Could not find the correct location.
throw new Exception("Could not find tile"); return DtStatus.DT_FAILURE | DtStatus.DT_OUT_OF_MEMORY;
} }
tile = target; tile = target;
@ -409,6 +414,12 @@ namespace DotRecast.Detour
tile.salt = DecodePolyIdSalt(lastRef); tile.salt = DecodePolyIdSalt(lastRef);
} }
// Make sure we could allocate a tile.
if (null == tile)
{
return DtStatus.DT_FAILURE | DtStatus.DT_OUT_OF_MEMORY;
}
tile.data = data; tile.data = data;
tile.flags = flags; tile.flags = flags;
tile.links.Clear(); tile.links.Clear();
@ -461,7 +472,8 @@ namespace DotRecast.Detour
} }
} }
return GetTileRef(tile); result = GetTileRef(tile);
return DtStatus.DT_SUCCESS;
} }
/// Removes the specified tile from the navigation mesh. /// Removes the specified tile from the navigation mesh.

View File

@ -68,7 +68,8 @@ namespace DotRecast.Detour.Io
} }
bool cCompatibility = header.version == NavMeshSetHeader.NAVMESHSET_VERSION; bool cCompatibility = header.version == NavMeshSetHeader.NAVMESHSET_VERSION;
DtNavMesh mesh = new DtNavMesh(header.option, header.maxVertsPerPoly); DtNavMesh mesh = new DtNavMesh();
mesh.Init(header.option, header.maxVertsPerPoly);
ReadTiles(bb, is32Bit, ref header, cCompatibility, mesh); ReadTiles(bb, is32Bit, ref header, cCompatibility, mesh);
return mesh; return mesh;
} }
@ -133,7 +134,7 @@ namespace DotRecast.Detour.Io
} }
DtMeshData data = meshReader.Read(bb, mesh.GetMaxVertsPerPoly(), is32Bit); DtMeshData data = meshReader.Read(bb, mesh.GetMaxVertsPerPoly(), is32Bit);
mesh.AddTile(data, i, tileHeader.tileRef); mesh.AddTile(data, i, tileHeader.tileRef, out _);
} }
} }

View File

@ -73,7 +73,14 @@ namespace DotRecast.Recast.Toolset.Builder
private DtNavMesh BuildNavMesh(DtMeshData meshData, int vertsPerPoly) private DtNavMesh BuildNavMesh(DtMeshData meshData, int vertsPerPoly)
{ {
return new DtNavMesh(meshData, vertsPerPoly, 0); var mesh = new DtNavMesh();
var status = mesh.Init(meshData, vertsPerPoly, 0);
if (status.Failed())
{
return null;
}
return mesh;
} }
private RcBuilderResult BuildRecastResult(DemoInputGeomProvider geom, RcConfig cfg, bool keepInterResults) private RcBuilderResult BuildRecastResult(DemoInputGeomProvider geom, RcConfig cfg, bool keepInterResults)

View File

@ -115,8 +115,9 @@ namespace DotRecast.Recast.Toolset.Builder
navMeshParams.maxTiles = GetMaxTiles(geom, cellSize, tileSize); navMeshParams.maxTiles = GetMaxTiles(geom, cellSize, tileSize);
navMeshParams.maxPolys = GetMaxPolysPerTile(geom, cellSize, tileSize); navMeshParams.maxPolys = GetMaxPolysPerTile(geom, cellSize, tileSize);
DtNavMesh navMesh = new DtNavMesh(navMeshParams, vertsPerPoly); DtNavMesh navMesh = new DtNavMesh();
meshData.ForEach(md => navMesh.AddTile(md, 0, 0)); navMesh.Init(navMeshParams, vertsPerPoly);
meshData.ForEach(md => navMesh.AddTile(md, 0, 0, out _));
return navMesh; return navMesh;
} }

View File

@ -141,7 +141,8 @@ namespace DotRecast.Recast.Toolset.Tools
navMeshParams.maxTiles = 256; // .. navMeshParams.maxTiles = 256; // ..
navMeshParams.maxPolys = 16384; navMeshParams.maxPolys = 16384;
var navMesh = new DtNavMesh(navMeshParams, 6); var navMesh = new DtNavMesh();
navMesh.Init(navMeshParams, 6);
var comp = _comp.Create(cCompatibility ? 0 : 1); var comp = _comp.Create(cCompatibility ? 0 : 1);
var storageParams = new DtTileCacheStorageParams(order, cCompatibility); var storageParams = new DtTileCacheStorageParams(order, cCompatibility);
DtTileCache tc = new DtTileCache(option, storageParams, navMesh, comp, _proc); DtTileCache tc = new DtTileCache(option, storageParams, navMesh, comp, _proc);

View File

@ -25,7 +25,6 @@ using NUnit.Framework;
namespace DotRecast.Detour.Crowd.Test; namespace DotRecast.Detour.Crowd.Test;
public class AbstractCrowdTest public class AbstractCrowdTest
{ {
protected readonly long[] startRefs = protected readonly long[] startRefs =
@ -64,7 +63,8 @@ public class AbstractCrowdTest
public void SetUp() public void SetUp()
{ {
nmd = new RecastTestMeshBuilder().GetMeshData(); nmd = new RecastTestMeshBuilder().GetMeshData();
navmesh = new DtNavMesh(nmd, 6, 0); navmesh = new DtNavMesh();
navmesh.Init(nmd, 6, 0);
query = new DtNavMeshQuery(navmesh); query = new DtNavMeshQuery(navmesh);
DtCrowdConfig config = new DtCrowdConfig(0.6f); DtCrowdConfig config = new DtCrowdConfig(0.6f);
crowd = new DtCrowd(config, navmesh); crowd = new DtCrowd(config, navmesh);

View File

@ -21,7 +21,6 @@ using NUnit.Framework;
namespace DotRecast.Detour.Test; namespace DotRecast.Detour.Test;
public abstract class AbstractDetourTest public abstract class AbstractDetourTest
{ {
protected static readonly long[] startRefs = protected static readonly long[] startRefs =
@ -64,6 +63,8 @@ public abstract class AbstractDetourTest
protected DtNavMesh CreateNavMesh() protected DtNavMesh CreateNavMesh()
{ {
return new DtNavMesh(new RecastTestMeshBuilder().GetMeshData(), 6, 0); var mesh = new DtNavMesh();
mesh.Init(new RecastTestMeshBuilder().GetMeshData(), 6, 0);
return mesh;
} }
} }

View File

@ -28,7 +28,6 @@ using NUnit.Framework;
namespace DotRecast.Detour.Test.Io; namespace DotRecast.Detour.Test.Io;
public class MeshSetReaderWriterTest public class MeshSetReaderWriterTest
{ {
private readonly DtMeshSetWriter writer = new DtMeshSetWriter(); private readonly DtMeshSetWriter writer = new DtMeshSetWriter();
@ -66,7 +65,8 @@ public class MeshSetReaderWriterTest
header.option.maxTiles = m_maxTiles; header.option.maxTiles = m_maxTiles;
header.option.maxPolys = m_maxPolysPerTile; header.option.maxPolys = m_maxPolysPerTile;
header.numTiles = 0; header.numTiles = 0;
DtNavMesh mesh = new DtNavMesh(header.option, 6); DtNavMesh mesh = new DtNavMesh();
mesh.Init(header.option, 6);
RcVec3f bmin = geom.GetMeshBoundsMin(); RcVec3f bmin = geom.GetMeshBoundsMin();
RcVec3f bmax = geom.GetMeshBoundsMax(); RcVec3f bmax = geom.GetMeshBoundsMax();
@ -92,7 +92,7 @@ public class MeshSetReaderWriterTest
if (data != null) if (data != null)
{ {
mesh.RemoveTile(mesh.GetTileRefAt(x, y, 0)); mesh.RemoveTile(mesh.GetTileRefAt(x, y, 0));
mesh.AddTile(data, 0, 0); mesh.AddTile(data, 0, 0, out _);
} }
} }
} }

View File

@ -17,7 +17,6 @@ freely, subject to the following restrictions:
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using DotRecast.Core.Numerics;
using DotRecast.Recast; using DotRecast.Recast;
using DotRecast.Recast.Geom; using DotRecast.Recast.Geom;
@ -64,7 +63,8 @@ public class TestTiledNavMeshBuilder
navMeshParams.tileHeight = tileSize * cellSize; navMeshParams.tileHeight = tileSize * cellSize;
navMeshParams.maxTiles = 128; navMeshParams.maxTiles = 128;
navMeshParams.maxPolys = 32768; navMeshParams.maxPolys = 32768;
navMesh = new DtNavMesh(navMeshParams, 6); navMesh = new DtNavMesh();
navMesh.Init(navMeshParams, 6);
// Build all tiles // Build all tiles
RcConfig cfg = new RcConfig(true, tileSize, tileSize, RcConfig.CalcBorder(agentRadius, cellSize), RcConfig cfg = new RcConfig(true, tileSize, tileSize, RcConfig.CalcBorder(agentRadius, cellSize),
@ -119,7 +119,7 @@ public class TestTiledNavMeshBuilder
option.tileX = result.TileX; option.tileX = result.TileX;
option.tileZ = result.TileZ; option.tileZ = result.TileZ;
option.buildBvTree = true; option.buildBvTree = true;
navMesh.AddTile(DtNavMeshBuilder.CreateNavMeshData(option), 0, 0); navMesh.AddTile(DtNavMeshBuilder.CreateNavMeshData(option), 0, 0, out _);
} }
} }

View File

@ -64,7 +64,8 @@ public class AbstractTileCacheTest
navMeshParams.maxTiles = 256; navMeshParams.maxTiles = 256;
navMeshParams.maxPolys = 16384; navMeshParams.maxPolys = 16384;
var navMesh = new DtNavMesh(navMeshParams, 6); var navMesh = new DtNavMesh();
navMesh.Init(navMeshParams, 6);
var comp = DtTileCacheCompressorFactory.Shared.Create(cCompatibility ? 0 : 1); var comp = DtTileCacheCompressorFactory.Shared.Create(cCompatibility ? 0 : 1);
var storageParams = new DtTileCacheStorageParams(order, cCompatibility); var storageParams = new DtTileCacheStorageParams(order, cCompatibility);
var process = new TestTileCacheMeshProcess(); var process = new TestTileCacheMeshProcess();