mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-27 10:46:17 +00:00
提交Unity 联机Pro
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79f59c7bf226438cb591ec56fa35968f
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Colliders
|
||||
{
|
||||
public class DtBoxCollider : DtCollider
|
||||
{
|
||||
private readonly RcVec3f center;
|
||||
private readonly RcVec3f[] halfEdges;
|
||||
|
||||
public DtBoxCollider(RcVec3f center, RcVec3f[] halfEdges, int area, LFloat flagMergeThreshold) :
|
||||
base(area, flagMergeThreshold, Bounds(center, halfEdges))
|
||||
{
|
||||
this.center = center;
|
||||
this.halfEdges = halfEdges;
|
||||
}
|
||||
|
||||
private static LFloat[] Bounds(RcVec3f center, RcVec3f[] halfEdges)
|
||||
{
|
||||
LFloat[] bounds = new LFloat[]
|
||||
{
|
||||
LFloat.PositiveInfinity, LFloat.PositiveInfinity, LFloat.PositiveInfinity,
|
||||
LFloat.NegativeInfinity, LFloat.NegativeInfinity, LFloat.NegativeInfinity
|
||||
};
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
LFloat s0 = (i & 1) != 0 ? (LFloat)1f : -(LFloat)1f;
|
||||
LFloat s1 = (i & 2) != 0 ? (LFloat)1f : -(LFloat)1f;
|
||||
LFloat s2 = (i & 4) != 0 ? (LFloat)1f : -(LFloat)1f;
|
||||
LFloat vx = center.X + s0 * halfEdges[0].X + s1 * halfEdges[1].X + s2 * halfEdges[2].X;
|
||||
LFloat vy = center.Y + s0 * halfEdges[0].Y + s1 * halfEdges[1].Y + s2 * halfEdges[2].Y;
|
||||
LFloat vz = center.Z + s0 * halfEdges[0].Z + s1 * halfEdges[1].Z + s2 * halfEdges[2].Z;
|
||||
bounds[0] = LMath.Min(bounds[0], vx);
|
||||
bounds[1] = LMath.Min(bounds[1], vy);
|
||||
bounds[2] = LMath.Min(bounds[2], vz);
|
||||
bounds[3] = LMath.Max(bounds[3], vx);
|
||||
bounds[4] = LMath.Max(bounds[4], vy);
|
||||
bounds[5] = LMath.Max(bounds[5], vz);
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public override void Rasterize(RcHeightfield hf, RcContext context)
|
||||
{
|
||||
RcFilledVolumeRasterization.RasterizeBox(
|
||||
hf, center, halfEdges, area, (int)LMath.Floor(flagMergeThreshold / hf.ch), context);
|
||||
}
|
||||
|
||||
public static RcVec3f[] GetHalfEdges(RcVec3f up, RcVec3f forward, RcVec3f extent)
|
||||
{
|
||||
RcVec3f[] halfEdges =
|
||||
{
|
||||
RcVec3f.Zero,
|
||||
new RcVec3f(up.X, up.Y, up.Z),
|
||||
RcVec3f.Zero
|
||||
};
|
||||
|
||||
halfEdges[1] = RcVec3f.Normalize(halfEdges[1]);
|
||||
halfEdges[0] = RcVec3f.Cross(up, forward);
|
||||
halfEdges[0] = RcVec3f.Normalize(halfEdges[0]);
|
||||
halfEdges[2] = RcVec3f.Cross(halfEdges[0], up);
|
||||
halfEdges[2] = RcVec3f.Normalize(halfEdges[2]);
|
||||
halfEdges[0].X *= extent.X;
|
||||
halfEdges[0].Y *= extent.X;
|
||||
halfEdges[0].Z *= extent.X;
|
||||
halfEdges[1].X *= extent.Y;
|
||||
halfEdges[1].Y *= extent.Y;
|
||||
halfEdges[1].Z *= extent.Y;
|
||||
halfEdges[2].X *= extent.Z;
|
||||
halfEdges[2].Y *= extent.Z;
|
||||
halfEdges[2].Z *= extent.Z;
|
||||
return halfEdges;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 343af89640044ca4b578cf236fb94cf0
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Colliders
|
||||
{
|
||||
public class DtCapsuleCollider : DtCollider
|
||||
{
|
||||
private readonly RcVec3f start;
|
||||
private readonly RcVec3f end;
|
||||
private readonly LFloat radius;
|
||||
|
||||
public DtCapsuleCollider(RcVec3f start, RcVec3f end, LFloat radius, int area, LFloat flagMergeThreshold)
|
||||
: base(area, flagMergeThreshold, Bounds(start, end, radius))
|
||||
{
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public override void Rasterize(RcHeightfield hf, RcContext context)
|
||||
{
|
||||
RcFilledVolumeRasterization.RasterizeCapsule(hf, start, end, radius, area, (int)LMath.Floor(flagMergeThreshold / hf.ch), context);
|
||||
}
|
||||
|
||||
private static LFloat[] Bounds(RcVec3f start, RcVec3f end, LFloat radius)
|
||||
{
|
||||
return new LFloat[]
|
||||
{
|
||||
LMath.Min(start.X, end.X) - radius, LMath.Min(start.Y, end.Y) - radius,
|
||||
LMath.Min(start.Z, end.Z) - radius, LMath.Max(start.X, end.X) + radius, LMath.Max(start.Y, end.Y) + radius,
|
||||
LMath.Max(start.Z, end.Z) + radius
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 924df89ba25a438fbfbd934f761b814f
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 DotRecast.Core;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Colliders
|
||||
{
|
||||
public abstract class DtCollider : IDtCollider
|
||||
{
|
||||
protected readonly int area;
|
||||
protected readonly LFloat flagMergeThreshold;
|
||||
protected readonly LFloat[] _bounds;
|
||||
|
||||
public DtCollider(int area, LFloat flagMergeThreshold, LFloat[] bounds)
|
||||
{
|
||||
this.area = area;
|
||||
this.flagMergeThreshold = flagMergeThreshold;
|
||||
this._bounds = bounds;
|
||||
}
|
||||
|
||||
public LFloat[] Bounds()
|
||||
{
|
||||
return _bounds;
|
||||
}
|
||||
|
||||
public abstract void Rasterize(RcHeightfield hf, RcContext context);
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c681f6cb72b4f82b609ea36106f9fa5
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.Generic;
|
||||
using System.Linq;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Colliders
|
||||
{
|
||||
public class DtCompositeCollider : IDtCollider
|
||||
{
|
||||
private readonly List<IDtCollider> colliders;
|
||||
private readonly LFloat[] _bounds;
|
||||
|
||||
public DtCompositeCollider(List<IDtCollider> colliders)
|
||||
{
|
||||
this.colliders = colliders;
|
||||
_bounds = Bounds(colliders);
|
||||
}
|
||||
|
||||
public DtCompositeCollider(params IDtCollider[] colliders)
|
||||
{
|
||||
this.colliders = colliders.ToList();
|
||||
_bounds = Bounds(this.colliders);
|
||||
}
|
||||
|
||||
public LFloat[] Bounds()
|
||||
{
|
||||
return _bounds;
|
||||
}
|
||||
|
||||
private static LFloat[] Bounds(List<IDtCollider> colliders)
|
||||
{
|
||||
LFloat[] bounds = new LFloat[]
|
||||
{
|
||||
LFloat.PositiveInfinity, LFloat.PositiveInfinity, LFloat.PositiveInfinity,
|
||||
LFloat.NegativeInfinity, LFloat.NegativeInfinity, LFloat.NegativeInfinity
|
||||
};
|
||||
foreach (IDtCollider collider in colliders)
|
||||
{
|
||||
LFloat[] b = collider.Bounds();
|
||||
bounds[0] = LMath.Min(bounds[0], b[0]);
|
||||
bounds[1] = LMath.Min(bounds[1], b[1]);
|
||||
bounds[2] = LMath.Min(bounds[2], b[2]);
|
||||
bounds[3] = LMath.Max(bounds[3], b[3]);
|
||||
bounds[4] = LMath.Max(bounds[4], b[4]);
|
||||
bounds[5] = LMath.Max(bounds[5], b[5]);
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public void Rasterize(RcHeightfield hf, RcContext context)
|
||||
{
|
||||
foreach (var c in colliders)
|
||||
c.Rasterize(hf, context);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31c4e9ca0a634501bbd20a01e5ca00b6
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 DotRecast.Core;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Colliders
|
||||
{
|
||||
public class DtConvexTrimeshCollider : DtCollider
|
||||
{
|
||||
private readonly LFloat[] vertices;
|
||||
private readonly int[] triangles;
|
||||
|
||||
public DtConvexTrimeshCollider(LFloat[] vertices, int[] triangles, int area, LFloat flagMergeThreshold)
|
||||
: base(area, flagMergeThreshold, DtTrimeshCollider.ComputeBounds(vertices))
|
||||
{
|
||||
this.vertices = vertices;
|
||||
this.triangles = triangles;
|
||||
}
|
||||
|
||||
public DtConvexTrimeshCollider(LFloat[] vertices, int[] triangles, LFloat[] bounds, int area, LFloat flagMergeThreshold)
|
||||
: base(area, flagMergeThreshold, bounds)
|
||||
{
|
||||
this.vertices = vertices;
|
||||
this.triangles = triangles;
|
||||
}
|
||||
|
||||
public override void Rasterize(RcHeightfield hf, RcContext context)
|
||||
{
|
||||
RcFilledVolumeRasterization.RasterizeConvex(hf, vertices, triangles, area,
|
||||
(int)LMath.Floor(flagMergeThreshold / hf.ch), context);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc503c1503a240f7b8a23fc2b63eaa1d
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Colliders
|
||||
{
|
||||
public class DtCylinderCollider : DtCollider
|
||||
{
|
||||
private readonly RcVec3f start;
|
||||
private readonly RcVec3f end;
|
||||
private readonly LFloat radius;
|
||||
|
||||
public DtCylinderCollider(RcVec3f start, RcVec3f end, LFloat radius, int area, LFloat flagMergeThreshold) :
|
||||
base(area, flagMergeThreshold, Bounds(start, end, radius))
|
||||
{
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public override void Rasterize(RcHeightfield hf, RcContext context)
|
||||
{
|
||||
RcFilledVolumeRasterization.RasterizeCylinder(hf, start, end, radius, area, (int)LMath.Floor(flagMergeThreshold / hf.ch),
|
||||
context);
|
||||
}
|
||||
|
||||
private static LFloat[] Bounds(RcVec3f start, RcVec3f end, LFloat radius)
|
||||
{
|
||||
return new LFloat[]
|
||||
{
|
||||
LMath.Min(start.X, end.X) - radius, LMath.Min(start.Y, end.Y) - radius,
|
||||
LMath.Min(start.Z, end.Z) - radius, LMath.Max(start.X, end.X) + radius, LMath.Max(start.Y, end.Y) + radius,
|
||||
LMath.Max(start.Z, end.Z) + radius
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 826cab82648144898478cf98f9b1e40a
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Colliders
|
||||
{
|
||||
public class DtSphereCollider : DtCollider
|
||||
{
|
||||
private readonly RcVec3f center;
|
||||
private readonly LFloat radius;
|
||||
|
||||
public DtSphereCollider(RcVec3f center, LFloat radius, int area, LFloat flagMergeThreshold)
|
||||
: base(area, flagMergeThreshold, Bounds(center, radius))
|
||||
{
|
||||
this.center = center;
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public override void Rasterize(RcHeightfield hf, RcContext context)
|
||||
{
|
||||
RcFilledVolumeRasterization.RasterizeSphere(hf, center, radius, area, (int)LMath.Floor(flagMergeThreshold / hf.ch),
|
||||
context);
|
||||
}
|
||||
|
||||
private static LFloat[] Bounds(RcVec3f center, LFloat radius)
|
||||
{
|
||||
return new LFloat[]
|
||||
{
|
||||
center.X - radius,
|
||||
center.Y - radius,
|
||||
center.Z - radius,
|
||||
center.X + radius,
|
||||
center.Y + radius,
|
||||
center.Z + radius
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e353c1f8bfff4365acf828322df2a9df
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 DotRecast.Core;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Colliders
|
||||
{
|
||||
public class DtTrimeshCollider : DtCollider
|
||||
{
|
||||
private readonly LFloat[] vertices;
|
||||
private readonly int[] triangles;
|
||||
|
||||
public DtTrimeshCollider(LFloat[] vertices, int[] triangles, int area, LFloat flagMergeThreshold)
|
||||
: base(area, flagMergeThreshold, ComputeBounds(vertices))
|
||||
{
|
||||
this.vertices = vertices;
|
||||
this.triangles = triangles;
|
||||
}
|
||||
|
||||
public DtTrimeshCollider(LFloat[] vertices, int[] triangles, LFloat[] bounds, int area, LFloat flagMergeThreshold) :
|
||||
base(area, flagMergeThreshold, bounds)
|
||||
{
|
||||
this.vertices = vertices;
|
||||
this.triangles = triangles;
|
||||
}
|
||||
|
||||
public static LFloat[] ComputeBounds(LFloat[] vertices)
|
||||
{
|
||||
LFloat[] bounds = new LFloat[] { vertices[0], vertices[1], vertices[2], vertices[0], vertices[1], vertices[2] };
|
||||
for (int i = 3; i < vertices.Length; i += 3)
|
||||
{
|
||||
bounds[0] = LMath.Min(bounds[0], vertices[i]);
|
||||
bounds[1] = LMath.Min(bounds[1], vertices[i + 1]);
|
||||
bounds[2] = LMath.Min(bounds[2], vertices[i + 2]);
|
||||
bounds[3] = LMath.Max(bounds[3], vertices[i]);
|
||||
bounds[4] = LMath.Max(bounds[4], vertices[i + 1]);
|
||||
bounds[5] = LMath.Max(bounds[5], vertices[i + 2]);
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public override void Rasterize(RcHeightfield hf, RcContext context)
|
||||
{
|
||||
for (int i = 0; i < triangles.Length; i += 3)
|
||||
{
|
||||
RcRasterizations.RasterizeTriangle(context, vertices, triangles[i], triangles[i + 1], triangles[i + 2], area,
|
||||
hf, (int)LMath.Floor(flagMergeThreshold / hf.ch));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20a4ce560af24659b04a463f259e9114
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 DotRecast.Core;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Colliders
|
||||
{
|
||||
public interface IDtCollider
|
||||
{
|
||||
LFloat[] Bounds();
|
||||
void Rasterize(RcHeightfield hf, RcContext context);
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa31a946c5ba4ef0aacaa77e218527ad
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageId>DotRecast.Detour.Dynamic</PackageId>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<Authors>ikpil</Authors>
|
||||
<Description>DotRecast - a port of Recast Detour, Industry-standard navigation mesh toolset for .NET, C#, Unity3D, games, servers</Description>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
||||
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
||||
<PackageReleaseNotes>https://github.com/ikpil/DotRecast/blob/main/CHANGELOG.md</PackageReleaseNotes>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../../README.md" Pack="true" PackagePath="\"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DotRecast.Detour\DotRecast.Detour.csproj"/>
|
||||
<ProjectReference Include="..\DotRecast.Recast\DotRecast.Recast.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86271b6d8541401b9c49be9bfb02f251
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.Linq;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Detour.Dynamic.Colliders;
|
||||
using DotRecast.Detour.Dynamic.Io;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic
|
||||
{
|
||||
public class DtDynamicNavMesh
|
||||
{
|
||||
public const int MAX_VERTS_PER_POLY = 6;
|
||||
public readonly DtDynamicNavMeshConfig config;
|
||||
private readonly RcBuilder builder;
|
||||
private readonly Dictionary<long, DtDynamicTile> _tiles = new Dictionary<long, DtDynamicTile>();
|
||||
private readonly RcContext _context;
|
||||
private readonly DtNavMeshParams navMeshParams;
|
||||
private readonly BlockingCollection<IDtDaynmicTileJob> updateQueue = new BlockingCollection<IDtDaynmicTileJob>();
|
||||
private readonly RcAtomicLong currentColliderId = new RcAtomicLong(0);
|
||||
private DtNavMesh _navMesh;
|
||||
private bool _dirty = true;
|
||||
|
||||
public DtDynamicNavMesh(DtVoxelFile voxelFile)
|
||||
{
|
||||
config = new DtDynamicNavMeshConfig(voxelFile.useTiles, voxelFile.tileSizeX, voxelFile.tileSizeZ, voxelFile.cellSize);
|
||||
config.walkableHeight = voxelFile.walkableHeight;
|
||||
config.walkableRadius = voxelFile.walkableRadius;
|
||||
config.walkableClimb = voxelFile.walkableClimb;
|
||||
config.walkableSlopeAngle = voxelFile.walkableSlopeAngle;
|
||||
config.maxSimplificationError = voxelFile.maxSimplificationError;
|
||||
config.maxEdgeLen = voxelFile.maxEdgeLen;
|
||||
config.minRegionArea = voxelFile.minRegionArea;
|
||||
config.regionMergeArea = voxelFile.regionMergeArea;
|
||||
config.vertsPerPoly = voxelFile.vertsPerPoly;
|
||||
config.buildDetailMesh = voxelFile.buildMeshDetail;
|
||||
config.detailSampleDistance = voxelFile.detailSampleDistance;
|
||||
config.detailSampleMaxError = voxelFile.detailSampleMaxError;
|
||||
builder = new RcBuilder();
|
||||
navMeshParams = new DtNavMeshParams();
|
||||
navMeshParams.orig.X = voxelFile.bounds[0];
|
||||
navMeshParams.orig.Y = voxelFile.bounds[1];
|
||||
navMeshParams.orig.Z = voxelFile.bounds[2];
|
||||
navMeshParams.tileWidth = voxelFile.cellSize * voxelFile.tileSizeX;
|
||||
navMeshParams.tileHeight = voxelFile.cellSize * voxelFile.tileSizeZ;
|
||||
navMeshParams.maxTiles = voxelFile.tiles.Count;
|
||||
navMeshParams.maxPolys = 0x8000;
|
||||
foreach (var t in voxelFile.tiles)
|
||||
{
|
||||
_tiles.Add(LookupKey(t.tileX, t.tileZ), new DtDynamicTile(t));
|
||||
}
|
||||
|
||||
;
|
||||
_context = new RcContext();
|
||||
}
|
||||
|
||||
public DtNavMesh NavMesh()
|
||||
{
|
||||
return _navMesh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Voxel queries require checkpoints to be enabled in {@link DynamicNavMeshConfig}
|
||||
*/
|
||||
public DtVoxelQuery VoxelQuery()
|
||||
{
|
||||
return new DtVoxelQuery(navMeshParams.orig, navMeshParams.tileWidth, navMeshParams.tileHeight, LookupHeightfield);
|
||||
}
|
||||
|
||||
private RcHeightfield LookupHeightfield(int x, int z)
|
||||
{
|
||||
return GetTileAt(x, z)?.checkpoint.heightfield;
|
||||
}
|
||||
|
||||
public long AddCollider(IDtCollider collider)
|
||||
{
|
||||
long cid = currentColliderId.IncrementAndGet();
|
||||
updateQueue.Add(new DtDynamicTileColliderAdditionJob(cid, collider, GetTiles(collider.Bounds())));
|
||||
return cid;
|
||||
}
|
||||
|
||||
public void RemoveCollider(long colliderId)
|
||||
{
|
||||
updateQueue.Add(new DtDynamicTileColliderRemovalJob(colliderId, GetTilesByCollider(colliderId)));
|
||||
}
|
||||
|
||||
|
||||
private HashSet<DtDynamicTile> ProcessQueue()
|
||||
{
|
||||
var items = ConsumeQueue();
|
||||
foreach (var item in items)
|
||||
{
|
||||
Process(item);
|
||||
}
|
||||
|
||||
return items.SelectMany(i => i.AffectedTiles()).ToHashSet();
|
||||
}
|
||||
|
||||
private List<IDtDaynmicTileJob> ConsumeQueue()
|
||||
{
|
||||
List<IDtDaynmicTileJob> items = new List<IDtDaynmicTileJob>();
|
||||
while (updateQueue.TryTake(out var item))
|
||||
{
|
||||
items.Add(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private void Process(IDtDaynmicTileJob item)
|
||||
{
|
||||
foreach (var tile in item.AffectedTiles())
|
||||
{
|
||||
item.Process(tile);
|
||||
}
|
||||
}
|
||||
|
||||
// Perform full build of the navmesh
|
||||
public void Build()
|
||||
{
|
||||
ProcessQueue();
|
||||
Rebuild(_tiles.Values);
|
||||
}
|
||||
|
||||
// // Perform full build concurrently using the given {@link ExecutorService}
|
||||
// public bool Build(TaskFactory executor)
|
||||
// {
|
||||
// ProcessQueue();
|
||||
// return Rebuild(_tiles.Values, executor);
|
||||
// }
|
||||
|
||||
|
||||
// Perform incremental update of the navmesh
|
||||
public bool Update()
|
||||
{
|
||||
return Rebuild(ProcessQueue());
|
||||
}
|
||||
|
||||
// // Perform incremental update concurrently using the given {@link ExecutorService}
|
||||
// public bool Update(TaskFactory executor)
|
||||
// {
|
||||
// return Rebuild(ProcessQueue(), executor);
|
||||
// }
|
||||
|
||||
private bool Rebuild(ICollection<DtDynamicTile> tiles)
|
||||
{
|
||||
foreach (var tile in tiles)
|
||||
Rebuild(tile);
|
||||
|
||||
return UpdateNavMesh();
|
||||
}
|
||||
|
||||
// private bool Rebuild(ICollection<DtDynamicTile> tiles, TaskFactory executor)
|
||||
// {
|
||||
// var tasks = tiles
|
||||
// .Select(tile => executor.StartNew(() => Rebuild(tile)))
|
||||
// .ToArray();
|
||||
//
|
||||
// Task.WaitAll(tasks);
|
||||
// return UpdateNavMesh();
|
||||
// }
|
||||
|
||||
private ICollection<DtDynamicTile> GetTiles(LFloat[] bounds)
|
||||
{
|
||||
if (bounds == null)
|
||||
{
|
||||
return _tiles.Values;
|
||||
}
|
||||
|
||||
int minx = (int)LMath.Floor((bounds[0] - navMeshParams.orig.X) / navMeshParams.tileWidth);
|
||||
int minz = (int)LMath.Floor((bounds[2] - navMeshParams.orig.Z) / navMeshParams.tileHeight);
|
||||
int maxx = (int)LMath.Floor((bounds[3] - navMeshParams.orig.X) / navMeshParams.tileWidth);
|
||||
int maxz = (int)LMath.Floor((bounds[5] - navMeshParams.orig.Z) / navMeshParams.tileHeight);
|
||||
List<DtDynamicTile> tiles = new List<DtDynamicTile>();
|
||||
for (int z = minz; z <= maxz; ++z)
|
||||
{
|
||||
for (int x = minx; x <= maxx; ++x)
|
||||
{
|
||||
DtDynamicTile tile = GetTileAt(x, z);
|
||||
if (tile != null)
|
||||
{
|
||||
tiles.Add(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tiles;
|
||||
}
|
||||
|
||||
private List<DtDynamicTile> GetTilesByCollider(long cid)
|
||||
{
|
||||
return _tiles.Values.Where(t => t.ContainsCollider(cid)).ToList();
|
||||
}
|
||||
|
||||
private void Rebuild(DtDynamicTile tile)
|
||||
{
|
||||
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
|
||||
option.walkableHeight = config.walkableHeight;
|
||||
_dirty = _dirty | tile.Build(builder, config, _context);
|
||||
}
|
||||
|
||||
private bool UpdateNavMesh()
|
||||
{
|
||||
if (_dirty)
|
||||
{
|
||||
DtNavMesh navMesh = new DtNavMesh(navMeshParams, MAX_VERTS_PER_POLY);
|
||||
foreach (var t in _tiles.Values)
|
||||
t.AddTo(navMesh);
|
||||
|
||||
_navMesh = navMesh;
|
||||
_dirty = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private DtDynamicTile GetTileAt(int x, int z)
|
||||
{
|
||||
return _tiles.TryGetValue(LookupKey(x, z), out var tile)
|
||||
? tile
|
||||
: null;
|
||||
}
|
||||
|
||||
private long LookupKey(long x, long z)
|
||||
{
|
||||
return (z << 32) | x;
|
||||
}
|
||||
|
||||
public List<DtVoxelTile> VoxelTiles()
|
||||
{
|
||||
return _tiles.Values.Select(t => t.voxelTile).ToList();
|
||||
}
|
||||
|
||||
public List<RcBuilderResult> RecastResults()
|
||||
{
|
||||
return _tiles.Values.Select(t => t.recastResult).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46f1520fe06a45c4a8aa3b17ff69176f
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic
|
||||
{
|
||||
public class DtDynamicNavMeshConfig
|
||||
{
|
||||
public readonly bool useTiles;
|
||||
public readonly int tileSizeX;
|
||||
public readonly int tileSizeZ;
|
||||
public readonly LFloat cellSize;
|
||||
public int partition = RcPartitionType.WATERSHED.Value;
|
||||
public RcAreaModification walkableAreaModification = new RcAreaModification(1);
|
||||
public LFloat walkableHeight;
|
||||
public LFloat walkableSlopeAngle;
|
||||
public LFloat walkableRadius;
|
||||
public LFloat walkableClimb;
|
||||
public LFloat minRegionArea;
|
||||
public LFloat regionMergeArea;
|
||||
public LFloat maxEdgeLen;
|
||||
public LFloat maxSimplificationError;
|
||||
public int vertsPerPoly;
|
||||
public bool buildDetailMesh;
|
||||
public LFloat detailSampleDistance;
|
||||
public LFloat detailSampleMaxError;
|
||||
public bool filterLowHangingObstacles = true;
|
||||
public bool filterLedgeSpans = true;
|
||||
public bool filterWalkableLowHeightSpans = true;
|
||||
public bool enableCheckpoints = true;
|
||||
public bool keepIntermediateResults = false;
|
||||
|
||||
public DtDynamicNavMeshConfig(bool useTiles, int tileSizeX, int tileSizeZ, LFloat cellSize)
|
||||
{
|
||||
this.useTiles = useTiles;
|
||||
this.tileSizeX = tileSizeX;
|
||||
this.tileSizeZ = tileSizeZ;
|
||||
this.cellSize = cellSize;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9477363671ce4a1a8f959c610d76f4c4
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.Linq;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Collections;
|
||||
using DotRecast.Detour.Dynamic.Colliders;
|
||||
using DotRecast.Detour.Dynamic.Io;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic
|
||||
{
|
||||
public class DtDynamicTile
|
||||
{
|
||||
public readonly DtVoxelTile voxelTile;
|
||||
public DtDynamicTileCheckpoint checkpoint;
|
||||
public RcBuilderResult recastResult;
|
||||
private DtMeshData meshData;
|
||||
private readonly ConcurrentDictionary<long, IDtCollider> colliders = new ConcurrentDictionary<long, IDtCollider>();
|
||||
private bool dirty = true;
|
||||
private long id;
|
||||
|
||||
public DtDynamicTile(DtVoxelTile voxelTile)
|
||||
{
|
||||
this.voxelTile = voxelTile;
|
||||
}
|
||||
|
||||
public bool Build(RcBuilder builder, DtDynamicNavMeshConfig config, RcContext context)
|
||||
{
|
||||
if (dirty)
|
||||
{
|
||||
RcHeightfield heightfield = BuildHeightfield(config, context);
|
||||
RcBuilderResult r = BuildRecast(builder, config, voxelTile, heightfield, context);
|
||||
DtNavMeshCreateParams option = NavMeshCreateParams(voxelTile.tileX, voxelTile.tileZ, voxelTile.cellSize,
|
||||
voxelTile.cellHeight, config, r);
|
||||
meshData = DtNavMeshBuilder.CreateNavMeshData(option);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private RcHeightfield BuildHeightfield(DtDynamicNavMeshConfig config, RcContext context)
|
||||
{
|
||||
ICollection<long> rasterizedColliders = checkpoint != null
|
||||
? checkpoint.colliders as ICollection<long>
|
||||
: RcImmutableArray<long>.Empty;
|
||||
|
||||
RcHeightfield heightfield = checkpoint != null
|
||||
? checkpoint.heightfield
|
||||
: voxelTile.Heightfield();
|
||||
|
||||
foreach (var (cid, c) in colliders)
|
||||
{
|
||||
if (!rasterizedColliders.Contains(cid))
|
||||
{
|
||||
heightfield.bmax.Y = LMath.Max(heightfield.bmax.Y, c.Bounds()[4] + heightfield.ch * 2);
|
||||
c.Rasterize(heightfield, context);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.enableCheckpoints)
|
||||
{
|
||||
checkpoint = new DtDynamicTileCheckpoint(heightfield, colliders.Keys.ToHashSet());
|
||||
}
|
||||
|
||||
return heightfield;
|
||||
}
|
||||
|
||||
private RcBuilderResult BuildRecast(RcBuilder builder, DtDynamicNavMeshConfig config, DtVoxelTile vt,
|
||||
RcHeightfield heightfield, RcContext context)
|
||||
{
|
||||
RcConfig rcConfig = new RcConfig(
|
||||
config.useTiles, config.tileSizeX, config.tileSizeZ,
|
||||
vt.borderSize,
|
||||
RcPartitionType.OfValue(config.partition),
|
||||
vt.cellSize, vt.cellHeight,
|
||||
config.walkableSlopeAngle, config.walkableHeight, config.walkableRadius, config.walkableClimb,
|
||||
config.minRegionArea, config.regionMergeArea,
|
||||
config.maxEdgeLen, config.maxSimplificationError,
|
||||
LMath.Min(DtDynamicNavMesh.MAX_VERTS_PER_POLY, config.vertsPerPoly),
|
||||
config.detailSampleDistance, config.detailSampleMaxError,
|
||||
true, true, true, default, true);
|
||||
RcBuilderResult r = builder.Build(context, vt.tileX, vt.tileZ, null, rcConfig, heightfield, false);
|
||||
if (config.keepIntermediateResults)
|
||||
{
|
||||
recastResult = r;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public void AddCollider(long cid, IDtCollider 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 DtNavMeshCreateParams NavMeshCreateParams(int tilex, int tileZ, LFloat cellSize, LFloat cellHeight,
|
||||
DtDynamicNavMeshConfig config, RcBuilderResult rcResult)
|
||||
{
|
||||
RcPolyMesh m_pmesh = rcResult.Mesh;
|
||||
RcPolyMeshDetail m_dmesh = rcResult.MeshDetail;
|
||||
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
|
||||
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 LFloat[0];
|
||||
option.offMeshConRad = new LFloat[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(DtNavMesh navMesh)
|
||||
{
|
||||
if (meshData != null)
|
||||
{
|
||||
id = navMesh.AddTile(meshData, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
navMesh.RemoveTile(id);
|
||||
id = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3bd3585a21db4b3f8b529e903d4d5826
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.Collections.Generic;
|
||||
using DotRecast.Recast;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic
|
||||
{
|
||||
public class DtDynamicTileCheckpoint
|
||||
{
|
||||
public readonly RcHeightfield heightfield;
|
||||
public readonly ISet<long> colliders;
|
||||
|
||||
public DtDynamicTileCheckpoint(RcHeightfield heightfield, ISet<long> colliders)
|
||||
{
|
||||
this.colliders = colliders;
|
||||
this.heightfield = Clone(heightfield);
|
||||
}
|
||||
|
||||
private RcHeightfield Clone(RcHeightfield source)
|
||||
{
|
||||
RcHeightfield clone = new RcHeightfield(source.width, source.height, source.bmin, source.bmax, source.cs, source.ch, source.borderSize);
|
||||
for (int z = 0, pz = 0; z < source.height; z++, pz += source.width)
|
||||
{
|
||||
for (int x = 0; x < source.width; x++)
|
||||
{
|
||||
RcSpan span = source.spans[pz + x];
|
||||
RcSpan prevCopy = null;
|
||||
while (span != null)
|
||||
{
|
||||
RcSpan copy = new RcSpan();
|
||||
copy.smin = span.smin;
|
||||
copy.smax = span.smax;
|
||||
copy.area = span.area;
|
||||
if (prevCopy == null)
|
||||
{
|
||||
clone.spans[pz + x] = copy;
|
||||
}
|
||||
else
|
||||
{
|
||||
prevCopy.next = copy;
|
||||
}
|
||||
|
||||
prevCopy = copy;
|
||||
span = span.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 433b050e76494e05ba4a78341d616bce
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.Collections.Generic;
|
||||
using DotRecast.Detour.Dynamic.Colliders;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic
|
||||
{
|
||||
public class DtDynamicTileColliderAdditionJob : IDtDaynmicTileJob
|
||||
{
|
||||
private readonly long _colliderId;
|
||||
private readonly IDtCollider _collider;
|
||||
private readonly ICollection<DtDynamicTile> _affectedTiles;
|
||||
|
||||
public DtDynamicTileColliderAdditionJob(long colliderId, IDtCollider collider, ICollection<DtDynamicTile> affectedTiles)
|
||||
{
|
||||
_colliderId = colliderId;
|
||||
_collider = collider;
|
||||
_affectedTiles = affectedTiles;
|
||||
}
|
||||
|
||||
public ICollection<DtDynamicTile> AffectedTiles()
|
||||
{
|
||||
return _affectedTiles;
|
||||
}
|
||||
|
||||
public void Process(DtDynamicTile tile)
|
||||
{
|
||||
tile.AddCollider(_colliderId, _collider);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 821ca3ee2d4f4a8da6c669890af921d1
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic
|
||||
{
|
||||
public class DtDynamicTileColliderRemovalJob : IDtDaynmicTileJob
|
||||
{
|
||||
private readonly long colliderId;
|
||||
private readonly ICollection<DtDynamicTile> _affectedTiles;
|
||||
|
||||
public DtDynamicTileColliderRemovalJob(long colliderId, ICollection<DtDynamicTile> affectedTiles)
|
||||
{
|
||||
this.colliderId = colliderId;
|
||||
this._affectedTiles = affectedTiles;
|
||||
}
|
||||
|
||||
public ICollection<DtDynamicTile> AffectedTiles()
|
||||
{
|
||||
return _affectedTiles;
|
||||
}
|
||||
|
||||
public void Process(DtDynamicTile tile)
|
||||
{
|
||||
tile.RemoveCollider(colliderId);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1142016290a4504b0591f5107f13dd5
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic
|
||||
{
|
||||
/**
|
||||
* Voxel raycast based on the algorithm described in
|
||||
*
|
||||
* "A Fast Voxel Traversal Algorithm for Ray Tracing" by John Amanatides and Andrew Woo
|
||||
*/
|
||||
public class DtVoxelQuery
|
||||
{
|
||||
private readonly RcVec3f origin;
|
||||
private readonly LFloat tileWidth;
|
||||
private readonly LFloat tileDepth;
|
||||
private readonly Func<int, int, RcHeightfield> heightfieldProvider;
|
||||
|
||||
public DtVoxelQuery(RcVec3f origin, LFloat tileWidth, LFloat tileDepth, Func<int, int, RcHeightfield> heightfieldProvider)
|
||||
{
|
||||
this.origin = origin;
|
||||
this.tileWidth = tileWidth;
|
||||
this.tileDepth = tileDepth;
|
||||
this.heightfieldProvider = heightfieldProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform raycast using voxels heightfields.
|
||||
*
|
||||
* @return Optional with hit parameter (t) or empty if no hit found
|
||||
*/
|
||||
public bool Raycast(RcVec3f start, RcVec3f end, out LFloat hit)
|
||||
{
|
||||
return TraverseTiles(start, end, out hit);
|
||||
}
|
||||
|
||||
private bool TraverseTiles(RcVec3f start, RcVec3f end, out LFloat hit)
|
||||
{
|
||||
LFloat relStartX = start.X - origin.X;
|
||||
LFloat relStartZ = start.Z - origin.Z;
|
||||
int sx = (int)LMath.Floor(relStartX / tileWidth);
|
||||
int sz = (int)LMath.Floor(relStartZ / tileDepth);
|
||||
int ex = (int)LMath.Floor((end.X - origin.X) / tileWidth);
|
||||
int ez = (int)LMath.Floor((end.Z - origin.Z) / tileDepth);
|
||||
int dx = ex - sx;
|
||||
int dz = ez - sz;
|
||||
int stepX = dx < 0 ? -1 : 1;
|
||||
int stepZ = dz < 0 ? -1 : 1;
|
||||
LFloat xRem = (tileWidth + (relStartX % tileWidth)) % tileWidth;
|
||||
LFloat zRem = (tileDepth + (relStartZ % tileDepth)) % tileDepth;
|
||||
LFloat tx = end.X - start.X;
|
||||
LFloat tz = end.Z - start.Z;
|
||||
LFloat xOffest = LMath.Abs(tx < 0 ? xRem : tileWidth - xRem);
|
||||
LFloat zOffest = LMath.Abs(tz < 0 ? zRem : tileDepth - zRem);
|
||||
tx = LMath.Abs(tx);
|
||||
tz = LMath.Abs(tz);
|
||||
LFloat tMaxX = xOffest / tx;
|
||||
LFloat tMaxZ = zOffest / tz;
|
||||
LFloat tDeltaX = tileWidth / tx;
|
||||
LFloat tDeltaZ = tileDepth / tz;
|
||||
LFloat t = 0;
|
||||
while (true)
|
||||
{
|
||||
bool isHit = TraversHeightfield(sx, sz, start, end, t, LMath.Min(1, LMath.Min(tMaxX, tMaxZ)), out hit);
|
||||
if (isHit)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((dx > 0 ? sx >= ex : sx <= ex) && (dz > 0 ? sz >= ez : sz <= ez))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (tMaxX < tMaxZ)
|
||||
{
|
||||
t = tMaxX;
|
||||
tMaxX += tDeltaX;
|
||||
sx += stepX;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = tMaxZ;
|
||||
tMaxZ += tDeltaZ;
|
||||
sz += stepZ;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TraversHeightfield(int x, int z, RcVec3f start, RcVec3f end, LFloat tMin, LFloat tMax, out LFloat hit)
|
||||
{
|
||||
RcHeightfield hf = heightfieldProvider.Invoke(x, z);
|
||||
if (null != hf)
|
||||
{
|
||||
LFloat tx = end.X - start.X;
|
||||
LFloat ty = end.Y - start.Y;
|
||||
LFloat tz = end.Z - start.Z;
|
||||
LFloat[] entry = { start.X + tMin * tx, start.Y + tMin * ty, start.Z + tMin * tz };
|
||||
LFloat[] exit = { start.X + tMax * tx, start.Y + tMax * ty, start.Z + tMax * tz };
|
||||
LFloat relStartX = entry[0] - hf.bmin.X;
|
||||
LFloat relStartZ = entry[2] - hf.bmin.Z;
|
||||
int sx = (int)LMath.Floor(relStartX / hf.cs);
|
||||
int sz = (int)LMath.Floor(relStartZ / hf.cs);
|
||||
int ex = (int)LMath.Floor((exit[0] - hf.bmin.X) / hf.cs);
|
||||
int ez = (int)LMath.Floor((exit[2] - hf.bmin.Z) / hf.cs);
|
||||
int dx = ex - sx;
|
||||
int dz = ez - sz;
|
||||
int stepX = dx < 0 ? -1 : 1;
|
||||
int stepZ = dz < 0 ? -1 : 1;
|
||||
LFloat xRem = (hf.cs + (relStartX % hf.cs)) % hf.cs;
|
||||
LFloat zRem = (hf.cs + (relStartZ % hf.cs)) % hf.cs;
|
||||
LFloat xOffest = LMath.Abs(tx < 0 ? xRem : hf.cs - xRem);
|
||||
LFloat zOffest = LMath.Abs(tz < 0 ? zRem : hf.cs - zRem);
|
||||
tx = LMath.Abs(tx);
|
||||
tz = LMath.Abs(tz);
|
||||
LFloat tMaxX = xOffest / tx;
|
||||
LFloat tMaxZ = zOffest / tz;
|
||||
LFloat tDeltaX = hf.cs / tx;
|
||||
LFloat tDeltaZ = hf.cs / tz;
|
||||
LFloat t = 0;
|
||||
while (true)
|
||||
{
|
||||
if (sx >= 0 && sx < hf.width && sz >= 0 && sz < hf.height)
|
||||
{
|
||||
LFloat y1 = start.Y + ty * (tMin + t) - hf.bmin.Y;
|
||||
LFloat y2 = start.Y + ty * (tMin + LMath.Min(tMaxX, tMaxZ)) - hf.bmin.Y;
|
||||
LFloat ymin = LMath.Min(y1, y2) / hf.ch;
|
||||
LFloat ymax = LMath.Max(y1, y2) / hf.ch;
|
||||
RcSpan span = hf.spans[sx + sz * hf.width];
|
||||
while (span != null)
|
||||
{
|
||||
if (span.smin <= ymin && span.smax >= ymax)
|
||||
{
|
||||
hit = LMath.Min(1, tMin + t);
|
||||
return true;
|
||||
}
|
||||
|
||||
span = span.next;
|
||||
}
|
||||
}
|
||||
|
||||
if ((dx > 0 ? sx >= ex : sx <= ex) && (dz > 0 ? sz >= ez : sz <= ez))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (tMaxX < tMaxZ)
|
||||
{
|
||||
t = tMaxX;
|
||||
tMaxX += tDeltaX;
|
||||
sx += stepX;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = tMaxZ;
|
||||
tMaxZ += tDeltaZ;
|
||||
sz += stepZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hit = (LFloat)0.0f;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d08389815a14755ba38b1be514d5512
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic
|
||||
{
|
||||
public interface IDtDaynmicTileJob
|
||||
{
|
||||
ICollection<DtDynamicTile> AffectedTiles();
|
||||
|
||||
void Process(DtDynamicTile tile);
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48d1627002564821bcea618fe2973132
|
||||
timeCreated: 1715335340
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d0e9c4460604af49b11cd184bb1fdd4
|
||||
timeCreated: 1715335338
|
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.Generic;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Io
|
||||
{
|
||||
public class DtVoxelFile
|
||||
{
|
||||
public static readonly RcByteOrder PREFERRED_BYTE_ORDER = RcByteOrder.BIG_ENDIAN;
|
||||
public const int MAGIC = 'V' << 24 | 'O' << 16 | 'X' << 8 | 'L';
|
||||
public const int VERSION_EXPORTER_MASK = 0xF000;
|
||||
public const int VERSION_COMPRESSION_MASK = 0x0F00;
|
||||
public const int VERSION_EXPORTER_RECAST4J = 0x1000;
|
||||
public const int VERSION_COMPRESSION_LZ4 = 0x0100;
|
||||
public int version;
|
||||
public int partition = RcPartitionType.WATERSHED.Value;
|
||||
public bool filterLowHangingObstacles = true;
|
||||
public bool filterLedgeSpans = true;
|
||||
public bool filterWalkableLowHeightSpans = true;
|
||||
public LFloat walkableRadius;
|
||||
public LFloat walkableHeight;
|
||||
public LFloat walkableClimb;
|
||||
public LFloat walkableSlopeAngle;
|
||||
public LFloat cellSize;
|
||||
public LFloat maxSimplificationError;
|
||||
public LFloat maxEdgeLen;
|
||||
public LFloat minRegionArea;
|
||||
public LFloat regionMergeArea;
|
||||
public int vertsPerPoly;
|
||||
public bool buildMeshDetail;
|
||||
public LFloat detailSampleDistance;
|
||||
public LFloat detailSampleMaxError;
|
||||
public bool useTiles;
|
||||
public int tileSizeX;
|
||||
public int tileSizeZ;
|
||||
public RcVec3f rotation = new RcVec3f();
|
||||
public LFloat[] bounds = new LFloat[6];
|
||||
public readonly List<DtVoxelTile> tiles = new List<DtVoxelTile>();
|
||||
|
||||
public void AddTile(DtVoxelTile tile)
|
||||
{
|
||||
tiles.Add(tile);
|
||||
}
|
||||
|
||||
public RcConfig GetConfig(DtVoxelTile tile, RcAreaModification walkbableAreaMod, bool buildMeshDetail)
|
||||
{
|
||||
return new RcConfig(useTiles, tileSizeX, tileSizeZ,
|
||||
tile.borderSize,
|
||||
RcPartitionType.OfValue(partition),
|
||||
cellSize, tile.cellHeight,
|
||||
walkableSlopeAngle, walkableHeight, walkableRadius, walkableClimb,
|
||||
minRegionArea, regionMergeArea,
|
||||
maxEdgeLen, maxSimplificationError,
|
||||
vertsPerPoly,
|
||||
detailSampleDistance, detailSampleMaxError,
|
||||
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans,
|
||||
walkbableAreaMod, buildMeshDetail);
|
||||
}
|
||||
|
||||
public static DtVoxelFile From(RcConfig config, List<RcBuilderResult> results)
|
||||
{
|
||||
DtVoxelFile f = new DtVoxelFile();
|
||||
f.version = 1;
|
||||
f.partition = config.Partition;
|
||||
f.filterLowHangingObstacles = config.FilterLowHangingObstacles;
|
||||
f.filterLedgeSpans = config.FilterLedgeSpans;
|
||||
f.filterWalkableLowHeightSpans = config.FilterWalkableLowHeightSpans;
|
||||
f.walkableRadius = config.WalkableRadiusWorld;
|
||||
f.walkableHeight = config.WalkableHeightWorld;
|
||||
f.walkableClimb = config.WalkableClimbWorld;
|
||||
f.walkableSlopeAngle = config.WalkableSlopeAngle;
|
||||
f.cellSize = config.Cs;
|
||||
f.maxSimplificationError = config.MaxSimplificationError;
|
||||
f.maxEdgeLen = config.MaxEdgeLenWorld;
|
||||
f.minRegionArea = config.MinRegionAreaWorld;
|
||||
f.regionMergeArea = config.MergeRegionAreaWorld;
|
||||
f.vertsPerPoly = config.MaxVertsPerPoly;
|
||||
f.buildMeshDetail = config.BuildMeshDetail;
|
||||
f.detailSampleDistance = config.DetailSampleDist;
|
||||
f.detailSampleMaxError = config.DetailSampleMaxError;
|
||||
f.useTiles = config.UseTiles;
|
||||
f.tileSizeX = config.TileSizeX;
|
||||
f.tileSizeZ = config.TileSizeZ;
|
||||
f.bounds = new LFloat[]
|
||||
{
|
||||
LFloat.PositiveInfinity, LFloat.PositiveInfinity, LFloat.PositiveInfinity,
|
||||
LFloat.NegativeInfinity, LFloat.NegativeInfinity, LFloat.NegativeInfinity
|
||||
};
|
||||
foreach (RcBuilderResult r in results)
|
||||
{
|
||||
f.tiles.Add(new DtVoxelTile(r.TileX, r.TileZ, r.SolidHeightfiled));
|
||||
f.bounds[0] = LMath.Min(f.bounds[0], r.SolidHeightfiled.bmin.X);
|
||||
f.bounds[1] = LMath.Min(f.bounds[1], r.SolidHeightfiled.bmin.Y);
|
||||
f.bounds[2] = LMath.Min(f.bounds[2], r.SolidHeightfiled.bmin.Z);
|
||||
f.bounds[3] = LMath.Max(f.bounds[3], r.SolidHeightfiled.bmax.X);
|
||||
f.bounds[4] = LMath.Max(f.bounds[4], r.SolidHeightfiled.bmax.Y);
|
||||
f.bounds[5] = LMath.Max(f.bounds[5], r.SolidHeightfiled.bmax.Z);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
public static DtVoxelFile From(DtDynamicNavMesh mesh)
|
||||
{
|
||||
DtVoxelFile f = new DtVoxelFile();
|
||||
f.version = 1;
|
||||
DtDynamicNavMeshConfig config = mesh.config;
|
||||
f.partition = config.partition;
|
||||
f.filterLowHangingObstacles = config.filterLowHangingObstacles;
|
||||
f.filterLedgeSpans = config.filterLedgeSpans;
|
||||
f.filterWalkableLowHeightSpans = config.filterWalkableLowHeightSpans;
|
||||
f.walkableRadius = config.walkableRadius;
|
||||
f.walkableHeight = config.walkableHeight;
|
||||
f.walkableClimb = config.walkableClimb;
|
||||
f.walkableSlopeAngle = config.walkableSlopeAngle;
|
||||
f.cellSize = config.cellSize;
|
||||
f.maxSimplificationError = config.maxSimplificationError;
|
||||
f.maxEdgeLen = config.maxEdgeLen;
|
||||
f.minRegionArea = config.minRegionArea;
|
||||
f.regionMergeArea = config.regionMergeArea;
|
||||
f.vertsPerPoly = config.vertsPerPoly;
|
||||
f.buildMeshDetail = config.buildDetailMesh;
|
||||
f.detailSampleDistance = config.detailSampleDistance;
|
||||
f.detailSampleMaxError = config.detailSampleMaxError;
|
||||
f.useTiles = config.useTiles;
|
||||
f.tileSizeX = config.tileSizeX;
|
||||
f.tileSizeZ = config.tileSizeZ;
|
||||
f.bounds = new LFloat[]
|
||||
{
|
||||
LFloat.PositiveInfinity, LFloat.PositiveInfinity, LFloat.PositiveInfinity,
|
||||
LFloat.NegativeInfinity, LFloat.NegativeInfinity, LFloat.NegativeInfinity
|
||||
};
|
||||
foreach (DtVoxelTile vt in mesh.VoxelTiles())
|
||||
{
|
||||
RcHeightfield heightfield = vt.Heightfield();
|
||||
f.tiles.Add(new DtVoxelTile(vt.tileX, vt.tileZ, heightfield));
|
||||
f.bounds[0] = LMath.Min(f.bounds[0], vt.boundsMin.X);
|
||||
f.bounds[1] = LMath.Min(f.bounds[1], vt.boundsMin.Y);
|
||||
f.bounds[2] = LMath.Min(f.bounds[2], vt.boundsMin.Z);
|
||||
f.bounds[3] = LMath.Max(f.bounds[3], vt.boundsMax.X);
|
||||
f.bounds[4] = LMath.Max(f.bounds[4], vt.boundsMax.Y);
|
||||
f.bounds[5] = LMath.Max(f.bounds[5], vt.boundsMax.Z);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd9487a5961c425eb87ca603c28fec15
|
||||
timeCreated: 1715335338
|
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.IO;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Detour.Io;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Io
|
||||
{
|
||||
public class DtVoxelFileReader
|
||||
{
|
||||
private readonly IRcCompressor _compressor;
|
||||
|
||||
public DtVoxelFileReader(IRcCompressor compressor)
|
||||
{
|
||||
_compressor = compressor;
|
||||
}
|
||||
|
||||
public DtVoxelFile Read(BinaryReader stream)
|
||||
{
|
||||
RcByteBuffer buf = IOUtils.ToByteBuffer(stream);
|
||||
DtVoxelFile file = new DtVoxelFile();
|
||||
int magic = buf.GetInt();
|
||||
if (magic != DtVoxelFile.MAGIC)
|
||||
{
|
||||
magic = IOUtils.SwapEndianness(magic);
|
||||
if (magic != DtVoxelFile.MAGIC)
|
||||
{
|
||||
throw new IOException("Invalid magic");
|
||||
}
|
||||
|
||||
buf.Order(buf.Order() == RcByteOrder.BIG_ENDIAN ? RcByteOrder.LITTLE_ENDIAN : RcByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
file.version = buf.GetInt();
|
||||
bool isExportedFromAstar = (file.version & DtVoxelFile.VERSION_EXPORTER_MASK) == 0;
|
||||
bool compression = (file.version & DtVoxelFile.VERSION_COMPRESSION_MASK) == DtVoxelFile.VERSION_COMPRESSION_LZ4;
|
||||
file.walkableRadius = buf.GetFloat();
|
||||
file.walkableHeight = buf.GetFloat();
|
||||
file.walkableClimb = buf.GetFloat();
|
||||
file.walkableSlopeAngle = buf.GetFloat();
|
||||
file.cellSize = buf.GetFloat();
|
||||
file.maxSimplificationError = buf.GetFloat();
|
||||
file.maxEdgeLen = buf.GetFloat();
|
||||
file.minRegionArea = (int)buf.GetFloat();
|
||||
if (!isExportedFromAstar)
|
||||
{
|
||||
file.regionMergeArea = buf.GetFloat();
|
||||
file.vertsPerPoly = buf.GetInt();
|
||||
file.buildMeshDetail = buf.Get() != 0;
|
||||
file.detailSampleDistance = buf.GetFloat();
|
||||
file.detailSampleMaxError = buf.GetFloat();
|
||||
}
|
||||
else
|
||||
{
|
||||
file.regionMergeArea = 6 * file.minRegionArea;
|
||||
file.vertsPerPoly = 6;
|
||||
file.buildMeshDetail = true;
|
||||
file.detailSampleDistance = file.maxEdgeLen * (LFloat)0.5f;
|
||||
file.detailSampleMaxError = file.maxSimplificationError * (LFloat)0.8f;
|
||||
}
|
||||
|
||||
file.useTiles = buf.Get() != 0;
|
||||
file.tileSizeX = buf.GetInt();
|
||||
file.tileSizeZ = buf.GetInt();
|
||||
file.rotation.X = buf.GetFloat();
|
||||
file.rotation.Y = buf.GetFloat();
|
||||
file.rotation.Z = buf.GetFloat();
|
||||
file.bounds[0] = buf.GetFloat();
|
||||
file.bounds[1] = buf.GetFloat();
|
||||
file.bounds[2] = buf.GetFloat();
|
||||
file.bounds[3] = buf.GetFloat();
|
||||
file.bounds[4] = buf.GetFloat();
|
||||
file.bounds[5] = buf.GetFloat();
|
||||
if (isExportedFromAstar)
|
||||
{
|
||||
// bounds are saved as center + size
|
||||
file.bounds[0] -= (LFloat)0.5f * file.bounds[3];
|
||||
file.bounds[1] -= (LFloat)0.5f * file.bounds[4];
|
||||
file.bounds[2] -= (LFloat)0.5f * file.bounds[5];
|
||||
file.bounds[3] += file.bounds[0];
|
||||
file.bounds[4] += file.bounds[1];
|
||||
file.bounds[5] += file.bounds[2];
|
||||
}
|
||||
|
||||
int tileCount = buf.GetInt();
|
||||
for (int tile = 0; tile < tileCount; tile++)
|
||||
{
|
||||
int tileX = buf.GetInt();
|
||||
int tileZ = buf.GetInt();
|
||||
int width = buf.GetInt();
|
||||
int depth = buf.GetInt();
|
||||
int borderSize = buf.GetInt();
|
||||
RcVec3f boundsMin = new RcVec3f();
|
||||
boundsMin.X = buf.GetFloat();
|
||||
boundsMin.Y = buf.GetFloat();
|
||||
boundsMin.Z = buf.GetFloat();
|
||||
RcVec3f boundsMax = new RcVec3f();
|
||||
boundsMax.X = buf.GetFloat();
|
||||
boundsMax.Y = buf.GetFloat();
|
||||
boundsMax.Z = buf.GetFloat();
|
||||
if (isExportedFromAstar)
|
||||
{
|
||||
// bounds are local
|
||||
boundsMin.X += file.bounds[0];
|
||||
boundsMin.Y += file.bounds[1];
|
||||
boundsMin.Z += file.bounds[2];
|
||||
boundsMax.X += file.bounds[0];
|
||||
boundsMax.Y += file.bounds[1];
|
||||
boundsMax.Z += file.bounds[2];
|
||||
}
|
||||
|
||||
LFloat cellSize = buf.GetFloat();
|
||||
LFloat cellHeight = buf.GetFloat();
|
||||
int voxelSize = buf.GetInt();
|
||||
int position = buf.Position();
|
||||
byte[] bytes = buf.ReadBytes(voxelSize).ToArray();
|
||||
if (compression)
|
||||
{
|
||||
bytes = _compressor.Decompress(bytes);
|
||||
}
|
||||
|
||||
RcByteBuffer data = new RcByteBuffer(bytes);
|
||||
data.Order(buf.Order());
|
||||
file.AddTile(new DtVoxelTile(tileX, tileZ, width, depth, boundsMin, boundsMax, cellSize, cellHeight, borderSize, data));
|
||||
buf.Position(position + voxelSize);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd66a05921a942558006c63396be5407
|
||||
timeCreated: 1715335338
|
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.IO;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Detour.Io;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Io
|
||||
{
|
||||
public class DtVoxelFileWriter : DtWriter
|
||||
{
|
||||
private readonly IRcCompressor _compressor;
|
||||
|
||||
public DtVoxelFileWriter(IRcCompressor compressor)
|
||||
{
|
||||
_compressor = compressor;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter stream, DtVoxelFile f, bool compression)
|
||||
{
|
||||
Write(stream, f, DtVoxelFile.PREFERRED_BYTE_ORDER, compression);
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter stream, DtVoxelFile f, RcByteOrder byteOrder, bool compression)
|
||||
{
|
||||
Write(stream, DtVoxelFile.MAGIC, byteOrder);
|
||||
Write(stream, DtVoxelFile.VERSION_EXPORTER_RECAST4J | (compression ? DtVoxelFile.VERSION_COMPRESSION_LZ4 : 0), byteOrder);
|
||||
Write(stream, f.walkableRadius, byteOrder);
|
||||
Write(stream, f.walkableHeight, byteOrder);
|
||||
Write(stream, f.walkableClimb, byteOrder);
|
||||
Write(stream, f.walkableSlopeAngle, byteOrder);
|
||||
Write(stream, f.cellSize, byteOrder);
|
||||
Write(stream, f.maxSimplificationError, byteOrder);
|
||||
Write(stream, f.maxEdgeLen, byteOrder);
|
||||
Write(stream, f.minRegionArea, byteOrder);
|
||||
Write(stream, f.regionMergeArea, byteOrder);
|
||||
Write(stream, f.vertsPerPoly, byteOrder);
|
||||
Write(stream, f.buildMeshDetail);
|
||||
Write(stream, f.detailSampleDistance, byteOrder);
|
||||
Write(stream, f.detailSampleMaxError, byteOrder);
|
||||
Write(stream, f.useTiles);
|
||||
Write(stream, f.tileSizeX, byteOrder);
|
||||
Write(stream, f.tileSizeZ, byteOrder);
|
||||
Write(stream, f.rotation.X, byteOrder);
|
||||
Write(stream, f.rotation.Y, byteOrder);
|
||||
Write(stream, f.rotation.Z, byteOrder);
|
||||
Write(stream, f.bounds[0], byteOrder);
|
||||
Write(stream, f.bounds[1], byteOrder);
|
||||
Write(stream, f.bounds[2], byteOrder);
|
||||
Write(stream, f.bounds[3], byteOrder);
|
||||
Write(stream, f.bounds[4], byteOrder);
|
||||
Write(stream, f.bounds[5], byteOrder);
|
||||
Write(stream, f.tiles.Count, byteOrder);
|
||||
foreach (DtVoxelTile t in f.tiles)
|
||||
{
|
||||
WriteTile(stream, t, byteOrder, compression);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteTile(BinaryWriter stream, DtVoxelTile tile, RcByteOrder byteOrder, bool compression)
|
||||
{
|
||||
Write(stream, tile.tileX, byteOrder);
|
||||
Write(stream, tile.tileZ, byteOrder);
|
||||
Write(stream, tile.width, byteOrder);
|
||||
Write(stream, tile.depth, byteOrder);
|
||||
Write(stream, tile.borderSize, byteOrder);
|
||||
Write(stream, tile.boundsMin.X, byteOrder);
|
||||
Write(stream, tile.boundsMin.Y, byteOrder);
|
||||
Write(stream, tile.boundsMin.Z, byteOrder);
|
||||
Write(stream, tile.boundsMax.X, byteOrder);
|
||||
Write(stream, tile.boundsMax.Y, byteOrder);
|
||||
Write(stream, tile.boundsMax.Z, byteOrder);
|
||||
Write(stream, tile.cellSize, byteOrder);
|
||||
Write(stream, tile.cellHeight, byteOrder);
|
||||
byte[] bytes = tile.spanData;
|
||||
if (compression)
|
||||
{
|
||||
bytes = _compressor.Compress(bytes);
|
||||
}
|
||||
|
||||
Write(stream, bytes.Length, byteOrder);
|
||||
stream.Write(bytes);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2bbfda0005f432cb0c8d78264f6cf82
|
||||
timeCreated: 1715335338
|
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Io
|
||||
{
|
||||
public class DtVoxelTile
|
||||
{
|
||||
private const int SERIALIZED_SPAN_COUNT_BYTES = 2;
|
||||
private const int SERIALIZED_SPAN_BYTES = 12;
|
||||
public readonly int tileX;
|
||||
public readonly int tileZ;
|
||||
public readonly int borderSize;
|
||||
public int width;
|
||||
public int depth;
|
||||
public readonly RcVec3f boundsMin;
|
||||
public RcVec3f boundsMax;
|
||||
public LFloat cellSize;
|
||||
public LFloat cellHeight;
|
||||
public readonly byte[] spanData;
|
||||
|
||||
public DtVoxelTile(int tileX, int tileZ, int width, int depth, RcVec3f boundsMin, RcVec3f boundsMax, LFloat cellSize,
|
||||
LFloat cellHeight, int borderSize, RcByteBuffer buffer)
|
||||
{
|
||||
this.tileX = tileX;
|
||||
this.tileZ = tileZ;
|
||||
this.width = width;
|
||||
this.depth = depth;
|
||||
this.boundsMin = boundsMin;
|
||||
this.boundsMax = boundsMax;
|
||||
this.cellSize = cellSize;
|
||||
this.cellHeight = cellHeight;
|
||||
this.borderSize = borderSize;
|
||||
spanData = ToByteArray(buffer, width, depth, DtVoxelFile.PREFERRED_BYTE_ORDER);
|
||||
}
|
||||
|
||||
public DtVoxelTile(int tileX, int tileZ, RcHeightfield heightfield)
|
||||
{
|
||||
this.tileX = tileX;
|
||||
this.tileZ = tileZ;
|
||||
width = heightfield.width;
|
||||
depth = heightfield.height;
|
||||
boundsMin = heightfield.bmin;
|
||||
boundsMax = heightfield.bmax;
|
||||
cellSize = heightfield.cs;
|
||||
cellHeight = heightfield.ch;
|
||||
borderSize = heightfield.borderSize;
|
||||
spanData = SerializeSpans(heightfield, DtVoxelFile.PREFERRED_BYTE_ORDER);
|
||||
}
|
||||
|
||||
public RcHeightfield Heightfield()
|
||||
{
|
||||
return DtVoxelFile.PREFERRED_BYTE_ORDER == RcByteOrder.BIG_ENDIAN ? HeightfieldBE() : HeightfieldLE();
|
||||
}
|
||||
|
||||
private RcHeightfield HeightfieldBE()
|
||||
{
|
||||
RcHeightfield hf = new RcHeightfield(width, depth, boundsMin, boundsMax, cellSize, cellHeight, borderSize);
|
||||
int position = 0;
|
||||
for (int z = 0, pz = 0; z < depth; z++, pz += width)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
RcSpan prev = null;
|
||||
int spanCount = RcByteUtils.GetShortBE(spanData, position);
|
||||
position += 2;
|
||||
for (int s = 0; s < spanCount; s++)
|
||||
{
|
||||
RcSpan span = new RcSpan();
|
||||
span.smin = RcByteUtils.GetIntBE(spanData, position);
|
||||
position += 4;
|
||||
span.smax = RcByteUtils.GetIntBE(spanData, position);
|
||||
position += 4;
|
||||
span.area = RcByteUtils.GetIntBE(spanData, position);
|
||||
position += 4;
|
||||
if (prev == null)
|
||||
{
|
||||
hf.spans[pz + x] = span;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev.next = span;
|
||||
}
|
||||
|
||||
prev = span;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hf;
|
||||
}
|
||||
|
||||
private RcHeightfield HeightfieldLE()
|
||||
{
|
||||
RcHeightfield hf = new RcHeightfield(width, depth, boundsMin, boundsMax, cellSize, cellHeight, borderSize);
|
||||
int position = 0;
|
||||
for (int z = 0, pz = 0; z < depth; z++, pz += width)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
RcSpan prev = null;
|
||||
int spanCount = RcByteUtils.GetShortLE(spanData, position);
|
||||
position += 2;
|
||||
for (int s = 0; s < spanCount; s++)
|
||||
{
|
||||
RcSpan span = new RcSpan();
|
||||
span.smin = RcByteUtils.GetIntLE(spanData, position);
|
||||
position += 4;
|
||||
span.smax = RcByteUtils.GetIntLE(spanData, position);
|
||||
position += 4;
|
||||
span.area = RcByteUtils.GetIntLE(spanData, position);
|
||||
position += 4;
|
||||
if (prev == null)
|
||||
{
|
||||
hf.spans[pz + x] = span;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev.next = span;
|
||||
}
|
||||
|
||||
prev = span;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hf;
|
||||
}
|
||||
|
||||
private byte[] SerializeSpans(RcHeightfield heightfield, RcByteOrder order)
|
||||
{
|
||||
int[] counts = new int[heightfield.width * heightfield.height];
|
||||
int totalCount = 0;
|
||||
for (int z = 0, pz = 0; z < heightfield.height; z++, pz += heightfield.width)
|
||||
{
|
||||
for (int x = 0; x < heightfield.width; x++)
|
||||
{
|
||||
RcSpan span = heightfield.spans[pz + x];
|
||||
while (span != null)
|
||||
{
|
||||
counts[pz + x]++;
|
||||
totalCount++;
|
||||
span = span.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte[] data = new byte[totalCount * SERIALIZED_SPAN_BYTES + counts.Length * SERIALIZED_SPAN_COUNT_BYTES];
|
||||
int position = 0;
|
||||
for (int z = 0, pz = 0; z < heightfield.height; z++, pz += heightfield.width)
|
||||
{
|
||||
for (int x = 0; x < heightfield.width; x++)
|
||||
{
|
||||
position = RcByteUtils.PutShort(counts[pz + x], data, position, order);
|
||||
RcSpan span = heightfield.spans[pz + x];
|
||||
while (span != null)
|
||||
{
|
||||
position = RcByteUtils.PutInt(span.smin, data, position, order);
|
||||
position = RcByteUtils.PutInt(span.smax, data, position, order);
|
||||
position = RcByteUtils.PutInt(span.area, data, position, order);
|
||||
span = span.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private byte[] ToByteArray(RcByteBuffer buf, int width, int height, RcByteOrder order)
|
||||
{
|
||||
byte[] data;
|
||||
if (buf.Order() == order)
|
||||
{
|
||||
data = buf.ReadBytes(buf.Limit()).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
data = new byte[buf.Limit()];
|
||||
int l = width * height;
|
||||
int position = 0;
|
||||
for (int i = 0; i < l; i++)
|
||||
{
|
||||
int count = buf.GetShort();
|
||||
RcByteUtils.PutShort(count, data, position, order);
|
||||
position += 2;
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
RcByteUtils.PutInt(buf.GetInt(), data, position, order);
|
||||
position += 4;
|
||||
RcByteUtils.PutInt(buf.GetInt(), data, position, order);
|
||||
position += 4;
|
||||
RcByteUtils.PutInt(buf.GetInt(), data, position, order);
|
||||
position += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91a85b5d1fb946a2ba40c5fa9695644d
|
||||
timeCreated: 1715335338
|
Reference in New Issue
Block a user