C# style function name

This commit is contained in:
ikpil 2023-05-05 08:44:48 +09:00
parent bef429e5dc
commit ded8f33ac1
229 changed files with 5832 additions and 5830 deletions

View File

@ -6,12 +6,12 @@ namespace DotRecast.Core
{ {
private volatile int _location; private volatile int _location;
public bool set(bool v) public bool Set(bool v)
{ {
return 0 != Interlocked.Exchange(ref _location, v ? 1 : 0); return 0 != Interlocked.Exchange(ref _location, v ? 1 : 0);
} }
public bool get() public bool Get()
{ {
return 0 != _location; return 0 != _location;
} }

View File

@ -19,34 +19,34 @@ namespace DotRecast.Core
_position = 0; _position = 0;
} }
public ByteOrder order() public ByteOrder Order()
{ {
return _order; return _order;
} }
public void order(ByteOrder order) public void Order(ByteOrder order)
{ {
_order = order; _order = order;
} }
public int limit() public int Limit()
{ {
return _bytes.Length - _position; return _bytes.Length - _position;
} }
public int remaining() public int Remaining()
{ {
int rem = limit(); int rem = Limit();
return rem > 0 ? rem : 0; return rem > 0 ? rem : 0;
} }
public void position(int pos) public void Position(int pos)
{ {
_position = pos; _position = pos;
} }
public int position() public int Position()
{ {
return _position; return _position;
} }
@ -59,13 +59,13 @@ namespace DotRecast.Core
return _bytes.AsSpan(nextPos, length); return _bytes.AsSpan(nextPos, length);
} }
public byte get() public byte Get()
{ {
var span = ReadBytes(1); var span = ReadBytes(1);
return span[0]; return span[0];
} }
public short getShort() public short GetShort()
{ {
var span = ReadBytes(2); var span = ReadBytes(2);
if (_order == ByteOrder.BIG_ENDIAN) if (_order == ByteOrder.BIG_ENDIAN)
@ -79,7 +79,7 @@ namespace DotRecast.Core
} }
public int getInt() public int GetInt()
{ {
var span = ReadBytes(4); var span = ReadBytes(4);
if (_order == ByteOrder.BIG_ENDIAN) if (_order == ByteOrder.BIG_ENDIAN)
@ -92,7 +92,7 @@ namespace DotRecast.Core
} }
} }
public float getFloat() public float GetFloat()
{ {
var span = ReadBytes(4); var span = ReadBytes(4);
if (_order == ByteOrder.BIG_ENDIAN && BitConverter.IsLittleEndian) if (_order == ByteOrder.BIG_ENDIAN && BitConverter.IsLittleEndian)
@ -107,7 +107,7 @@ namespace DotRecast.Core
return BitConverter.ToSingle(span); return BitConverter.ToSingle(span);
} }
public long getLong() public long GetLong()
{ {
var span = ReadBytes(8); var span = ReadBytes(8);
if (_order == ByteOrder.BIG_ENDIAN) if (_order == ByteOrder.BIG_ENDIAN)
@ -120,7 +120,7 @@ namespace DotRecast.Core
} }
} }
public void putFloat(float v) public void PutFloat(float v)
{ {
// if (_order == ByteOrder.BIG_ENDIAN) // if (_order == ByteOrder.BIG_ENDIAN)
// { // {
@ -134,7 +134,7 @@ namespace DotRecast.Core
// ? // ?
} }
public void putInt(int v) public void PutInt(int v)
{ {
// ? // ?
} }

View File

@ -5,7 +5,7 @@ namespace DotRecast.Core
{ {
public static class CollectionExtensions public static class CollectionExtensions
{ {
public static void forEach<T>(this IEnumerable<T> collection, Action<T> action) public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
{ {
foreach (var item in collection) foreach (var item in collection)
{ {

View File

@ -25,7 +25,7 @@ namespace DotRecast.Core
// Calculates convex hull on xz-plane of points on 'pts', // Calculates convex hull on xz-plane of points on 'pts',
// stores the indices of the resulting hull in 'out' and // stores the indices of the resulting hull in 'out' and
// returns number of points on hull. // returns number of points on hull.
public static List<int> convexhull(List<float> pts) public static List<int> Convexhull(List<float> pts)
{ {
int npts = pts.Count / 3; int npts = pts.Count / 3;
List<int> @out = new List<int>(); List<int> @out = new List<int>();
@ -35,7 +35,7 @@ namespace DotRecast.Core
{ {
Vector3f a = Vector3f.Of(pts[i * 3], pts[i * 3 + 1], pts[i * 3 + 2]); Vector3f a = Vector3f.Of(pts[i * 3], pts[i * 3 + 1], pts[i * 3 + 2]);
Vector3f b = Vector3f.Of(pts[hull * 3], pts[hull * 3 + 1], pts[hull * 3 + 2]); Vector3f b = Vector3f.Of(pts[hull * 3], pts[hull * 3 + 1], pts[hull * 3 + 2]);
if (cmppt(a, b)) if (Cmppt(a, b))
{ {
hull = i; hull = i;
} }
@ -52,7 +52,7 @@ namespace DotRecast.Core
Vector3f a = Vector3f.Of(pts[hull * 3], pts[hull * 3 + 1], pts[hull * 3 + 2]); Vector3f a = Vector3f.Of(pts[hull * 3], pts[hull * 3 + 1], pts[hull * 3 + 2]);
Vector3f b = Vector3f.Of(pts[endpt * 3], pts[endpt * 3 + 1], pts[endpt * 3 + 2]); Vector3f b = Vector3f.Of(pts[endpt * 3], pts[endpt * 3 + 1], pts[endpt * 3 + 2]);
Vector3f c = Vector3f.Of(pts[j * 3], pts[j * 3 + 1], pts[j * 3 + 2]); Vector3f c = Vector3f.Of(pts[j * 3], pts[j * 3 + 1], pts[j * 3 + 2]);
if (hull == endpt || left(a, b, c)) if (hull == endpt || Left(a, b, c))
{ {
endpt = j; endpt = j;
} }
@ -65,7 +65,7 @@ namespace DotRecast.Core
} }
// Returns true if 'a' is more lower-left than 'b'. // Returns true if 'a' is more lower-left than 'b'.
private static bool cmppt(Vector3f a, Vector3f b) private static bool Cmppt(Vector3f a, Vector3f b)
{ {
if (a.x < b.x) if (a.x < b.x)
{ {
@ -91,7 +91,7 @@ namespace DotRecast.Core
} }
// Returns true if 'c' is left of line 'a'-'b'. // Returns true if 'c' is left of line 'a'-'b'.
private static bool left(Vector3f a, Vector3f b, Vector3f c) private static bool Left(Vector3f a, Vector3f b, Vector3f c)
{ {
float u1 = b.x - a.x; float u1 = b.x - a.x;
float v1 = b.z - a.z; float v1 = b.z - a.z;

View File

@ -16,7 +16,7 @@ namespace DotRecast.Core
r = new Random((int)seed); // TODO : 랜덤 시드 확인 필요 r = new Random((int)seed); // TODO : 랜덤 시드 확인 필요
} }
public float frand() public float Frand()
{ {
return (float)r.NextDouble(); return (float)r.NextDouble();
} }

View File

@ -24,20 +24,20 @@ namespace DotRecast.Core
{ {
public static class Intersections public static class Intersections
{ {
public static float? intersectSegmentTriangle(Vector3f sp, Vector3f sq, Vector3f a, Vector3f b, Vector3f c) public static float? IntersectSegmentTriangle(Vector3f sp, Vector3f sq, Vector3f a, Vector3f b, Vector3f c)
{ {
float v, w; float v, w;
Vector3f ab = vSub(b, a); Vector3f ab = VSub(b, a);
Vector3f ac = vSub(c, a); Vector3f ac = VSub(c, a);
Vector3f qp = vSub(sp, sq); Vector3f qp = VSub(sp, sq);
// Compute triangle normal. Can be precalculated or cached if // Compute triangle normal. Can be precalculated or cached if
// intersecting multiple segments against the same triangle // intersecting multiple segments against the same triangle
Vector3f norm = vCross(ab, ac); Vector3f norm = VCross(ab, ac);
// Compute denominator d. If d <= 0, segment is parallel to or points // Compute denominator d. If d <= 0, segment is parallel to or points
// away from triangle, so exit early // away from triangle, so exit early
float d = vDot(qp, norm); float d = VDot(qp, norm);
if (d <= 0.0f) if (d <= 0.0f)
{ {
return null; return null;
@ -46,8 +46,8 @@ namespace DotRecast.Core
// Compute intersection t value of pq with plane of triangle. A ray // Compute intersection t value of pq with plane of triangle. A ray
// intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay // intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay
// dividing by d until intersection has been found to pierce triangle // dividing by d until intersection has been found to pierce triangle
Vector3f ap = vSub(sp, a); Vector3f ap = VSub(sp, a);
float t = vDot(ap, norm); float t = VDot(ap, norm);
if (t < 0.0f) if (t < 0.0f)
{ {
return null; return null;
@ -59,14 +59,14 @@ namespace DotRecast.Core
} }
// Compute barycentric coordinate components and test if within bounds // Compute barycentric coordinate components and test if within bounds
Vector3f e = vCross(qp, ap); Vector3f e = VCross(qp, ap);
v = vDot(ac, e); v = VDot(ac, e);
if (v < 0.0f || v > d) if (v < 0.0f || v > d)
{ {
return null; return null;
} }
w = -vDot(ab, e); w = -VDot(ab, e);
if (w < 0.0f || v + w > d) if (w < 0.0f || v + w > d)
{ {
return null; return null;
@ -78,7 +78,7 @@ namespace DotRecast.Core
return t; return t;
} }
public static float[] intersectSegmentAABB(Vector3f sp, Vector3f sq, Vector3f amin, Vector3f amax) public static float[] IntersectSegmentAABB(Vector3f sp, Vector3f sq, Vector3f amin, Vector3f amax)
{ {
float EPS = 1e-6f; float EPS = 1e-6f;

View File

@ -26,9 +26,9 @@ namespace DotRecast.Core
public static class RecastMath public static class RecastMath
{ {
public const float EPS = 1e-4f; public const float EPS = 1e-4f;
private static readonly float EQUAL_THRESHOLD = sqr(1.0f / 16384.0f); private static readonly float EQUAL_THRESHOLD = Sqr(1.0f / 16384.0f);
public static float vDistSqr(Vector3f v1, float[] v2, int i) public static float VDistSqr(Vector3f v1, float[] v2, int i)
{ {
float dx = v2[i] - v1.x; float dx = v2[i] - v1.x;
float dy = v2[i + 1] - v1.y; float dy = v2[i + 1] - v1.y;
@ -36,7 +36,7 @@ namespace DotRecast.Core
return dx * dx + dy * dy + dz * dz; return dx * dx + dy * dy + dz * dz;
} }
public static float vDistSqr(Vector3f v1, Vector3f v2) public static float VDistSqr(Vector3f v1, Vector3f v2)
{ {
float dx = v2.x - v1.x; float dx = v2.x - v1.x;
float dy = v2.y - v1.y; float dy = v2.y - v1.y;
@ -44,7 +44,7 @@ namespace DotRecast.Core
return dx * dx + dy * dy + dz * dz; return dx * dx + dy * dy + dz * dz;
} }
public static float vDistSqr(float[] v, int i, int j) public static float VDistSqr(float[] v, int i, int j)
{ {
float dx = v[i] - v[j]; float dx = v[i] - v[j];
float dy = v[i + 1] - v[j + 1]; float dy = v[i + 1] - v[j + 1];
@ -52,7 +52,7 @@ namespace DotRecast.Core
return dx * dx + dy * dy + dz * dz; return dx * dx + dy * dy + dz * dz;
} }
public static Vector3f vCross(Vector3f v1, Vector3f v2) public static Vector3f VCross(Vector3f v1, Vector3f v2)
{ {
Vector3f dest = new Vector3f(); Vector3f dest = new Vector3f();
dest.x = v1.y * v2.z - v1.z * v2.y; dest.x = v1.y * v2.z - v1.z * v2.y;
@ -61,22 +61,22 @@ namespace DotRecast.Core
return dest; return dest;
} }
public static float vDot(Vector3f v1, Vector3f v2) public static float VDot(Vector3f v1, Vector3f v2)
{ {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
} }
public static float sqr(float f) public static float Sqr(float f)
{ {
return f * f; return f * f;
} }
public static float getPathLen(float[] path, int npath) public static float GetPathLen(float[] path, int npath)
{ {
float totd = 0; float totd = 0;
for (int i = 0; i < npath - 1; ++i) for (int i = 0; i < npath - 1; ++i)
{ {
totd += (float)Math.Sqrt(vDistSqr(path, i * 3, (i + 1) * 3)); totd += (float)Math.Sqrt(VDistSqr(path, i * 3, (i + 1) * 3));
} }
return totd; return totd;
@ -84,22 +84,22 @@ namespace DotRecast.Core
public static float step(float threshold, float v) public static float Step(float threshold, float v)
{ {
return v < threshold ? 0.0f : 1.0f; return v < threshold ? 0.0f : 1.0f;
} }
public static float clamp(float v, float min, float max) public static float Clamp(float v, float min, float max)
{ {
return Math.Max(Math.Min(v, max), min); return Math.Max(Math.Min(v, max), min);
} }
public static int clamp(int v, int min, int max) public static int Clamp(int v, int min, int max)
{ {
return Math.Max(Math.Min(v, max), min); return Math.Max(Math.Min(v, max), min);
} }
public static float lerp(float f, float g, float u) public static float Lerp(float f, float g, float u)
{ {
return u * g + (1f - u) * f; return u * g + (1f - u) * f;
} }
@ -110,7 +110,7 @@ namespace DotRecast.Core
/// @param[in] v1 The base vector. [(x, y, z)] /// @param[in] v1 The base vector. [(x, y, z)]
/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)] /// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
/// @param[in] s The amount to scale @p v2 by before adding to @p v1. /// @param[in] s The amount to scale @p v2 by before adding to @p v1.
public static Vector3f vMad(Vector3f v1, Vector3f v2, float s) public static Vector3f VMad(Vector3f v1, Vector3f v2, float s)
{ {
Vector3f dest = new Vector3f(); Vector3f dest = new Vector3f();
dest.x = v1.x + v2.x * s; dest.x = v1.x + v2.x * s;
@ -119,7 +119,7 @@ namespace DotRecast.Core
return dest; return dest;
} }
public static Vector3f vMad(float[] v1, Vector3f v2, float s) public static Vector3f VMad(float[] v1, Vector3f v2, float s)
{ {
Vector3f dest = new Vector3f(); Vector3f dest = new Vector3f();
dest.x = v1[0] + v2.x * s; dest.x = v1[0] + v2.x * s;
@ -136,7 +136,7 @@ namespace DotRecast.Core
/// @param[in] v1 The starting vector. /// @param[in] v1 The starting vector.
/// @param[in] v2 The destination vector. /// @param[in] v2 The destination vector.
/// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0] /// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0]
public static Vector3f vLerp(float[] verts, int v1, int v2, float t) public static Vector3f VLerp(float[] verts, int v1, int v2, float t)
{ {
Vector3f dest = new Vector3f(); Vector3f dest = new Vector3f();
dest.x = verts[v1 + 0] + (verts[v2 + 0] - verts[v1 + 0]) * t; dest.x = verts[v1 + 0] + (verts[v2 + 0] - verts[v1 + 0]) * t;
@ -145,7 +145,7 @@ namespace DotRecast.Core
return dest; return dest;
} }
public static Vector3f vLerp(Vector3f v1, Vector3f v2, float t) public static Vector3f VLerp(Vector3f v1, Vector3f v2, float t)
{ {
Vector3f dest = new Vector3f(); Vector3f dest = new Vector3f();
dest.x = v1.x + (v2.x - v1.x) * t; dest.x = v1.x + (v2.x - v1.x) * t;
@ -155,16 +155,16 @@ namespace DotRecast.Core
} }
public static Vector3f vSub(VectorPtr v1, VectorPtr v2) public static Vector3f VSub(VectorPtr v1, VectorPtr v2)
{ {
Vector3f dest = new Vector3f(); Vector3f dest = new Vector3f();
dest.x = v1.get(0) - v2.get(0); dest.x = v1.Get(0) - v2.Get(0);
dest.y = v1.get(1) - v2.get(1); dest.y = v1.Get(1) - v2.Get(1);
dest.z = v1.get(2) - v2.get(2); dest.z = v1.Get(2) - v2.Get(2);
return dest; return dest;
} }
public static Vector3f vSub(Vector3f v1, Vector3f v2) public static Vector3f VSub(Vector3f v1, Vector3f v2)
{ {
Vector3f dest = new Vector3f(); Vector3f dest = new Vector3f();
dest.x = v1.x - v2.x; dest.x = v1.x - v2.x;
@ -173,17 +173,17 @@ namespace DotRecast.Core
return dest; return dest;
} }
public static Vector3f vSub(Vector3f v1, VectorPtr v2) public static Vector3f VSub(Vector3f v1, VectorPtr v2)
{ {
Vector3f dest = new Vector3f(); Vector3f dest = new Vector3f();
dest.x = v1.x - v2.get(0); dest.x = v1.x - v2.Get(0);
dest.y = v1.y - v2.get(1); dest.y = v1.y - v2.Get(1);
dest.z = v1.z - v2.get(2); dest.z = v1.z - v2.Get(2);
return dest; return dest;
} }
public static Vector3f vSub(Vector3f v1, float[] v2) public static Vector3f VSub(Vector3f v1, float[] v2)
{ {
Vector3f dest = new Vector3f(); Vector3f dest = new Vector3f();
dest.x = v1.x - v2[0]; dest.x = v1.x - v2[0];
@ -192,7 +192,7 @@ namespace DotRecast.Core
return dest; return dest;
} }
public static Vector3f vAdd(Vector3f v1, Vector3f v2) public static Vector3f VAdd(Vector3f v1, Vector3f v2)
{ {
Vector3f dest = new Vector3f(); Vector3f dest = new Vector3f();
dest.x = v1.x + v2.x; dest.x = v1.x + v2.x;
@ -201,42 +201,42 @@ namespace DotRecast.Core
return dest; return dest;
} }
public static void vSet(ref Vector3f @out, float a, float b, float c) public static void VSet(ref Vector3f @out, float a, float b, float c)
{ {
@out.x = a; @out.x = a;
@out.y = b; @out.y = b;
@out.z = c; @out.z = c;
} }
public static void vCopy(float[] @out, Vector3f @in) public static void VCopy(float[] @out, Vector3f @in)
{ {
@out[0] = @in.x; @out[0] = @in.x;
@out[1] = @in.y; @out[1] = @in.y;
@out[2] = @in.z; @out[2] = @in.z;
} }
public static void vCopy(ref Vector3f @out, float[] @in) public static void VCopy(ref Vector3f @out, float[] @in)
{ {
@out.x = @in[0]; @out.x = @in[0];
@out.y = @in[1]; @out.y = @in[1];
@out.z = @in[2]; @out.z = @in[2];
} }
public static void vCopy(ref Vector3f @out, float[] @in, int i) public static void VCopy(ref Vector3f @out, float[] @in, int i)
{ {
@out.x = @in[i]; @out.x = @in[i];
@out.y = @in[i + 1]; @out.y = @in[i + 1];
@out.z = @in[i + 2]; @out.z = @in[i + 2];
} }
public static void vMin(float[] @out, float[] @in, int i) public static void VMin(float[] @out, float[] @in, int i)
{ {
@out[0] = Math.Min(@out[0], @in[i]); @out[0] = Math.Min(@out[0], @in[i]);
@out[1] = Math.Min(@out[1], @in[i + 1]); @out[1] = Math.Min(@out[1], @in[i + 1]);
@out[2] = Math.Min(@out[2], @in[i + 2]); @out[2] = Math.Min(@out[2], @in[i + 2]);
} }
public static void vMin(ref Vector3f @out, float[] @in, int i) public static void VMin(ref Vector3f @out, float[] @in, int i)
{ {
@out.x = Math.Min(@out.x, @in[i]); @out.x = Math.Min(@out.x, @in[i]);
@out.y = Math.Min(@out.y, @in[i + 1]); @out.y = Math.Min(@out.y, @in[i + 1]);
@ -244,14 +244,14 @@ namespace DotRecast.Core
} }
public static void vMax(float[] @out, float[] @in, int i) public static void VMax(float[] @out, float[] @in, int i)
{ {
@out[0] = Math.Max(@out[0], @in[i]); @out[0] = Math.Max(@out[0], @in[i]);
@out[1] = Math.Max(@out[1], @in[i + 1]); @out[1] = Math.Max(@out[1], @in[i + 1]);
@out[2] = Math.Max(@out[2], @in[i + 2]); @out[2] = Math.Max(@out[2], @in[i + 2]);
} }
public static void vMax(ref Vector3f @out, float[] @in, int i) public static void VMax(ref Vector3f @out, float[] @in, int i)
{ {
@out.x = Math.Max(@out.x, @in[i]); @out.x = Math.Max(@out.x, @in[i]);
@out.y = Math.Max(@out.y, @in[i + 1]); @out.y = Math.Max(@out.y, @in[i + 1]);
@ -263,7 +263,7 @@ namespace DotRecast.Core
/// @param[in] v1 A point. [(x, y, z)] /// @param[in] v1 A point. [(x, y, z)]
/// @param[in] v2 A point. [(x, y, z)] /// @param[in] v2 A point. [(x, y, z)]
/// @return The distance between the two points. /// @return The distance between the two points.
public static float vDist(float[] v1, float[] v2) public static float VDist(float[] v1, float[] v2)
{ {
float dx = v2[0] - v1[0]; float dx = v2[0] - v1[0];
float dy = v2[1] - v1[1]; float dy = v2[1] - v1[1];
@ -271,7 +271,7 @@ namespace DotRecast.Core
return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz); return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
} }
public static float vDist(Vector3f v1, float[] v2) public static float VDist(Vector3f v1, float[] v2)
{ {
float dx = v2[0] - v1.x; float dx = v2[0] - v1.x;
float dy = v2[1] - v1.y; float dy = v2[1] - v1.y;
@ -279,7 +279,7 @@ namespace DotRecast.Core
return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz); return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
} }
public static float vDist(Vector3f v1, Vector3f v2) public static float VDist(Vector3f v1, Vector3f v2)
{ {
float dx = v2.x - v1.x; float dx = v2.x - v1.x;
float dy = v2.y - v1.y; float dy = v2.y - v1.y;
@ -293,7 +293,7 @@ namespace DotRecast.Core
/// @param[in] v1 A point. [(x, y, z)] /// @param[in] v1 A point. [(x, y, z)]
/// @param[in] v2 A point. [(x, y, z)] /// @param[in] v2 A point. [(x, y, z)]
/// @return The distance between the two points. /// @return The distance between the two points.
public static float vDistSqr(float[] v1, float[] v2) public static float VDistSqr(float[] v1, float[] v2)
{ {
float dx = v2[0] - v1[0]; float dx = v2[0] - v1[0];
float dy = v2[1] - v1[1]; float dy = v2[1] - v1[1];
@ -306,29 +306,29 @@ namespace DotRecast.Core
/// Derives the square of the scalar length of the vector. (len * len) /// Derives the square of the scalar length of the vector. (len * len)
/// @param[in] v The vector. [(x, y, z)] /// @param[in] v The vector. [(x, y, z)]
/// @return The square of the scalar length of the vector. /// @return The square of the scalar length of the vector.
public static float vLenSqr(float[] v) public static float VLenSqr(float[] v)
{ {
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
} }
public static float vLenSqr(Vector3f v) public static float VLenSqr(Vector3f v)
{ {
return v.x * v.x + v.y * v.y + v.z * v.z; return v.x * v.x + v.y * v.y + v.z * v.z;
} }
public static float vLen(float[] v) public static float VLen(float[] v)
{ {
return (float)Math.Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); return (float)Math.Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
} }
public static float vLen(Vector3f v) public static float VLen(Vector3f v)
{ {
return (float)Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z); return (float)Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
} }
public static float vDist(float[] v1, float[] verts, int i) public static float VDist(float[] v1, float[] verts, int i)
{ {
float dx = verts[i] - v1[0]; float dx = verts[i] - v1[0];
float dy = verts[i + 1] - v1[1]; float dy = verts[i + 1] - v1[1];
@ -344,14 +344,14 @@ namespace DotRecast.Core
/// ///
/// The vectors are projected onto the xz-plane, so the y-values are /// The vectors are projected onto the xz-plane, so the y-values are
/// ignored. /// ignored.
public static float vDist2D(float[] v1, float[] v2) public static float VDist2D(float[] v1, float[] v2)
{ {
float dx = v2[0] - v1[0]; float dx = v2[0] - v1[0];
float dz = v2[2] - v1[2]; float dz = v2[2] - v1[2];
return (float)Math.Sqrt(dx * dx + dz * dz); return (float)Math.Sqrt(dx * dx + dz * dz);
} }
public static float vDist2D(Vector3f v1, Vector3f v2) public static float VDist2D(Vector3f v1, Vector3f v2)
{ {
float dx = v2.x - v1.x; float dx = v2.x - v1.x;
float dz = v2.z - v1.z; float dz = v2.z - v1.z;
@ -359,14 +359,14 @@ namespace DotRecast.Core
} }
public static float vDist2DSqr(float[] v1, float[] v2) public static float VDist2DSqr(float[] v1, float[] v2)
{ {
float dx = v2[0] - v1[0]; float dx = v2[0] - v1[0];
float dz = v2[2] - v1[2]; float dz = v2[2] - v1[2];
return dx * dx + dz * dz; return dx * dx + dz * dz;
} }
public static float vDist2DSqr(Vector3f v1, Vector3f v2) public static float VDist2DSqr(Vector3f v1, Vector3f v2)
{ {
float dx = v2.x - v1.x; float dx = v2.x - v1.x;
float dz = v2.z - v1.z; float dz = v2.z - v1.z;
@ -374,7 +374,7 @@ namespace DotRecast.Core
} }
public static float vDist2DSqr(Vector3f p, float[] verts, int i) public static float VDist2DSqr(Vector3f p, float[] verts, int i)
{ {
float dx = verts[i] - p.x; float dx = verts[i] - p.x;
float dz = verts[i + 2] - p.z; float dz = verts[i + 2] - p.z;
@ -383,9 +383,9 @@ namespace DotRecast.Core
/// Normalizes the vector. /// Normalizes the vector.
/// @param[in,out] v The vector to normalize. [(x, y, z)] /// @param[in,out] v The vector to normalize. [(x, y, z)]
public static void vNormalize(float[] v) public static void VNormalize(float[] v)
{ {
float d = (float)(1.0f / Math.Sqrt(sqr(v[0]) + sqr(v[1]) + sqr(v[2]))); float d = (float)(1.0f / Math.Sqrt(Sqr(v[0]) + Sqr(v[1]) + Sqr(v[2])));
if (d != 0) if (d != 0)
{ {
v[0] *= d; v[0] *= d;
@ -394,9 +394,9 @@ namespace DotRecast.Core
} }
} }
public static void vNormalize(ref Vector3f v) public static void VNormalize(ref Vector3f v)
{ {
float d = (float)(1.0f / Math.Sqrt(sqr(v.x) + sqr(v.y) + sqr(v.z))); float d = (float)(1.0f / Math.Sqrt(Sqr(v.x) + Sqr(v.y) + Sqr(v.z)));
if (d != 0) if (d != 0)
{ {
v.x *= d; v.x *= d;
@ -413,26 +413,26 @@ namespace DotRecast.Core
/// ///
/// Basically, this function will return true if the specified points are /// Basically, this function will return true if the specified points are
/// close enough to eachother to be considered colocated. /// close enough to eachother to be considered colocated.
public static bool vEqual(float[] p0, float[] p1) public static bool VEqual(float[] p0, float[] p1)
{ {
return vEqual(p0, p1, EQUAL_THRESHOLD); return VEqual(p0, p1, EQUAL_THRESHOLD);
} }
public static bool vEqual(Vector3f p0, Vector3f p1) public static bool VEqual(Vector3f p0, Vector3f p1)
{ {
return vEqual(p0, p1, EQUAL_THRESHOLD); return VEqual(p0, p1, EQUAL_THRESHOLD);
} }
public static bool vEqual(float[] p0, float[] p1, float thresholdSqr) public static bool VEqual(float[] p0, float[] p1, float thresholdSqr)
{ {
float d = vDistSqr(p0, p1); float d = VDistSqr(p0, p1);
return d < thresholdSqr; return d < thresholdSqr;
} }
public static bool vEqual(Vector3f p0, Vector3f p1, float thresholdSqr) public static bool VEqual(Vector3f p0, Vector3f p1, float thresholdSqr)
{ {
float d = vDistSqr(p0, p1); float d = VDistSqr(p0, p1);
return d < thresholdSqr; return d < thresholdSqr;
} }
@ -444,18 +444,18 @@ namespace DotRecast.Core
/// ///
/// The vectors are projected onto the xz-plane, so the y-values are /// The vectors are projected onto the xz-plane, so the y-values are
/// ignored. /// ignored.
public static float vDot2D(float[] u, float[] v) public static float VDot2D(float[] u, float[] v)
{ {
return u[0] * v[0] + u[2] * v[2]; return u[0] * v[0] + u[2] * v[2];
} }
public static float vDot2D(Vector3f u, Vector3f v) public static float VDot2D(Vector3f u, Vector3f v)
{ {
return u.x * v.x + u.z * v.z; return u.x * v.x + u.z * v.z;
} }
public static float vDot2D(Vector3f u, float[] v, int vi) public static float VDot2D(Vector3f u, float[] v, int vi)
{ {
return u.x * v[vi] + u.z * v[vi + 2]; return u.x * v[vi] + u.z * v[vi + 2];
} }
@ -467,12 +467,12 @@ namespace DotRecast.Core
/// ///
/// The vectors are projected onto the xz-plane, so the y-values are /// The vectors are projected onto the xz-plane, so the y-values are
/// ignored. /// ignored.
public static float vPerp2D(float[] u, float[] v) public static float VPerp2D(float[] u, float[] v)
{ {
return u[2] * v[0] - u[0] * v[2]; return u[2] * v[0] - u[0] * v[2];
} }
public static float vPerp2D(Vector3f u, Vector3f v) public static float VPerp2D(Vector3f u, Vector3f v)
{ {
return u.z * v.x - u.x * v.z; return u.z * v.x - u.x * v.z;
} }
@ -487,7 +487,7 @@ namespace DotRecast.Core
/// @param[in] b Vertex B. [(x, y, z)] /// @param[in] b Vertex B. [(x, y, z)]
/// @param[in] c Vertex C. [(x, y, z)] /// @param[in] c Vertex C. [(x, y, z)]
/// @return The signed xz-plane area of the triangle. /// @return The signed xz-plane area of the triangle.
public static float triArea2D(float[] verts, int a, int b, int c) public static float TriArea2D(float[] verts, int a, int b, int c)
{ {
float abx = verts[b] - verts[a]; float abx = verts[b] - verts[a];
float abz = verts[b + 2] - verts[a + 2]; float abz = verts[b + 2] - verts[a + 2];
@ -496,7 +496,7 @@ namespace DotRecast.Core
return acx * abz - abx * acz; return acx * abz - abx * acz;
} }
public static float triArea2D(float[] a, float[] b, float[] c) public static float TriArea2D(float[] a, float[] b, float[] c)
{ {
float abx = b[0] - a[0]; float abx = b[0] - a[0];
float abz = b[2] - a[2]; float abz = b[2] - a[2];
@ -505,7 +505,7 @@ namespace DotRecast.Core
return acx * abz - abx * acz; return acx * abz - abx * acz;
} }
public static float triArea2D(Vector3f a, Vector3f b, Vector3f c) public static float TriArea2D(Vector3f a, Vector3f b, Vector3f c)
{ {
float abx = b.x - a.x; float abx = b.x - a.x;
float abz = b.z - a.z; float abz = b.z - a.z;
@ -514,7 +514,7 @@ namespace DotRecast.Core
return acx * abz - abx * acz; return acx * abz - abx * acz;
} }
public static float triArea2D(Vector3f a, float[] b, Vector3f c) public static float TriArea2D(Vector3f a, float[] b, Vector3f c)
{ {
float abx = b[0] - a.x; float abx = b[0] - a.x;
float abz = b[2] - a.z; float abz = b[2] - a.z;
@ -532,7 +532,7 @@ namespace DotRecast.Core
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)] /// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
/// @return True if the two AABB's overlap. /// @return True if the two AABB's overlap.
/// @see dtOverlapBounds /// @see dtOverlapBounds
public static bool overlapQuantBounds(int[] amin, int[] amax, int[] bmin, int[] bmax) public static bool OverlapQuantBounds(int[] amin, int[] amax, int[] bmin, int[] bmax)
{ {
bool overlap = true; bool overlap = true;
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap; overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
@ -548,7 +548,7 @@ namespace DotRecast.Core
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)] /// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
/// @return True if the two AABB's overlap. /// @return True if the two AABB's overlap.
/// @see dtOverlapQuantBounds /// @see dtOverlapQuantBounds
public static bool overlapBounds(float[] amin, float[] amax, float[] bmin, float[] bmax) public static bool OverlapBounds(float[] amin, float[] amax, float[] bmin, float[] bmax)
{ {
bool overlap = true; bool overlap = true;
overlap = (amin[0]> bmax[0] || amax[0] < bmin[0]) ? false : overlap; overlap = (amin[0]> bmax[0] || amax[0] < bmin[0]) ? false : overlap;
@ -557,7 +557,7 @@ namespace DotRecast.Core
return overlap; return overlap;
} }
public static bool overlapBounds(Vector3f amin, Vector3f amax, Vector3f bmin, Vector3f bmax) public static bool OverlapBounds(Vector3f amin, Vector3f amax, Vector3f bmin, Vector3f bmax)
{ {
bool overlap = true; bool overlap = true;
overlap = (amin.x > bmax.x || amax.x < bmin.x) ? false : overlap; overlap = (amin.x > bmax.x || amax.x < bmin.x) ? false : overlap;
@ -566,7 +566,7 @@ namespace DotRecast.Core
return overlap; return overlap;
} }
public static Tuple<float, float> distancePtSegSqr2D(Vector3f pt, Vector3f p, Vector3f q) public static Tuple<float, float> DistancePtSegSqr2D(Vector3f pt, Vector3f p, Vector3f q)
{ {
float pqx = q.x - p.x; float pqx = q.x - p.x;
float pqz = q.z - p.z; float pqz = q.z - p.z;
@ -593,11 +593,11 @@ namespace DotRecast.Core
return Tuple.Create(dx * dx + dz * dz, t); return Tuple.Create(dx * dx + dz * dz, t);
} }
public static float? closestHeightPointTriangle(Vector3f p, Vector3f a, Vector3f b, Vector3f c) public static float? ClosestHeightPointTriangle(Vector3f p, Vector3f a, Vector3f b, Vector3f c)
{ {
Vector3f v0 = vSub(c, a); Vector3f v0 = VSub(c, a);
Vector3f v1 = vSub(b, a); Vector3f v1 = VSub(b, a);
Vector3f v2 = vSub(p, a); Vector3f v2 = VSub(p, a);
// Compute scaled barycentric coordinates // Compute scaled barycentric coordinates
float denom = v0.x * v1.z - v0.z * v1.x; float denom = v0.x * v1.z - v0.z * v1.x;
@ -629,7 +629,7 @@ namespace DotRecast.Core
/// @par /// @par
/// ///
/// All points are projected onto the xz-plane, so the y-values are ignored. /// All points are projected onto the xz-plane, so the y-values are ignored.
public static bool pointInPolygon(Vector3f pt, float[] verts, int nverts) public static bool PointInPolygon(Vector3f pt, float[] verts, int nverts)
{ {
// TODO: Replace pnpoly with triArea2D tests? // TODO: Replace pnpoly with triArea2D tests?
int i, j; int i, j;
@ -648,7 +648,7 @@ namespace DotRecast.Core
return c; return c;
} }
public static bool distancePtPolyEdgesSqr(Vector3f pt, float[] verts, int nverts, float[] ed, float[] et) public static bool DistancePtPolyEdgesSqr(Vector3f pt, float[] verts, int nverts, float[] ed, float[] et)
{ {
// TODO: Replace pnpoly with triArea2D tests? // TODO: Replace pnpoly with triArea2D tests?
int i, j; int i, j;
@ -663,7 +663,7 @@ namespace DotRecast.Core
c = !c; c = !c;
} }
Tuple<float, float> edet = distancePtSegSqr2D(pt, verts, vj, vi); Tuple<float, float> edet = DistancePtSegSqr2D(pt, verts, vj, vi);
ed[j] = edet.Item1; ed[j] = edet.Item1;
et[j] = edet.Item2; et[j] = edet.Item2;
} }
@ -671,13 +671,13 @@ namespace DotRecast.Core
return c; return c;
} }
public static float[] projectPoly(Vector3f axis, float[] poly, int npoly) public static float[] ProjectPoly(Vector3f axis, float[] poly, int npoly)
{ {
float rmin, rmax; float rmin, rmax;
rmin = rmax = vDot2D(axis, poly, 0); rmin = rmax = VDot2D(axis, poly, 0);
for (int i = 1; i < npoly; ++i) for (int i = 1; i < npoly; ++i)
{ {
float d = vDot2D(axis, poly, i * 3); float d = VDot2D(axis, poly, i * 3);
rmin = Math.Min(rmin, d); rmin = Math.Min(rmin, d);
rmax = Math.Max(rmax, d); rmax = Math.Max(rmax, d);
} }
@ -685,7 +685,7 @@ namespace DotRecast.Core
return new float[] { rmin, rmax }; return new float[] { rmin, rmax };
} }
public static bool overlapRange(float amin, float amax, float bmin, float bmax, float eps) public static bool OverlapRange(float amin, float amax, float bmin, float bmax, float eps)
{ {
return ((amin + eps) > bmax || (amax - eps) < bmin) ? false : true; return ((amin + eps) > bmax || (amax - eps) < bmin) ? false : true;
} }
@ -695,7 +695,7 @@ namespace DotRecast.Core
/// @par /// @par
/// ///
/// All vertices are projected onto the xz-plane, so the y-values are ignored. /// All vertices are projected onto the xz-plane, so the y-values are ignored.
public static bool overlapPolyPoly2D(float[] polya, int npolya, float[] polyb, int npolyb) public static bool OverlapPolyPoly2D(float[] polya, int npolya, float[] polyb, int npolyb)
{ {
for (int i = 0, j = npolya - 1; i < npolya; j = i++) for (int i = 0, j = npolya - 1; i < npolya; j = i++)
{ {
@ -704,9 +704,9 @@ namespace DotRecast.Core
Vector3f n = Vector3f.Of(polya[vb + 2] - polya[va + 2], 0, -(polya[vb + 0] - polya[va + 0])); Vector3f n = Vector3f.Of(polya[vb + 2] - polya[va + 2], 0, -(polya[vb + 0] - polya[va + 0]));
float[] aminmax = projectPoly(n, polya, npolya); float[] aminmax = ProjectPoly(n, polya, npolya);
float[] bminmax = projectPoly(n, polyb, npolyb); float[] bminmax = ProjectPoly(n, polyb, npolyb);
if (!overlapRange(aminmax[0], aminmax[1], bminmax[0], bminmax[1], eps)) if (!OverlapRange(aminmax[0], aminmax[1], bminmax[0], bminmax[1], eps))
{ {
// Found separating axis // Found separating axis
return false; return false;
@ -720,9 +720,9 @@ namespace DotRecast.Core
Vector3f n = Vector3f.Of(polyb[vb + 2] - polyb[va + 2], 0, -(polyb[vb + 0] - polyb[va + 0])); Vector3f n = Vector3f.Of(polyb[vb + 2] - polyb[va + 2], 0, -(polyb[vb + 0] - polyb[va + 0]));
float[] aminmax = projectPoly(n, polya, npolya); float[] aminmax = ProjectPoly(n, polya, npolya);
float[] bminmax = projectPoly(n, polyb, npolyb); float[] bminmax = ProjectPoly(n, polyb, npolyb);
if (!overlapRange(aminmax[0], aminmax[1], bminmax[0], bminmax[1], eps)) if (!OverlapRange(aminmax[0], aminmax[1], bminmax[0], bminmax[1], eps))
{ {
// Found separating axis // Found separating axis
return false; return false;
@ -734,13 +734,13 @@ namespace DotRecast.Core
// Returns a random point in a convex polygon. // Returns a random point in a convex polygon.
// Adapted from Graphics Gems article. // Adapted from Graphics Gems article.
public static Vector3f randomPointInConvexPoly(float[] pts, int npts, float[] areas, float s, float t) public static Vector3f RandomPointInConvexPoly(float[] pts, int npts, float[] areas, float s, float t)
{ {
// Calc triangle araes // Calc triangle araes
float areasum = 0.0f; float areasum = 0.0f;
for (int i = 2; i < npts; i++) for (int i = 2; i < npts; i++)
{ {
areas[i] = triArea2D(pts, 0, (i - 1) * 3, i * 3); areas[i] = TriArea2D(pts, 0, (i - 1) * 3, i * 3);
areasum += Math.Max(0.001f, areas[i]); areasum += Math.Max(0.001f, areas[i]);
} }
@ -779,7 +779,7 @@ namespace DotRecast.Core
}; };
} }
public static int nextPow2(int v) public static int NextPow2(int v)
{ {
v--; v--;
v |= v >> 1; v |= v >> 1;
@ -791,7 +791,7 @@ namespace DotRecast.Core
return v; return v;
} }
public static int ilog2(int v) public static int Ilog2(int v)
{ {
int r; int r;
int shift; int shift;
@ -819,20 +819,20 @@ namespace DotRecast.Core
public int segMax = -1; public int segMax = -1;
} }
public static IntersectResult intersectSegmentPoly2D(Vector3f p0, Vector3f p1, float[] verts, int nverts) public static IntersectResult IntersectSegmentPoly2D(Vector3f p0, Vector3f p1, float[] verts, int nverts)
{ {
IntersectResult result = new IntersectResult(); IntersectResult result = new IntersectResult();
float EPS = 0.000001f; float EPS = 0.000001f;
var dir = vSub(p1, p0); var dir = VSub(p1, p0);
var p0v = p0; var p0v = p0;
for (int i = 0, j = nverts - 1; i < nverts; j = i++) for (int i = 0, j = nverts - 1; i < nverts; j = i++)
{ {
VectorPtr vpj = new VectorPtr(verts, j * 3); VectorPtr vpj = new VectorPtr(verts, j * 3);
var edge = vSub(new VectorPtr(verts, i * 3), vpj); var edge = VSub(new VectorPtr(verts, i * 3), vpj);
var diff = vSub(p0v, vpj); var diff = VSub(p0v, vpj);
float n = vPerp2D(edge, diff); float n = VPerp2D(edge, diff);
float d = vPerp2D(dir, edge); float d = VPerp2D(dir, edge);
if (Math.Abs(d) < EPS) if (Math.Abs(d) < EPS)
{ {
// S is nearly parallel to this edge // S is nearly parallel to this edge
@ -881,7 +881,7 @@ namespace DotRecast.Core
return result; return result;
} }
public static Tuple<float, float> distancePtSegSqr2D(Vector3f pt, SegmentVert verts, int p, int q) public static Tuple<float, float> DistancePtSegSqr2D(Vector3f pt, SegmentVert verts, int p, int q)
{ {
float pqx = verts[q + 0] - verts[p + 0]; float pqx = verts[q + 0] - verts[p + 0];
float pqz = verts[q + 2] - verts[p + 2]; float pqz = verts[q + 2] - verts[p + 2];
@ -909,7 +909,7 @@ namespace DotRecast.Core
} }
public static Tuple<float, float> distancePtSegSqr2D(Vector3f pt, float[] verts, int p, int q) public static Tuple<float, float> DistancePtSegSqr2D(Vector3f pt, float[] verts, int p, int q)
{ {
float pqx = verts[q + 0] - verts[p + 0]; float pqx = verts[q + 0] - verts[p + 0];
float pqz = verts[q + 2] - verts[p + 2]; float pqz = verts[q + 2] - verts[p + 2];
@ -936,38 +936,38 @@ namespace DotRecast.Core
return Tuple.Create(dx * dx + dz * dz, t); return Tuple.Create(dx * dx + dz * dz, t);
} }
public static int oppositeTile(int side) public static int OppositeTile(int side)
{ {
return (side + 4) & 0x7; return (side + 4) & 0x7;
} }
public static float vperpXZ(float[] a, float[] b) public static float VperpXZ(float[] a, float[] b)
{ {
return a[0] * b[2] - a[2] * b[0]; return a[0] * b[2] - a[2] * b[0];
} }
public static float vperpXZ(Vector3f a, Vector3f b) public static float VperpXZ(Vector3f a, Vector3f b)
{ {
return a.x * b.z - a.z * b.x; return a.x * b.z - a.z * b.x;
} }
public static Tuple<float, float>? intersectSegSeg2D(Vector3f ap, Vector3f aq, Vector3f bp, Vector3f bq) public static Tuple<float, float>? IntersectSegSeg2D(Vector3f ap, Vector3f aq, Vector3f bp, Vector3f bq)
{ {
Vector3f u = vSub(aq, ap); Vector3f u = VSub(aq, ap);
Vector3f v = vSub(bq, bp); Vector3f v = VSub(bq, bp);
Vector3f w = vSub(ap, bp); Vector3f w = VSub(ap, bp);
float d = vperpXZ(u, v); float d = VperpXZ(u, v);
if (Math.Abs(d) < 1e-6f) if (Math.Abs(d) < 1e-6f)
{ {
return null; return null;
} }
float s = vperpXZ(v, w) / d; float s = VperpXZ(v, w) / d;
float t = vperpXZ(u, w) / d; float t = VperpXZ(u, w) / d;
return Tuple.Create(s, t); return Tuple.Create(s, t);
} }
public static Vector3f vScale(Vector3f @in, float scale) public static Vector3f VScale(Vector3f @in, float scale)
{ {
var @out = new Vector3f(); var @out = new Vector3f();
@out.x = @in.x * scale; @out.x = @in.x * scale;
@ -981,24 +981,24 @@ namespace DotRecast.Core
/// @param[in] v A point. [(x, y, z)] /// @param[in] v A point. [(x, y, z)]
/// @return True if all of the point's components are finite, i.e. not NaN /// @return True if all of the point's components are finite, i.e. not NaN
/// or any of the infinities. /// or any of the infinities.
public static bool vIsFinite(float[] v) public static bool VIsFinite(float[] v)
{ {
return float.IsFinite(v[0]) && float.IsFinite(v[1]) && float.IsFinite(v[2]); return float.IsFinite(v[0]) && float.IsFinite(v[1]) && float.IsFinite(v[2]);
} }
public static bool vIsFinite(Vector3f v) public static bool VIsFinite(Vector3f v)
{ {
return float.IsFinite(v.x) && float.IsFinite(v.y) && float.IsFinite(v.z); return float.IsFinite(v.x) && float.IsFinite(v.y) && float.IsFinite(v.z);
} }
/// Checks that the specified vector's 2D components are finite. /// Checks that the specified vector's 2D components are finite.
/// @param[in] v A point. [(x, y, z)] /// @param[in] v A point. [(x, y, z)]
public static bool vIsFinite2D(float[] v) public static bool VIsFinite2D(float[] v)
{ {
return float.IsFinite(v[0]) && float.IsFinite(v[2]); return float.IsFinite(v[0]) && float.IsFinite(v[2]);
} }
public static bool vIsFinite2D(Vector3f v) public static bool VIsFinite2D(Vector3f v)
{ {
return float.IsFinite(v.x) && float.IsFinite(v.z); return float.IsFinite(v.x) && float.IsFinite(v.z);
} }

View File

@ -40,7 +40,7 @@ namespace DotRecast.Core
this.index = index; this.index = index;
} }
public float get(int offset) public float Get(int offset)
{ {
return array[index + offset]; return array[index + offset];
} }

File diff suppressed because it is too large Load Diff

View File

@ -135,35 +135,35 @@ namespace DotRecast.Detour.Crowd
animation = new CrowdAgentAnimation(); animation = new CrowdAgentAnimation();
} }
public void integrate(float dt) public void Integrate(float dt)
{ {
// Fake dynamic constraint. // Fake dynamic constraint.
float maxDelta = option.maxAcceleration * dt; float maxDelta = option.maxAcceleration * dt;
Vector3f dv = vSub(nvel, vel); Vector3f dv = VSub(nvel, vel);
float ds = vLen(dv); float ds = VLen(dv);
if (ds > maxDelta) if (ds > maxDelta)
dv = vScale(dv, maxDelta / ds); dv = VScale(dv, maxDelta / ds);
vel = vAdd(vel, dv); vel = VAdd(vel, dv);
// Integrate // Integrate
if (vLen(vel) > 0.0001f) if (VLen(vel) > 0.0001f)
npos = vMad(npos, vel, dt); npos = VMad(npos, vel, dt);
else else
vel = Vector3f.Zero; vel = Vector3f.Zero;
} }
public bool overOffmeshConnection(float radius) public bool OverOffmeshConnection(float radius)
{ {
if (0 == corners.Count) if (0 == corners.Count)
return false; return false;
bool offMeshConnection = ((corners[corners.Count - 1].getFlags() bool offMeshConnection = ((corners[corners.Count - 1].GetFlags()
& NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0) & NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
? true ? true
: false; : false;
if (offMeshConnection) if (offMeshConnection)
{ {
float distSq = vDist2DSqr(npos, corners[corners.Count - 1].getPos()); float distSq = VDist2DSqr(npos, corners[corners.Count - 1].GetPos());
if (distSq < radius * radius) if (distSq < radius * radius)
return true; return true;
} }
@ -171,62 +171,62 @@ namespace DotRecast.Detour.Crowd
return false; return false;
} }
public float getDistanceToGoal(float range) public float GetDistanceToGoal(float range)
{ {
if (0 == corners.Count) if (0 == corners.Count)
return range; return range;
bool endOfPath = ((corners[corners.Count - 1].getFlags() & NavMeshQuery.DT_STRAIGHTPATH_END) != 0) ? true : false; bool endOfPath = ((corners[corners.Count - 1].GetFlags() & NavMeshQuery.DT_STRAIGHTPATH_END) != 0) ? true : false;
if (endOfPath) if (endOfPath)
return Math.Min(vDist2D(npos, corners[corners.Count - 1].getPos()), range); return Math.Min(VDist2D(npos, corners[corners.Count - 1].GetPos()), range);
return range; return range;
} }
public Vector3f calcSmoothSteerDirection() public Vector3f CalcSmoothSteerDirection()
{ {
Vector3f dir = new Vector3f(); Vector3f dir = new Vector3f();
if (0 < corners.Count) if (0 < corners.Count)
{ {
int ip0 = 0; int ip0 = 0;
int ip1 = Math.Min(1, corners.Count - 1); int ip1 = Math.Min(1, corners.Count - 1);
var p0 = corners[ip0].getPos(); var p0 = corners[ip0].GetPos();
var p1 = corners[ip1].getPos(); var p1 = corners[ip1].GetPos();
var dir0 = vSub(p0, npos); var dir0 = VSub(p0, npos);
var dir1 = vSub(p1, npos); var dir1 = VSub(p1, npos);
dir0.y = 0; dir0.y = 0;
dir1.y = 0; dir1.y = 0;
float len0 = vLen(dir0); float len0 = VLen(dir0);
float len1 = vLen(dir1); float len1 = VLen(dir1);
if (len1 > 0.001f) if (len1 > 0.001f)
dir1 = vScale(dir1, 1.0f / len1); dir1 = VScale(dir1, 1.0f / len1);
dir.x = dir0.x - dir1.x * len0 * 0.5f; dir.x = dir0.x - dir1.x * len0 * 0.5f;
dir.y = 0; dir.y = 0;
dir.z = dir0.z - dir1.z * len0 * 0.5f; dir.z = dir0.z - dir1.z * len0 * 0.5f;
vNormalize(ref dir); VNormalize(ref dir);
} }
return dir; return dir;
} }
public Vector3f calcStraightSteerDirection() public Vector3f CalcStraightSteerDirection()
{ {
Vector3f dir = new Vector3f(); Vector3f dir = new Vector3f();
if (0 < corners.Count) if (0 < corners.Count)
{ {
dir = vSub(corners[0].getPos(), npos); dir = VSub(corners[0].GetPos(), npos);
dir.y = 0; dir.y = 0;
vNormalize(ref dir); VNormalize(ref dir);
} }
return dir; return dir;
} }
public void setTarget(long refs, Vector3f pos) public void SetTarget(long refs, Vector3f pos)
{ {
targetRef = refs; targetRef = refs;
targetPos = pos; targetPos = pos;

View File

@ -54,11 +54,11 @@ namespace DotRecast.Detour.Crowd
public const int DT_CROWD_SEPARATION = 4; public const int DT_CROWD_SEPARATION = 4;
public const int DT_CROWD_OPTIMIZE_VIS = 8; public const int DT_CROWD_OPTIMIZE_VIS = 8;
/// < Use #dtPathCorridor::optimizePathVisibility() to optimize /// < Use #dtPathCorridor::OptimizePathVisibility() to optimize
/// the agent path. /// the agent path.
public const int DT_CROWD_OPTIMIZE_TOPO = 16; public const int DT_CROWD_OPTIMIZE_TOPO = 16;
/// < Use dtPathCorridor::optimizePathTopology() to optimize /// < Use dtPathCorridor::OptimizePathTopology() to optimize
/// the agent path. /// the agent path.
/// Flags that impact steering behavior. (See: #UpdateFlags) /// Flags that impact steering behavior. (See: #UpdateFlags)
public int updateFlags; public int updateFlags;

View File

@ -32,44 +32,44 @@ namespace DotRecast.Detour.Crowd
private readonly Dictionary<string, long> _executionTimings = new Dictionary<string, long>(); private readonly Dictionary<string, long> _executionTimings = new Dictionary<string, long>();
private readonly Dictionary<string, List<long>> _executionTimingSamples = new Dictionary<string, List<long>>(); private readonly Dictionary<string, List<long>> _executionTimingSamples = new Dictionary<string, List<long>>();
public float maxTimeToEnqueueRequest() public float MaxTimeToEnqueueRequest()
{ {
return _maxTimeToEnqueueRequest; return _maxTimeToEnqueueRequest;
} }
public float maxTimeToFindPath() public float MaxTimeToFindPath()
{ {
return _maxTimeToFindPath; return _maxTimeToFindPath;
} }
public Dictionary<string, long> executionTimings() public Dictionary<string, long> ExecutionTimings()
{ {
return _executionTimings; return _executionTimings;
} }
public void start() public void Start()
{ {
_maxTimeToEnqueueRequest = 0; _maxTimeToEnqueueRequest = 0;
_maxTimeToFindPath = 0; _maxTimeToFindPath = 0;
_executionTimings.Clear(); _executionTimings.Clear();
} }
public void recordMaxTimeToEnqueueRequest(float time) public void RecordMaxTimeToEnqueueRequest(float time)
{ {
_maxTimeToEnqueueRequest = Math.Max(_maxTimeToEnqueueRequest, time); _maxTimeToEnqueueRequest = Math.Max(_maxTimeToEnqueueRequest, time);
} }
public void recordMaxTimeToFindPath(float time) public void RecordMaxTimeToFindPath(float time)
{ {
_maxTimeToFindPath = Math.Max(_maxTimeToFindPath, time); _maxTimeToFindPath = Math.Max(_maxTimeToFindPath, time);
} }
public void start(string name) public void Start(string name)
{ {
_executionTimings.Add(name, FrequencyWatch.Ticks); _executionTimings.Add(name, FrequencyWatch.Ticks);
} }
public void stop(string name) public void Stop(string name)
{ {
long duration = FrequencyWatch.Ticks - _executionTimings[name]; long duration = FrequencyWatch.Ticks - _executionTimings[name];
if (!_executionTimingSamples.TryGetValue(name, out var s)) if (!_executionTimingSamples.TryGetValue(name, out var s))

View File

@ -49,14 +49,14 @@ namespace DotRecast.Detour.Crowd
m_center.x = m_center.y = m_center.z = float.MaxValue; m_center.x = m_center.y = m_center.z = float.MaxValue;
} }
public void reset() public void Reset()
{ {
m_center.x = m_center.y = m_center.z = float.MaxValue; m_center.x = m_center.y = m_center.z = float.MaxValue;
m_polys.Clear(); m_polys.Clear();
m_segs.Clear(); m_segs.Clear();
} }
protected void addSegment(float dist, SegmentVert s) protected void AddSegment(float dist, SegmentVert s)
{ {
// Insert neighbour based on the distance. // Insert neighbour based on the distance.
Segment seg = new Segment(); Segment seg = new Segment();
@ -98,47 +98,47 @@ namespace DotRecast.Detour.Crowd
} }
} }
public void update(long refs, Vector3f pos, float collisionQueryRange, NavMeshQuery navquery, QueryFilter filter) public void Update(long refs, Vector3f pos, float collisionQueryRange, NavMeshQuery navquery, QueryFilter filter)
{ {
if (refs == 0) if (refs == 0)
{ {
reset(); Reset();
return; return;
} }
m_center = pos; m_center = pos;
// First query non-overlapping polygons. // First query non-overlapping polygons.
Result<FindLocalNeighbourhoodResult> res = navquery.findLocalNeighbourhood(refs, pos, collisionQueryRange, Result<FindLocalNeighbourhoodResult> res = navquery.FindLocalNeighbourhood(refs, pos, collisionQueryRange,
filter); filter);
if (res.Succeeded()) if (res.Succeeded())
{ {
m_polys = res.result.getRefs(); m_polys = res.result.GetRefs();
m_segs.Clear(); m_segs.Clear();
// Secondly, store all polygon edges. // Secondly, store all polygon edges.
for (int j = 0; j < m_polys.Count; ++j) for (int j = 0; j < m_polys.Count; ++j)
{ {
Result<GetPolyWallSegmentsResult> result = navquery.getPolyWallSegments(m_polys[j], false, filter); Result<GetPolyWallSegmentsResult> result = navquery.GetPolyWallSegments(m_polys[j], false, filter);
if (result.Succeeded()) if (result.Succeeded())
{ {
GetPolyWallSegmentsResult gpws = result.result; GetPolyWallSegmentsResult gpws = result.result;
for (int k = 0; k < gpws.countSegmentRefs(); ++k) for (int k = 0; k < gpws.CountSegmentRefs(); ++k)
{ {
SegmentVert s = gpws.getSegmentVert(k); SegmentVert s = gpws.GetSegmentVert(k);
// Skip too distant segments. // Skip too distant segments.
Tuple<float, float> distseg = distancePtSegSqr2D(pos, s, 0, 3); Tuple<float, float> distseg = DistancePtSegSqr2D(pos, s, 0, 3);
if (distseg.Item1 > sqr(collisionQueryRange)) if (distseg.Item1 > Sqr(collisionQueryRange))
{ {
continue; continue;
} }
addSegment(distseg.Item1, s); AddSegment(distseg.Item1, s);
} }
} }
} }
} }
} }
public bool isValid(NavMeshQuery navquery, QueryFilter filter) public bool IsValid(NavMeshQuery navquery, QueryFilter filter)
{ {
if (m_polys.Count == 0) if (m_polys.Count == 0)
{ {
@ -148,7 +148,7 @@ namespace DotRecast.Detour.Crowd
// Check that all polygons still pass query filter. // Check that all polygons still pass query filter.
foreach (long refs in m_polys) foreach (long refs in m_polys)
{ {
if (!navquery.isValidPolyRef(refs, filter)) if (!navquery.IsValidPolyRef(refs, filter))
{ {
return false; return false;
} }
@ -157,17 +157,17 @@ namespace DotRecast.Detour.Crowd
return true; return true;
} }
public Vector3f getCenter() public Vector3f GetCenter()
{ {
return m_center; return m_center;
} }
public Vector3f[] getSegment(int j) public Vector3f[] GetSegment(int j)
{ {
return m_segs[j].s; return m_segs[j].s;
} }
public int getSegmentCount() public int GetSegmentCount()
{ {
return m_segs.Count; return m_segs.Count;
} }

View File

@ -98,13 +98,13 @@ namespace DotRecast.Detour.Crowd
} }
} }
public void reset() public void Reset()
{ {
m_ncircles = 0; m_ncircles = 0;
m_nsegments = 0; m_nsegments = 0;
} }
public void addCircle(Vector3f pos, float rad, Vector3f vel, Vector3f dvel) public void AddCircle(Vector3f pos, float rad, Vector3f vel, Vector3f dvel)
{ {
if (m_ncircles >= m_maxCircles) if (m_ncircles >= m_maxCircles)
return; return;
@ -116,7 +116,7 @@ namespace DotRecast.Detour.Crowd
cir.dvel = dvel; cir.dvel = dvel;
} }
public void addSegment(Vector3f p, Vector3f q) public void AddSegment(Vector3f p, Vector3f q)
{ {
if (m_nsegments >= m_maxSegments) if (m_nsegments >= m_maxSegments)
return; return;
@ -126,27 +126,27 @@ namespace DotRecast.Detour.Crowd
seg.q = q; seg.q = q;
} }
public int getObstacleCircleCount() public int GetObstacleCircleCount()
{ {
return m_ncircles; return m_ncircles;
} }
public ObstacleCircle getObstacleCircle(int i) public ObstacleCircle GetObstacleCircle(int i)
{ {
return m_circles[i]; return m_circles[i];
} }
public int getObstacleSegmentCount() public int GetObstacleSegmentCount()
{ {
return m_nsegments; return m_nsegments;
} }
public ObstacleSegment getObstacleSegment(int i) public ObstacleSegment GetObstacleSegment(int i)
{ {
return m_segments[i]; return m_segments[i];
} }
private void prepare(Vector3f pos, Vector3f dvel) private void Prepare(Vector3f pos, Vector3f dvel)
{ {
// Prepare obstacles // Prepare obstacles
for (int i = 0; i < m_ncircles; ++i) for (int i = 0; i < m_ncircles; ++i)
@ -159,11 +159,11 @@ namespace DotRecast.Detour.Crowd
Vector3f orig = new Vector3f(); Vector3f orig = new Vector3f();
Vector3f dv = new Vector3f(); Vector3f dv = new Vector3f();
cir.dp = vSub(pb, pa); cir.dp = VSub(pb, pa);
vNormalize(ref cir.dp); VNormalize(ref cir.dp);
dv = vSub(cir.dvel, dvel); dv = VSub(cir.dvel, dvel);
float a = triArea2D(orig, cir.dp, dv); float a = TriArea2D(orig, cir.dp, dv);
if (a < 0.01f) if (a < 0.01f)
{ {
cir.np.x = -cir.dp.z; cir.np.x = -cir.dp.z;
@ -182,23 +182,23 @@ namespace DotRecast.Detour.Crowd
// Precalc if the agent is really close to the segment. // Precalc if the agent is really close to the segment.
float r = 0.01f; float r = 0.01f;
Tuple<float, float> dt = distancePtSegSqr2D(pos, seg.p, seg.q); Tuple<float, float> dt = DistancePtSegSqr2D(pos, seg.p, seg.q);
seg.touch = dt.Item1 < sqr(r); seg.touch = dt.Item1 < Sqr(r);
} }
} }
SweepCircleCircleResult sweepCircleCircle(Vector3f c0, float r0, Vector3f v, Vector3f c1, float r1) SweepCircleCircleResult SweepCircleCircle(Vector3f c0, float r0, Vector3f v, Vector3f c1, float r1)
{ {
const float EPS = 0.0001f; const float EPS = 0.0001f;
Vector3f s = vSub(c1, c0); Vector3f s = VSub(c1, c0);
float r = r0 + r1; float r = r0 + r1;
float c = vDot2D(s, s) - r * r; float c = VDot2D(s, s) - r * r;
float a = vDot2D(v, v); float a = VDot2D(v, v);
if (a < EPS) if (a < EPS)
return new SweepCircleCircleResult(false, 0f, 0f); // not moving return new SweepCircleCircleResult(false, 0f, 0f); // not moving
// Overlap, calc time to exit. // Overlap, calc time to exit.
float b = vDot2D(v, s); float b = VDot2D(v, s);
float d = b * b - a * c; float d = b * b - a * c;
if (d < 0.0f) if (d < 0.0f)
return new SweepCircleCircleResult(false, 0f, 0f); // no intersection. return new SweepCircleCircleResult(false, 0f, 0f); // no intersection.
@ -207,20 +207,20 @@ namespace DotRecast.Detour.Crowd
return new SweepCircleCircleResult(true, (b - rd) * a, (b + rd) * a); return new SweepCircleCircleResult(true, (b - rd) * a, (b + rd) * a);
} }
IsectRaySegResult isectRaySeg(Vector3f ap, Vector3f u, Vector3f bp, Vector3f bq) IsectRaySegResult IsectRaySeg(Vector3f ap, Vector3f u, Vector3f bp, Vector3f bq)
{ {
Vector3f v = vSub(bq, bp); Vector3f v = VSub(bq, bp);
Vector3f w = vSub(ap, bp); Vector3f w = VSub(ap, bp);
float d = vPerp2D(u, v); float d = VPerp2D(u, v);
if (Math.Abs(d) < 1e-6f) if (Math.Abs(d) < 1e-6f)
return new IsectRaySegResult(false, 0f); return new IsectRaySegResult(false, 0f);
d = 1.0f / d; d = 1.0f / d;
float t = vPerp2D(v, w) * d; float t = VPerp2D(v, w) * d;
if (t < 0 || t > 1) if (t < 0 || t > 1)
return new IsectRaySegResult(false, 0f); return new IsectRaySegResult(false, 0f);
float s = vPerp2D(u, w) * d; float s = VPerp2D(u, w) * d;
if (s < 0 || s > 1) if (s < 0 || s > 1)
return new IsectRaySegResult(false, 0f); return new IsectRaySegResult(false, 0f);
@ -237,12 +237,12 @@ namespace DotRecast.Detour.Crowd
* @param minPenalty * @param minPenalty
* threshold penalty for early out * threshold penalty for early out
*/ */
private float processSample(Vector3f vcand, float cs, Vector3f pos, float rad, Vector3f vel, Vector3f dvel, private float ProcessSample(Vector3f vcand, float cs, Vector3f pos, float rad, Vector3f vel, Vector3f dvel,
float minPenalty, ObstacleAvoidanceDebugData debug) float minPenalty, ObstacleAvoidanceDebugData debug)
{ {
// penalty for straying away from the desired and current velocities // penalty for straying away from the desired and current velocities
float vpen = m_params.weightDesVel * (vDist2D(vcand, dvel) * m_invVmax); float vpen = m_params.weightDesVel * (VDist2D(vcand, dvel) * m_invVmax);
float vcpen = m_params.weightCurVel * (vDist2D(vcand, vel) * m_invVmax); float vcpen = m_params.weightCurVel * (VDist2D(vcand, vel) * m_invVmax);
// find the threshold hit time to bail out based on the early out penalty // find the threshold hit time to bail out based on the early out penalty
// (see how the penalty is calculated below to understnad) // (see how the penalty is calculated below to understnad)
@ -261,15 +261,15 @@ namespace DotRecast.Detour.Crowd
ObstacleCircle cir = m_circles[i]; ObstacleCircle cir = m_circles[i];
// RVO // RVO
Vector3f vab = vScale(vcand, 2); Vector3f vab = VScale(vcand, 2);
vab = vSub(vab, vel); vab = VSub(vab, vel);
vab = vSub(vab, cir.vel); vab = VSub(vab, cir.vel);
// Side // Side
side += clamp(Math.Min(vDot2D(cir.dp, vab) * 0.5f + 0.5f, vDot2D(cir.np, vab) * 2), 0.0f, 1.0f); side += Clamp(Math.Min(VDot2D(cir.dp, vab) * 0.5f + 0.5f, VDot2D(cir.np, vab) * 2), 0.0f, 1.0f);
nside++; nside++;
SweepCircleCircleResult sres = sweepCircleCircle(pos, rad, vab, cir.p, cir.rad); SweepCircleCircleResult sres = SweepCircleCircle(pos, rad, vab, cir.p, cir.rad);
if (!sres.intersection) if (!sres.intersection)
continue; continue;
float htmin = sres.htmin, htmax = sres.htmax; float htmin = sres.htmin, htmax = sres.htmax;
@ -301,19 +301,19 @@ namespace DotRecast.Detour.Crowd
if (seg.touch) if (seg.touch)
{ {
// Special case when the agent is very close to the segment. // Special case when the agent is very close to the segment.
Vector3f sdir = vSub(seg.q, seg.p); Vector3f sdir = VSub(seg.q, seg.p);
Vector3f snorm = new Vector3f(); Vector3f snorm = new Vector3f();
snorm.x = -sdir.z; snorm.x = -sdir.z;
snorm.z = sdir.x; snorm.z = sdir.x;
// If the velocity is pointing towards the segment, no collision. // If the velocity is pointing towards the segment, no collision.
if (vDot2D(snorm, vcand) < 0.0f) if (VDot2D(snorm, vcand) < 0.0f)
continue; continue;
// Else immediate collision. // Else immediate collision.
htmin = 0.0f; htmin = 0.0f;
} }
else else
{ {
var ires = isectRaySeg(pos, vcand, seg.p, seg.q); var ires = IsectRaySeg(pos, vcand, seg.p, seg.q);
if (!ires.result) if (!ires.result)
continue; continue;
@ -342,15 +342,15 @@ namespace DotRecast.Detour.Crowd
float penalty = vpen + vcpen + spen + tpen; float penalty = vpen + vcpen + spen + tpen;
// Store different penalties for debug viewing // Store different penalties for debug viewing
if (debug != null) if (debug != null)
debug.addSample(vcand, cs, penalty, vpen, vcpen, spen, tpen); debug.AddSample(vcand, cs, penalty, vpen, vcpen, spen, tpen);
return penalty; return penalty;
} }
public Tuple<int, Vector3f> sampleVelocityGrid(Vector3f pos, float rad, float vmax, Vector3f vel, Vector3f dvel, public Tuple<int, Vector3f> SampleVelocityGrid(Vector3f pos, float rad, float vmax, Vector3f vel, Vector3f dvel,
ObstacleAvoidanceParams option, ObstacleAvoidanceDebugData debug) ObstacleAvoidanceParams option, ObstacleAvoidanceDebugData debug)
{ {
prepare(pos, dvel); Prepare(pos, dvel);
m_params = option; m_params = option;
m_invHorizTime = 1.0f / m_params.horizTime; m_invHorizTime = 1.0f / m_params.horizTime;
m_vmax = vmax; m_vmax = vmax;
@ -359,7 +359,7 @@ namespace DotRecast.Detour.Crowd
Vector3f nvel = Vector3f.Zero; Vector3f nvel = Vector3f.Zero;
if (debug != null) if (debug != null)
debug.reset(); debug.Reset();
float cvx = dvel.x * m_params.velBias; float cvx = dvel.x * m_params.velBias;
float cvz = dvel.z * m_params.velBias; float cvz = dvel.z * m_params.velBias;
@ -374,12 +374,12 @@ namespace DotRecast.Detour.Crowd
for (int x = 0; x < m_params.gridSize; ++x) for (int x = 0; x < m_params.gridSize; ++x)
{ {
Vector3f vcand = new Vector3f(); Vector3f vcand = new Vector3f();
vSet(ref vcand, cvx + x * cs - half, 0f, cvz + y * cs - half); VSet(ref vcand, cvx + x * cs - half, 0f, cvz + y * cs - half);
if (sqr(vcand.x) + sqr(vcand.z) > sqr(vmax + cs / 2)) if (Sqr(vcand.x) + Sqr(vcand.z) > Sqr(vmax + cs / 2))
continue; continue;
float penalty = processSample(vcand, cs, pos, rad, vel, dvel, minPenalty, debug); float penalty = ProcessSample(vcand, cs, pos, rad, vel, dvel, minPenalty, debug);
ns++; ns++;
if (penalty < minPenalty) if (penalty < minPenalty)
{ {
@ -393,7 +393,7 @@ namespace DotRecast.Detour.Crowd
} }
// vector normalization that ignores the y-component. // vector normalization that ignores the y-component.
void dtNormalize2D(float[] v) void DtNormalize2D(float[] v)
{ {
float d = (float)Math.Sqrt(v[0] * v[0] + v[2] * v[2]); float d = (float)Math.Sqrt(v[0] * v[0] + v[2] * v[2]);
if (d == 0) if (d == 0)
@ -404,7 +404,7 @@ namespace DotRecast.Detour.Crowd
} }
// vector normalization that ignores the y-component. // vector normalization that ignores the y-component.
Vector3f dtRotate2D(float[] v, float ang) Vector3f DtRotate2D(float[] v, float ang)
{ {
Vector3f dest = new Vector3f(); Vector3f dest = new Vector3f();
float c = (float)Math.Cos(ang); float c = (float)Math.Cos(ang);
@ -417,10 +417,10 @@ namespace DotRecast.Detour.Crowd
static readonly float DT_PI = 3.14159265f; static readonly float DT_PI = 3.14159265f;
public Tuple<int, Vector3f> sampleVelocityAdaptive(Vector3f pos, float rad, float vmax, Vector3f vel, public Tuple<int, Vector3f> SampleVelocityAdaptive(Vector3f pos, float rad, float vmax, Vector3f vel,
Vector3f dvel, ObstacleAvoidanceParams option, ObstacleAvoidanceDebugData debug) Vector3f dvel, ObstacleAvoidanceParams option, ObstacleAvoidanceDebugData debug)
{ {
prepare(pos, dvel); Prepare(pos, dvel);
m_params = option; m_params = option;
m_invHorizTime = 1.0f / m_params.horizTime; m_invHorizTime = 1.0f / m_params.horizTime;
m_vmax = vmax; m_vmax = vmax;
@ -429,7 +429,7 @@ namespace DotRecast.Detour.Crowd
Vector3f nvel = Vector3f.Zero; Vector3f nvel = Vector3f.Zero;
if (debug != null) if (debug != null)
debug.reset(); debug.Reset();
// Build sampling pattern aligned to desired velocity. // Build sampling pattern aligned to desired velocity.
float[] pat = new float[(DT_MAX_PATTERN_DIVS * DT_MAX_PATTERN_RINGS + 1) * 2]; float[] pat = new float[(DT_MAX_PATTERN_DIVS * DT_MAX_PATTERN_RINGS + 1) * 2];
@ -439,17 +439,17 @@ namespace DotRecast.Detour.Crowd
int nrings = m_params.adaptiveRings; int nrings = m_params.adaptiveRings;
int depth = m_params.adaptiveDepth; int depth = m_params.adaptiveDepth;
int nd = clamp(ndivs, 1, DT_MAX_PATTERN_DIVS); int nd = Clamp(ndivs, 1, DT_MAX_PATTERN_DIVS);
int nr = clamp(nrings, 1, DT_MAX_PATTERN_RINGS); int nr = Clamp(nrings, 1, DT_MAX_PATTERN_RINGS);
float da = (1.0f / nd) * DT_PI * 2; float da = (1.0f / nd) * DT_PI * 2;
float ca = (float)Math.Cos(da); float ca = (float)Math.Cos(da);
float sa = (float)Math.Sin(da); float sa = (float)Math.Sin(da);
// desired direction // desired direction
float[] ddir = new float[6]; float[] ddir = new float[6];
vCopy(ddir, dvel); VCopy(ddir, dvel);
dtNormalize2D(ddir); DtNormalize2D(ddir);
Vector3f rotated = dtRotate2D(ddir, da * 0.5f); // rotated by da/2 Vector3f rotated = DtRotate2D(ddir, da * 0.5f); // rotated by da/2
ddir[3] = rotated.x; ddir[3] = rotated.x;
ddir[4] = rotated.y; ddir[4] = rotated.y;
ddir[5] = rotated.z; ddir[5] = rotated.z;
@ -493,7 +493,7 @@ namespace DotRecast.Detour.Crowd
// Start sampling. // Start sampling.
float cr = vmax * (1.0f - m_params.velBias); float cr = vmax * (1.0f - m_params.velBias);
Vector3f res = new Vector3f(); Vector3f res = new Vector3f();
vSet(ref res, dvel.x * m_params.velBias, 0, dvel.z * m_params.velBias); VSet(ref res, dvel.x * m_params.velBias, 0, dvel.z * m_params.velBias);
int ns = 0; int ns = 0;
for (int k = 0; k < depth; ++k) for (int k = 0; k < depth; ++k)
{ {
@ -504,11 +504,11 @@ namespace DotRecast.Detour.Crowd
for (int i = 0; i < npat; ++i) for (int i = 0; i < npat; ++i)
{ {
Vector3f vcand = new Vector3f(); Vector3f vcand = new Vector3f();
vSet(ref vcand, res.x + pat[i * 2 + 0] * cr, 0f, res.z + pat[i * 2 + 1] * cr); VSet(ref vcand, res.x + pat[i * 2 + 0] * cr, 0f, res.z + pat[i * 2 + 1] * cr);
if (sqr(vcand.x) + sqr(vcand.z) > sqr(vmax + 0.001f)) if (Sqr(vcand.x) + Sqr(vcand.z) > Sqr(vmax + 0.001f))
continue; continue;
float penalty = processSample(vcand, cr / 10, pos, rad, vel, dvel, minPenalty, debug); float penalty = ProcessSample(vcand, cr / 10, pos, rad, vel, dvel, minPenalty, debug);
ns++; ns++;
if (penalty < minPenalty) if (penalty < minPenalty)
{ {

View File

@ -30,17 +30,17 @@ namespace DotRecast.Detour.Crowd
/** /**
* Represents a dynamic polygon corridor used to plan agent movement. * Represents a dynamic polygon corridor used to plan agent movement.
* *
* The corridor is loaded with a path, usually obtained from a #NavMeshQuery::findPath() query. The corridor is then * The corridor is loaded with a path, usually obtained from a #NavMeshQuery::FindPath() query. The corridor is then
* used to plan local movement, with the corridor automatically updating as needed to deal with inaccurate agent * used to plan local movement, with the corridor automatically updating as needed to deal with inaccurate agent
* locomotion. * locomotion.
* *
* Example of a common use case: * Example of a common use case:
* *
* -# Construct the corridor object and call -# Obtain a path from a #dtNavMeshQuery object. -# Use #reset() to set the * -# Construct the corridor object and call -# Obtain a path from a #dtNavMeshQuery object. -# Use #Reset() to set the
* agent's current position. (At the beginning of the path.) -# Use #setCorridor() to load the path and target. -# Use * agent's current position. (At the beginning of the path.) -# Use #SetCorridor() to load the path and target. -# Use
* #findCorners() to plan movement. (This handles dynamic path straightening.) -# Use #movePosition() to feed agent * #FindCorners() to plan movement. (This handles dynamic path straightening.) -# Use #MovePosition() to feed agent
* movement back into the corridor. (The corridor will automatically adjust as needed.) -# If the target is moving, use * movement back into the corridor. (The corridor will automatically adjust as needed.) -# If the target is moving, use
* #moveTargetPosition() to update the end of the corridor. (The corridor will automatically adjust as needed.) -# * #MoveTargetPosition() to update the end of the corridor. (The corridor will automatically adjust as needed.) -#
* Repeat the previous 3 steps to continue to move the agent. * Repeat the previous 3 steps to continue to move the agent.
* *
* The corridor position and target are always constrained to the navigation mesh. * The corridor position and target are always constrained to the navigation mesh.
@ -55,13 +55,13 @@ namespace DotRecast.Detour.Crowd
* Every time a move function is used there is a chance that the path will become non-optimial. Basically, the further * Every time a move function is used there is a chance that the path will become non-optimial. Basically, the further
* the target is moved from its original location, and the further the position is moved outside the original corridor, * the target is moved from its original location, and the further the position is moved outside the original corridor,
* the more likely the path will become non-optimal. This issue can be addressed by periodically running the * the more likely the path will become non-optimal. This issue can be addressed by periodically running the
* #optimizePathTopology() and #optimizePathVisibility() methods. * #OptimizePathTopology() and #OptimizePathVisibility() methods.
* *
* All local mesh queries have distance limitations. (Review the #dtNavMeshQuery methods for details.) So the most * All local mesh queries have distance limitations. (Review the #dtNavMeshQuery methods for details.) So the most
* accurate use case is to move the position and target in small increments. If a large increment is used, then the * accurate use case is to move the position and target in small increments. If a large increment is used, then the
* corridor may not be able to accurately find the new location. Because of this limiation, if a position is moved in a * corridor may not be able to accurately find the new location. Because of this limiation, if a position is moved in a
* large increment, then compare the desired and resulting polygon references. If the two do not match, then path * large increment, then compare the desired and resulting polygon references. If the two do not match, then path
* replanning may be needed. E.g. If you move the target, check #getLastPoly() to see if it is the expected polygon. * replanning may be needed. E.g. If you move the target, check #GetLastPoly() to see if it is the expected polygon.
* *
*/ */
public class PathCorridor public class PathCorridor
@ -70,7 +70,7 @@ namespace DotRecast.Detour.Crowd
private Vector3f m_target = new Vector3f(); private Vector3f m_target = new Vector3f();
private List<long> m_path; private List<long> m_path;
protected List<long> mergeCorridorStartMoved(List<long> path, List<long> visited) protected List<long> MergeCorridorStartMoved(List<long> path, List<long> visited)
{ {
int furthestPath = -1; int furthestPath = -1;
int furthestVisited = -1; int furthestVisited = -1;
@ -115,7 +115,7 @@ namespace DotRecast.Detour.Crowd
return result; return result;
} }
protected List<long> mergeCorridorEndMoved(List<long> path, List<long> visited) protected List<long> MergeCorridorEndMoved(List<long> path, List<long> visited)
{ {
int furthestPath = -1; int furthestPath = -1;
int furthestVisited = -1; int furthestVisited = -1;
@ -152,7 +152,7 @@ namespace DotRecast.Detour.Crowd
return result; return result;
} }
protected List<long> mergeCorridorStartShortcut(List<long> path, List<long> visited) protected List<long> MergeCorridorStartShortcut(List<long> path, List<long> visited)
{ {
int furthestPath = -1; int furthestPath = -1;
int furthestVisited = -1; int furthestVisited = -1;
@ -207,7 +207,7 @@ namespace DotRecast.Detour.Crowd
* @param pos * @param pos
* The new position in the corridor. [(x, y, z)] * The new position in the corridor. [(x, y, z)]
*/ */
public void reset(long refs, Vector3f pos) public void Reset(long refs, Vector3f pos)
{ {
m_path.Clear(); m_path.Clear();
m_path.Add(refs); m_path.Add(refs);
@ -215,7 +215,7 @@ namespace DotRecast.Detour.Crowd
m_target = pos; m_target = pos;
} }
private static readonly float MIN_TARGET_DIST = sqr(0.01f); private static readonly float MIN_TARGET_DIST = Sqr(0.01f);
/** /**
* Finds the corners in the corridor from the position toward the target. (The straightened path.) * Finds the corners in the corridor from the position toward the target. (The straightened path.)
@ -234,10 +234,10 @@ namespace DotRecast.Detour.Crowd
* @param[in] navquery The query object used to build the corridor. * @param[in] navquery The query object used to build the corridor.
* @return Corners * @return Corners
*/ */
public List<StraightPathItem> findCorners(int maxCorners, NavMeshQuery navquery, QueryFilter filter) public List<StraightPathItem> FindCorners(int maxCorners, NavMeshQuery navquery, QueryFilter filter)
{ {
List<StraightPathItem> path = new List<StraightPathItem>(); List<StraightPathItem> path = new List<StraightPathItem>();
Result<List<StraightPathItem>> result = navquery.findStraightPath(m_pos, m_target, m_path, maxCorners, 0); Result<List<StraightPathItem>> result = navquery.FindStraightPath(m_pos, m_target, m_path, maxCorners, 0);
if (result.Succeeded()) if (result.Succeeded())
{ {
path = result.result; path = result.result;
@ -245,8 +245,8 @@ namespace DotRecast.Detour.Crowd
int start = 0; int start = 0;
foreach (StraightPathItem spi in path) foreach (StraightPathItem spi in path)
{ {
if ((spi.getFlags() & NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0 if ((spi.GetFlags() & NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0
|| vDist2DSqr(spi.getPos(), m_pos) > MIN_TARGET_DIST) || VDist2DSqr(spi.GetPos(), m_pos) > MIN_TARGET_DIST)
{ {
break; break;
} }
@ -259,7 +259,7 @@ namespace DotRecast.Detour.Crowd
for (int i = start; i < path.Count; i++) for (int i = start; i < path.Count; i++)
{ {
StraightPathItem spi = path[i]; StraightPathItem spi = path[i];
if ((spi.getFlags() & NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0) if ((spi.GetFlags() & NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
{ {
end = i + 1; end = i + 1;
break; break;
@ -299,10 +299,10 @@ namespace DotRecast.Detour.Crowd
* @param filter * @param filter
* The filter to apply to the operation. * The filter to apply to the operation.
*/ */
public void optimizePathVisibility(Vector3f next, float pathOptimizationRange, NavMeshQuery navquery, QueryFilter filter) public void OptimizePathVisibility(Vector3f next, float pathOptimizationRange, NavMeshQuery navquery, QueryFilter filter)
{ {
// Clamp the ray to max distance. // Clamp the ray to max distance.
float dist = vDist2D(m_pos, next); float dist = VDist2D(m_pos, next);
// If too close to the goal, do not try to optimize. // If too close to the goal, do not try to optimize.
if (dist < 0.01f) if (dist < 0.01f)
@ -315,15 +315,15 @@ namespace DotRecast.Detour.Crowd
dist = Math.Min(dist + 0.01f, pathOptimizationRange); dist = Math.Min(dist + 0.01f, pathOptimizationRange);
// Adjust ray length. // Adjust ray length.
var delta = vSub(next, m_pos); var delta = VSub(next, m_pos);
Vector3f goal = vMad(m_pos, delta, pathOptimizationRange / dist); Vector3f goal = VMad(m_pos, delta, pathOptimizationRange / dist);
Result<RaycastHit> rc = navquery.raycast(m_path[0], m_pos, goal, filter, 0, 0); Result<RaycastHit> rc = navquery.Raycast(m_path[0], m_pos, goal, filter, 0, 0);
if (rc.Succeeded()) if (rc.Succeeded())
{ {
if (rc.result.path.Count > 1 && rc.result.t > 0.99f) if (rc.result.path.Count > 1 && rc.result.t > 0.99f)
{ {
m_path = mergeCorridorStartShortcut(m_path, rc.result.path); m_path = MergeCorridorStartShortcut(m_path, rc.result.path);
} }
} }
} }
@ -344,27 +344,27 @@ namespace DotRecast.Detour.Crowd
* The filter to apply to the operation. * The filter to apply to the operation.
* *
*/ */
public bool optimizePathTopology(NavMeshQuery navquery, QueryFilter filter, int maxIterations) public bool OptimizePathTopology(NavMeshQuery navquery, QueryFilter filter, int maxIterations)
{ {
if (m_path.Count < 3) if (m_path.Count < 3)
{ {
return false; return false;
} }
navquery.initSlicedFindPath(m_path[0], m_path[m_path.Count - 1], m_pos, m_target, filter, 0); navquery.InitSlicedFindPath(m_path[0], m_path[m_path.Count - 1], m_pos, m_target, filter, 0);
navquery.updateSlicedFindPath(maxIterations); navquery.UpdateSlicedFindPath(maxIterations);
Result<List<long>> fpr = navquery.finalizeSlicedFindPathPartial(m_path); Result<List<long>> fpr = navquery.FinalizeSlicedFindPathPartial(m_path);
if (fpr.Succeeded() && fpr.result.Count > 0) if (fpr.Succeeded() && fpr.result.Count > 0)
{ {
m_path = mergeCorridorStartShortcut(m_path, fpr.result); m_path = MergeCorridorStartShortcut(m_path, fpr.result);
return true; return true;
} }
return false; return false;
} }
public bool moveOverOffmeshConnection(long offMeshConRef, long[] refs, ref Vector3f start, ref Vector3f end, NavMeshQuery navquery) public bool MoveOverOffmeshConnection(long offMeshConRef, long[] refs, ref Vector3f start, ref Vector3f end, NavMeshQuery navquery)
{ {
// Advance the path up to and over the off-mesh connection. // Advance the path up to and over the off-mesh connection.
long prevRef = 0, polyRef = m_path[0]; long prevRef = 0, polyRef = m_path[0];
@ -387,8 +387,8 @@ namespace DotRecast.Detour.Crowd
refs[0] = prevRef; refs[0] = prevRef;
refs[1] = polyRef; refs[1] = polyRef;
NavMesh nav = navquery.getAttachedNavMesh(); NavMesh nav = navquery.GetAttachedNavMesh();
var startEnd = nav.getOffMeshConnectionPolyEndPoints(refs[0], refs[1]); var startEnd = nav.GetOffMeshConnectionPolyEndPoints(refs[0], refs[1]);
if (startEnd.Succeeded()) if (startEnd.Succeeded())
{ {
m_pos = startEnd.result.Item2; m_pos = startEnd.result.Item2;
@ -423,16 +423,16 @@ namespace DotRecast.Detour.Crowd
* @param filter * @param filter
* The filter to apply to the operation. * The filter to apply to the operation.
*/ */
public bool movePosition(Vector3f npos, NavMeshQuery navquery, QueryFilter filter) public bool MovePosition(Vector3f npos, NavMeshQuery navquery, QueryFilter filter)
{ {
// Move along navmesh and update new position. // Move along navmesh and update new position.
Result<MoveAlongSurfaceResult> masResult = navquery.moveAlongSurface(m_path[0], m_pos, npos, filter); Result<MoveAlongSurfaceResult> masResult = navquery.MoveAlongSurface(m_path[0], m_pos, npos, filter);
if (masResult.Succeeded()) if (masResult.Succeeded())
{ {
m_path = mergeCorridorStartMoved(m_path, masResult.result.getVisited()); m_path = MergeCorridorStartMoved(m_path, masResult.result.GetVisited());
// Adjust the position to stay on top of the navmesh. // Adjust the position to stay on top of the navmesh.
m_pos = masResult.result.getResultPos(); m_pos = masResult.result.GetResultPos();
Result<float> hr = navquery.getPolyHeight(m_path[0], masResult.result.getResultPos()); Result<float> hr = navquery.GetPolyHeight(m_path[0], masResult.result.GetResultPos());
if (hr.Succeeded()) if (hr.Succeeded())
{ {
m_pos.y = hr.result; m_pos.y = hr.result;
@ -461,20 +461,20 @@ namespace DotRecast.Detour.Crowd
* @param filter * @param filter
* The filter to apply to the operation. * The filter to apply to the operation.
*/ */
public bool moveTargetPosition(Vector3f npos, NavMeshQuery navquery, QueryFilter filter) public bool MoveTargetPosition(Vector3f npos, NavMeshQuery navquery, QueryFilter filter)
{ {
// Move along navmesh and update new position. // Move along navmesh and update new position.
Result<MoveAlongSurfaceResult> masResult = navquery.moveAlongSurface(m_path[m_path.Count - 1], m_target, npos, filter); Result<MoveAlongSurfaceResult> masResult = navquery.MoveAlongSurface(m_path[m_path.Count - 1], m_target, npos, filter);
if (masResult.Succeeded()) if (masResult.Succeeded())
{ {
m_path = mergeCorridorEndMoved(m_path, masResult.result.getVisited()); m_path = MergeCorridorEndMoved(m_path, masResult.result.GetVisited());
// TODO: should we do that? // TODO: should we do that?
// Adjust the position to stay on top of the navmesh. // Adjust the position to stay on top of the navmesh.
/* /*
* float h = m_target.y; navquery->getPolyHeight(m_path[m_npath-1], * float h = m_target.y; navquery->GetPolyHeight(m_path[m_npath-1],
* result, &h); result.y = h; * result, &h); result.y = h;
*/ */
m_target = masResult.result.getResultPos(); m_target = masResult.result.GetResultPos();
return true; return true;
} }
@ -485,19 +485,19 @@ namespace DotRecast.Detour.Crowd
* Loads a new path and target into the corridor. The current corridor position is expected to be within the first * Loads a new path and target into the corridor. The current corridor position is expected to be within the first
* polygon in the path. The target is expected to be in the last polygon. * polygon in the path. The target is expected to be in the last polygon.
* *
* @warning The size of the path must not exceed the size of corridor's path buffer set during #init(). * @warning The size of the path must not exceed the size of corridor's path buffer set during #Init().
* @param target * @param target
* The target location within the last polygon of the path. [(x, y, z)] * The target location within the last polygon of the path. [(x, y, z)]
* @param path * @param path
* The path corridor. * The path corridor.
*/ */
public void setCorridor(Vector3f target, List<long> path) public void SetCorridor(Vector3f target, List<long> path)
{ {
m_target = target; m_target = target;
m_path = new List<long>(path); m_path = new List<long>(path);
} }
public void fixPathStart(long safeRef, Vector3f safePos) public void FixPathStart(long safeRef, Vector3f safePos)
{ {
m_pos = safePos; m_pos = safePos;
if (m_path.Count < 3 && m_path.Count > 0) if (m_path.Count < 3 && m_path.Count > 0)
@ -516,11 +516,11 @@ namespace DotRecast.Detour.Crowd
} }
} }
public void trimInvalidPath(long safeRef, float[] safePos, NavMeshQuery navquery, QueryFilter filter) public void TrimInvalidPath(long safeRef, float[] safePos, NavMeshQuery navquery, QueryFilter filter)
{ {
// Keep valid path as far as possible. // Keep valid path as far as possible.
int n = 0; int n = 0;
while (n < m_path.Count && navquery.isValidPolyRef(m_path[n], filter)) while (n < m_path.Count && navquery.IsValidPolyRef(m_path[n], filter))
{ {
n++; n++;
} }
@ -528,7 +528,7 @@ namespace DotRecast.Detour.Crowd
if (n == 0) if (n == 0)
{ {
// The first polyref is bad, use current safe values. // The first polyref is bad, use current safe values.
vCopy(ref m_pos, safePos); VCopy(ref m_pos, safePos);
m_path.Clear(); m_path.Clear();
m_path.Add(safeRef); m_path.Add(safeRef);
} }
@ -539,7 +539,7 @@ namespace DotRecast.Detour.Crowd
} }
// Clamp target pos to last poly // Clamp target pos to last poly
var result = navquery.closestPointOnPolyBoundary(m_path[m_path.Count - 1], m_target); var result = navquery.ClosestPointOnPolyBoundary(m_path[m_path.Count - 1], m_target);
if (result.Succeeded()) if (result.Succeeded())
{ {
m_target = result.result; m_target = result.result;
@ -559,13 +559,13 @@ namespace DotRecast.Detour.Crowd
* The filter to apply to the operation. * The filter to apply to the operation.
* @return * @return
*/ */
public bool isValid(int maxLookAhead, NavMeshQuery navquery, QueryFilter filter) public bool IsValid(int maxLookAhead, NavMeshQuery navquery, QueryFilter filter)
{ {
// Check that all polygons still pass query filter. // Check that all polygons still pass query filter.
int n = Math.Min(m_path.Count, maxLookAhead); int n = Math.Min(m_path.Count, maxLookAhead);
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
if (!navquery.isValidPolyRef(m_path[i], filter)) if (!navquery.IsValidPolyRef(m_path[i], filter))
{ {
return false; return false;
} }
@ -579,7 +579,7 @@ namespace DotRecast.Detour.Crowd
* *
* @return The current position within the corridor. * @return The current position within the corridor.
*/ */
public Vector3f getPos() public Vector3f GetPos()
{ {
return m_pos; return m_pos;
} }
@ -589,7 +589,7 @@ namespace DotRecast.Detour.Crowd
* *
* @return The current target within the corridor. * @return The current target within the corridor.
*/ */
public Vector3f getTarget() public Vector3f GetTarget()
{ {
return m_target; return m_target;
} }
@ -599,7 +599,7 @@ namespace DotRecast.Detour.Crowd
* *
* @return The polygon reference id of the first polygon in the corridor. (Or zero if there is no path.) * @return The polygon reference id of the first polygon in the corridor. (Or zero if there is no path.)
*/ */
public long getFirstPoly() public long GetFirstPoly()
{ {
return 0 == m_path.Count ? 0 : m_path[0]; return 0 == m_path.Count ? 0 : m_path[0];
} }
@ -609,7 +609,7 @@ namespace DotRecast.Detour.Crowd
* *
* @return The polygon reference id of the last polygon in the corridor. (Or zero if there is no path.) * @return The polygon reference id of the last polygon in the corridor. (Or zero if there is no path.)
*/ */
public long getLastPoly() public long GetLastPoly()
{ {
return 0 == m_path.Count ? 0 : m_path[m_path.Count - 1]; return 0 == m_path.Count ? 0 : m_path[m_path.Count - 1];
} }
@ -617,7 +617,7 @@ namespace DotRecast.Detour.Crowd
/** /**
* The corridor's path. * The corridor's path.
*/ */
public List<long> getPath() public List<long> GetPath()
{ {
return m_path; return m_path;
} }
@ -627,7 +627,7 @@ namespace DotRecast.Detour.Crowd
* *
* @return The number of polygons in the current corridor path. * @return The number of polygons in the current corridor path.
*/ */
public int getPathCount() public int GetPathCount()
{ {
return m_path.Count; return m_path.Count;
} }

View File

@ -36,7 +36,7 @@ namespace DotRecast.Detour.Crowd
this.config = config; this.config = config;
} }
public void update(NavMesh navMesh) public void Update(NavMesh navMesh)
{ {
// Update path request until there is nothing to update or up to maxIters pathfinder iterations has been // Update path request until there is nothing to update or up to maxIters pathfinder iterations has been
// consumed. // consumed.
@ -54,32 +54,32 @@ namespace DotRecast.Detour.Crowd
if (q.result.status == null) if (q.result.status == null)
{ {
q.navQuery = new NavMeshQuery(navMesh); q.navQuery = new NavMeshQuery(navMesh);
q.result.status = q.navQuery.initSlicedFindPath(q.startRef, q.endRef, q.startPos, q.endPos, q.filter, 0); q.result.status = q.navQuery.InitSlicedFindPath(q.startRef, q.endRef, q.startPos, q.endPos, q.filter, 0);
} }
// Handle query in progress. // Handle query in progress.
if (q.result.status.isInProgress()) if (q.result.status.IsInProgress())
{ {
Result<int> res = q.navQuery.updateSlicedFindPath(iterCount); Result<int> res = q.navQuery.UpdateSlicedFindPath(iterCount);
q.result.status = res.status; q.result.status = res.status;
iterCount -= res.result; iterCount -= res.result;
} }
if (q.result.status.isSuccess()) if (q.result.status.IsSuccess())
{ {
Result<List<long>> path = q.navQuery.finalizeSlicedFindPath(); Result<List<long>> path = q.navQuery.FinalizeSlicedFindPath();
q.result.status = path.status; q.result.status = path.status;
q.result.path = path.result; q.result.path = path.result;
} }
if (!(q.result.status.isFailed() || q.result.status.isSuccess())) if (!(q.result.status.IsFailed() || q.result.status.IsSuccess()))
{ {
queue.AddFirst(q); queue.AddFirst(q);
} }
} }
} }
public PathQueryResult request(long startRef, long endRef, Vector3f startPos, Vector3f endPos, QueryFilter filter) public PathQueryResult Request(long startRef, long endRef, Vector3f startPos, Vector3f endPos, QueryFilter filter)
{ {
if (queue.Count >= config.pathQueueSize) if (queue.Count >= config.pathQueueSize)
{ {

View File

@ -49,12 +49,12 @@ namespace DotRecast.Detour.Crowd.Tracking
m_tpen = new float[m_maxSamples]; m_tpen = new float[m_maxSamples];
} }
public void reset() public void Reset()
{ {
m_nsamples = 0; m_nsamples = 0;
} }
void normalizeArray(float[] arr, int n) void NormalizeArray(float[] arr, int n)
{ {
// Normalize penaly range. // Normalize penaly range.
float minPen = float.MaxValue; float minPen = float.MaxValue;
@ -68,19 +68,19 @@ namespace DotRecast.Detour.Crowd.Tracking
float penRange = maxPen - minPen; float penRange = maxPen - minPen;
float s = penRange > 0.001f ? (1.0f / penRange) : 1; float s = penRange > 0.001f ? (1.0f / penRange) : 1;
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
arr[i] = clamp((arr[i] - minPen) * s, 0.0f, 1.0f); arr[i] = Clamp((arr[i] - minPen) * s, 0.0f, 1.0f);
} }
public void normalizeSamples() public void NormalizeSamples()
{ {
normalizeArray(m_pen, m_nsamples); NormalizeArray(m_pen, m_nsamples);
normalizeArray(m_vpen, m_nsamples); NormalizeArray(m_vpen, m_nsamples);
normalizeArray(m_vcpen, m_nsamples); NormalizeArray(m_vcpen, m_nsamples);
normalizeArray(m_spen, m_nsamples); NormalizeArray(m_spen, m_nsamples);
normalizeArray(m_tpen, m_nsamples); NormalizeArray(m_tpen, m_nsamples);
} }
public void addSample(Vector3f vel, float ssize, float pen, float vpen, float vcpen, float spen, float tpen) public void AddSample(Vector3f vel, float ssize, float pen, float vpen, float vcpen, float spen, float tpen)
{ {
if (m_nsamples >= m_maxSamples) if (m_nsamples >= m_maxSamples)
return; return;
@ -96,12 +96,12 @@ namespace DotRecast.Detour.Crowd.Tracking
m_nsamples++; m_nsamples++;
} }
public int getSampleCount() public int GetSampleCount()
{ {
return m_nsamples; return m_nsamples;
} }
public Vector3f getSampleVelocity(int i) public Vector3f GetSampleVelocity(int i)
{ {
Vector3f vel = new Vector3f(); Vector3f vel = new Vector3f();
vel.x = m_vel[i * 3]; vel.x = m_vel[i * 3];
@ -110,32 +110,32 @@ namespace DotRecast.Detour.Crowd.Tracking
return vel; return vel;
} }
public float getSampleSize(int i) public float GetSampleSize(int i)
{ {
return m_ssize[i]; return m_ssize[i];
} }
public float getSamplePenalty(int i) public float GetSamplePenalty(int i)
{ {
return m_pen[i]; return m_pen[i];
} }
public float getSampleDesiredVelocityPenalty(int i) public float GetSampleDesiredVelocityPenalty(int i)
{ {
return m_vpen[i]; return m_vpen[i];
} }
public float getSampleCurrentVelocityPenalty(int i) public float GetSampleCurrentVelocityPenalty(int i)
{ {
return m_vcpen[i]; return m_vcpen[i];
} }
public float getSamplePreferredSidePenalty(int i) public float GetSamplePreferredSidePenalty(int i)
{ {
return m_spen[i]; return m_spen[i];
} }
public float getSampleCollisionTimePenalty(int i) public float GetSampleCollisionTimePenalty(int i)
{ {
return m_tpen[i]; return m_tpen[i];
} }

View File

@ -34,14 +34,14 @@ namespace DotRecast.Detour.Dynamic
_affectedTiles = affectedTiles; _affectedTiles = affectedTiles;
} }
public ICollection<DynamicTile> affectedTiles() public ICollection<DynamicTile> AffectedTiles()
{ {
return _affectedTiles; return _affectedTiles;
} }
public void process(DynamicTile tile) public void Process(DynamicTile tile)
{ {
tile.addCollider(colliderId, collider); tile.AddCollider(colliderId, collider);
} }
} }
} }

View File

@ -33,11 +33,11 @@ namespace DotRecast.Detour.Dynamic.Colliders
this._bounds = bounds; this._bounds = bounds;
} }
public float[] bounds() public float[] Bounds()
{ {
return _bounds; return _bounds;
} }
public abstract void rasterize(Heightfield hf, Telemetry telemetry); public abstract void Rasterize(Heightfield hf, Telemetry telemetry);
} }
} }

View File

@ -28,13 +28,13 @@ namespace DotRecast.Detour.Dynamic.Colliders
private readonly Vector3f[] halfEdges; private readonly Vector3f[] halfEdges;
public BoxCollider(Vector3f center, Vector3f[] halfEdges, int area, float flagMergeThreshold) : public BoxCollider(Vector3f center, Vector3f[] halfEdges, int area, float flagMergeThreshold) :
base(area, flagMergeThreshold, bounds(center, halfEdges)) base(area, flagMergeThreshold, Bounds(center, halfEdges))
{ {
this.center = center; this.center = center;
this.halfEdges = halfEdges; this.halfEdges = halfEdges;
} }
private static float[] bounds(Vector3f center, Vector3f[] halfEdges) private static float[] Bounds(Vector3f center, Vector3f[] halfEdges)
{ {
float[] bounds = new float[] float[] bounds = new float[]
{ {
@ -60,13 +60,13 @@ namespace DotRecast.Detour.Dynamic.Colliders
return bounds; return bounds;
} }
public override void rasterize(Heightfield hf, Telemetry telemetry) public override void Rasterize(Heightfield hf, Telemetry telemetry)
{ {
RecastFilledVolumeRasterization.rasterizeBox( RecastFilledVolumeRasterization.RasterizeBox(
hf, center, halfEdges, area, (int)Math.Floor(flagMergeThreshold / hf.ch), telemetry); hf, center, halfEdges, area, (int)Math.Floor(flagMergeThreshold / hf.ch), telemetry);
} }
public static Vector3f[] getHalfEdges(Vector3f up, Vector3f forward, Vector3f extent) public static Vector3f[] GetHalfEdges(Vector3f up, Vector3f forward, Vector3f extent)
{ {
Vector3f[] halfEdges = Vector3f[] halfEdges =
{ {
@ -74,11 +74,11 @@ namespace DotRecast.Detour.Dynamic.Colliders
Vector3f.Of(up.x, up.y, up.z), Vector3f.Of(up.x, up.y, up.z),
Vector3f.Zero Vector3f.Zero
}; };
RecastVectors.normalize(ref halfEdges[1]); RecastVectors.Normalize(ref halfEdges[1]);
RecastVectors.cross(ref halfEdges[0], up, forward); RecastVectors.Cross(ref halfEdges[0], up, forward);
RecastVectors.normalize(ref halfEdges[0]); RecastVectors.Normalize(ref halfEdges[0]);
RecastVectors.cross(ref halfEdges[2], halfEdges[0], up); RecastVectors.Cross(ref halfEdges[2], halfEdges[0], up);
RecastVectors.normalize(ref halfEdges[2]); RecastVectors.Normalize(ref halfEdges[2]);
halfEdges[0].x *= extent.x; halfEdges[0].x *= extent.x;
halfEdges[0].y *= extent.x; halfEdges[0].y *= extent.x;
halfEdges[0].z *= extent.x; halfEdges[0].z *= extent.x;

View File

@ -29,20 +29,20 @@ namespace DotRecast.Detour.Dynamic.Colliders
private readonly float radius; private readonly float radius;
public CapsuleCollider(Vector3f start, Vector3f end, float radius, int area, float flagMergeThreshold) : public CapsuleCollider(Vector3f start, Vector3f end, float radius, int area, float flagMergeThreshold) :
base(area, flagMergeThreshold, bounds(start, end, radius)) base(area, flagMergeThreshold, Bounds(start, end, radius))
{ {
this.start = start; this.start = start;
this.end = end; this.end = end;
this.radius = radius; this.radius = radius;
} }
public override void rasterize(Heightfield hf, Telemetry telemetry) public override void Rasterize(Heightfield hf, Telemetry telemetry)
{ {
RecastFilledVolumeRasterization.rasterizeCapsule(hf, start, end, radius, area, (int)Math.Floor(flagMergeThreshold / hf.ch), RecastFilledVolumeRasterization.RasterizeCapsule(hf, start, end, radius, area, (int)Math.Floor(flagMergeThreshold / hf.ch),
telemetry); telemetry);
} }
private static float[] bounds(Vector3f start, Vector3f end, float radius) private static float[] Bounds(Vector3f start, Vector3f end, float radius)
{ {
return new float[] return new float[]
{ {

View File

@ -22,7 +22,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
{ {
public interface Collider public interface Collider
{ {
float[] bounds(); float[] Bounds();
void rasterize(Heightfield hf, Telemetry telemetry); void Rasterize(Heightfield hf, Telemetry telemetry);
} }
} }

View File

@ -31,21 +31,21 @@ namespace DotRecast.Detour.Dynamic.Colliders
public CompositeCollider(List<Collider> colliders) public CompositeCollider(List<Collider> colliders)
{ {
this.colliders = colliders; this.colliders = colliders;
_bounds = bounds(colliders); _bounds = Bounds(colliders);
} }
public CompositeCollider(params Collider[] colliders) public CompositeCollider(params Collider[] colliders)
{ {
this.colliders = colliders.ToList(); this.colliders = colliders.ToList();
_bounds = bounds(this.colliders); _bounds = Bounds(this.colliders);
} }
public float[] bounds() public float[] Bounds()
{ {
return _bounds; return _bounds;
} }
private static float[] bounds(List<Collider> colliders) private static float[] Bounds(List<Collider> colliders)
{ {
float[] bounds = new float[] float[] bounds = new float[]
{ {
@ -54,7 +54,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
}; };
foreach (Collider collider in colliders) foreach (Collider collider in colliders)
{ {
float[] b = collider.bounds(); float[] b = collider.Bounds();
bounds[0] = Math.Min(bounds[0], b[0]); bounds[0] = Math.Min(bounds[0], b[0]);
bounds[1] = Math.Min(bounds[1], b[1]); bounds[1] = Math.Min(bounds[1], b[1]);
bounds[2] = Math.Min(bounds[2], b[2]); bounds[2] = Math.Min(bounds[2], b[2]);
@ -66,10 +66,10 @@ namespace DotRecast.Detour.Dynamic.Colliders
return bounds; return bounds;
} }
public void rasterize(Heightfield hf, Telemetry telemetry) public void Rasterize(Heightfield hf, Telemetry telemetry)
{ {
foreach (var c in colliders) foreach (var c in colliders)
c.rasterize(hf, telemetry); c.Rasterize(hf, telemetry);
} }
} }
} }

View File

@ -27,7 +27,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
private readonly int[] triangles; private readonly int[] triangles;
public ConvexTrimeshCollider(float[] vertices, int[] triangles, int area, float flagMergeThreshold) : public ConvexTrimeshCollider(float[] vertices, int[] triangles, int area, float flagMergeThreshold) :
base(area, flagMergeThreshold, TrimeshCollider.computeBounds(vertices)) base(area, flagMergeThreshold, TrimeshCollider.ComputeBounds(vertices))
{ {
this.vertices = vertices; this.vertices = vertices;
this.triangles = triangles; this.triangles = triangles;
@ -40,9 +40,9 @@ namespace DotRecast.Detour.Dynamic.Colliders
this.triangles = triangles; this.triangles = triangles;
} }
public override void rasterize(Heightfield hf, Telemetry telemetry) public override void Rasterize(Heightfield hf, Telemetry telemetry)
{ {
RecastFilledVolumeRasterization.rasterizeConvex(hf, vertices, triangles, area, RecastFilledVolumeRasterization.RasterizeConvex(hf, vertices, triangles, area,
(int)Math.Floor(flagMergeThreshold / hf.ch), telemetry); (int)Math.Floor(flagMergeThreshold / hf.ch), telemetry);
} }
} }

View File

@ -29,20 +29,20 @@ namespace DotRecast.Detour.Dynamic.Colliders
private readonly float radius; private readonly float radius;
public CylinderCollider(Vector3f start, Vector3f end, float radius, int area, float flagMergeThreshold) : public CylinderCollider(Vector3f start, Vector3f end, float radius, int area, float flagMergeThreshold) :
base(area, flagMergeThreshold, bounds(start, end, radius)) base(area, flagMergeThreshold, Bounds(start, end, radius))
{ {
this.start = start; this.start = start;
this.end = end; this.end = end;
this.radius = radius; this.radius = radius;
} }
public override void rasterize(Heightfield hf, Telemetry telemetry) public override void Rasterize(Heightfield hf, Telemetry telemetry)
{ {
RecastFilledVolumeRasterization.rasterizeCylinder(hf, start, end, radius, area, (int)Math.Floor(flagMergeThreshold / hf.ch), RecastFilledVolumeRasterization.RasterizeCylinder(hf, start, end, radius, area, (int)Math.Floor(flagMergeThreshold / hf.ch),
telemetry); telemetry);
} }
private static float[] bounds(Vector3f start, Vector3f end, float radius) private static float[] Bounds(Vector3f start, Vector3f end, float radius)
{ {
return new float[] return new float[]
{ {

View File

@ -28,19 +28,19 @@ namespace DotRecast.Detour.Dynamic.Colliders
private readonly float radius; private readonly float radius;
public SphereCollider(Vector3f center, float radius, int area, float flagMergeThreshold) : public SphereCollider(Vector3f center, float radius, int area, float flagMergeThreshold) :
base(area, flagMergeThreshold, bounds(center, radius)) base(area, flagMergeThreshold, Bounds(center, radius))
{ {
this.center = center; this.center = center;
this.radius = radius; this.radius = radius;
} }
public override void rasterize(Heightfield hf, Telemetry telemetry) public override void Rasterize(Heightfield hf, Telemetry telemetry)
{ {
RecastFilledVolumeRasterization.rasterizeSphere(hf, center, radius, area, (int)Math.Floor(flagMergeThreshold / hf.ch), RecastFilledVolumeRasterization.RasterizeSphere(hf, center, radius, area, (int)Math.Floor(flagMergeThreshold / hf.ch),
telemetry); telemetry);
} }
private static float[] bounds(Vector3f center, float radius) private static float[] Bounds(Vector3f center, float radius)
{ {
return new float[] return new float[]
{ {

View File

@ -27,7 +27,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
private readonly int[] triangles; private readonly int[] triangles;
public TrimeshCollider(float[] vertices, int[] triangles, int area, float flagMergeThreshold) : public TrimeshCollider(float[] vertices, int[] triangles, int area, float flagMergeThreshold) :
base(area, flagMergeThreshold, computeBounds(vertices)) base(area, flagMergeThreshold, ComputeBounds(vertices))
{ {
this.vertices = vertices; this.vertices = vertices;
this.triangles = triangles; this.triangles = triangles;
@ -40,7 +40,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
this.triangles = triangles; this.triangles = triangles;
} }
public static float[] computeBounds(float[] vertices) public static float[] ComputeBounds(float[] vertices)
{ {
float[] bounds = new float[] { vertices[0], vertices[1], vertices[2], vertices[0], vertices[1], vertices[2] }; float[] bounds = new float[] { vertices[0], vertices[1], vertices[2], vertices[0], vertices[1], vertices[2] };
for (int i = 3; i < vertices.Length; i += 3) for (int i = 3; i < vertices.Length; i += 3)
@ -56,11 +56,11 @@ namespace DotRecast.Detour.Dynamic.Colliders
return bounds; return bounds;
} }
public override void rasterize(Heightfield hf, Telemetry telemetry) public override void Rasterize(Heightfield hf, Telemetry telemetry)
{ {
for (int i = 0; i < triangles.Length; i += 3) for (int i = 0; i < triangles.Length; i += 3)
{ {
RecastRasterization.rasterizeTriangle(hf, vertices, triangles[i], triangles[i + 1], triangles[i + 2], area, RecastRasterization.RasterizeTriangle(hf, vertices, triangles[i], triangles[i + 1], triangles[i + 2], area,
(int)Math.Floor(flagMergeThreshold / hf.ch), telemetry); (int)Math.Floor(flagMergeThreshold / hf.ch), telemetry);
} }
} }

View File

@ -68,14 +68,14 @@ namespace DotRecast.Detour.Dynamic
navMeshParams.maxPolys = 0x8000; navMeshParams.maxPolys = 0x8000;
foreach (var t in voxelFile.tiles) foreach (var t in voxelFile.tiles)
{ {
_tiles.Add(lookupKey(t.tileX, t.tileZ), new DynamicTile(t)); _tiles.Add(LookupKey(t.tileX, t.tileZ), new DynamicTile(t));
} }
; ;
telemetry = new Telemetry(); telemetry = new Telemetry();
} }
public NavMesh navMesh() public NavMesh NavMesh()
{ {
return _navMesh; return _navMesh;
} }
@ -83,64 +83,64 @@ namespace DotRecast.Detour.Dynamic
/** /**
* Voxel queries require checkpoints to be enabled in {@link DynamicNavMeshConfig} * Voxel queries require checkpoints to be enabled in {@link DynamicNavMeshConfig}
*/ */
public VoxelQuery voxelQuery() public VoxelQuery VoxelQuery()
{ {
return new VoxelQuery(navMeshParams.orig, navMeshParams.tileWidth, navMeshParams.tileHeight, lookupHeightfield); return new VoxelQuery(navMeshParams.orig, navMeshParams.tileWidth, navMeshParams.tileHeight, LookupHeightfield);
} }
private Heightfield lookupHeightfield(int x, int z) private Heightfield LookupHeightfield(int x, int z)
{ {
return getTileAt(x, z)?.checkpoint.heightfield; return GetTileAt(x, z)?.checkpoint.heightfield;
} }
public long addCollider(Collider collider) public long AddCollider(Collider collider)
{ {
long cid = currentColliderId.IncrementAndGet(); long cid = currentColliderId.IncrementAndGet();
updateQueue.Add(new AddColliderQueueItem(cid, collider, getTiles(collider.bounds()))); updateQueue.Add(new AddColliderQueueItem(cid, collider, GetTiles(collider.Bounds())));
return cid; return cid;
} }
public void removeCollider(long colliderId) public void RemoveCollider(long colliderId)
{ {
updateQueue.Add(new RemoveColliderQueueItem(colliderId, getTilesByCollider(colliderId))); updateQueue.Add(new RemoveColliderQueueItem(colliderId, GetTilesByCollider(colliderId)));
} }
/** /**
* Perform full build of the nav mesh * Perform full build of the nav mesh
*/ */
public void build() public void Build()
{ {
processQueue(); ProcessQueue();
rebuild(_tiles.Values); Rebuild(_tiles.Values);
} }
/** /**
* Perform incremental update of the nav mesh * Perform incremental update of the nav mesh
*/ */
public bool update() public bool Update()
{ {
return rebuild(processQueue()); return Rebuild(ProcessQueue());
} }
private bool rebuild(ICollection<DynamicTile> stream) private bool Rebuild(ICollection<DynamicTile> stream)
{ {
foreach (var dynamicTile in stream) foreach (var dynamicTile in stream)
rebuild(dynamicTile); Rebuild(dynamicTile);
return updateNavMesh(); return UpdateNavMesh();
} }
private HashSet<DynamicTile> processQueue() private HashSet<DynamicTile> ProcessQueue()
{ {
var items = consumeQueue(); var items = ConsumeQueue();
foreach (var item in items) foreach (var item in items)
{ {
process(item); Process(item);
} }
return items.SelectMany(i => i.affectedTiles()).ToHashSet(); return items.SelectMany(i => i.AffectedTiles()).ToHashSet();
} }
private List<UpdateQueueItem> consumeQueue() private List<UpdateQueueItem> ConsumeQueue()
{ {
List<UpdateQueueItem> items = new List<UpdateQueueItem>(); List<UpdateQueueItem> items = new List<UpdateQueueItem>();
while (updateQueue.TryTake(out var item)) while (updateQueue.TryTake(out var item))
@ -151,38 +151,38 @@ namespace DotRecast.Detour.Dynamic
return items; return items;
} }
private void process(UpdateQueueItem item) private void Process(UpdateQueueItem item)
{ {
foreach (var tile in item.affectedTiles()) foreach (var tile in item.AffectedTiles())
{ {
item.process(tile); item.Process(tile);
} }
} }
/** /**
* Perform full build concurrently using the given {@link ExecutorService} * Perform full build concurrently using the given {@link ExecutorService}
*/ */
public Task<bool> build(TaskFactory executor) public Task<bool> Build(TaskFactory executor)
{ {
processQueue(); ProcessQueue();
return rebuild(_tiles.Values, executor); return Rebuild(_tiles.Values, executor);
} }
/** /**
* Perform incremental update concurrently using the given {@link ExecutorService} * Perform incremental update concurrently using the given {@link ExecutorService}
*/ */
public Task<bool> update(TaskFactory executor) public Task<bool> Update(TaskFactory executor)
{ {
return rebuild(processQueue(), executor); return Rebuild(ProcessQueue(), executor);
} }
private Task<bool> rebuild(ICollection<DynamicTile> tiles, TaskFactory executor) private Task<bool> Rebuild(ICollection<DynamicTile> tiles, TaskFactory executor)
{ {
var tasks = tiles.Select(tile => executor.StartNew(() => rebuild(tile))).ToArray(); var tasks = tiles.Select(tile => executor.StartNew(() => Rebuild(tile))).ToArray();
return Task.WhenAll(tasks).ContinueWith(k => updateNavMesh()); return Task.WhenAll(tasks).ContinueWith(k => UpdateNavMesh());
} }
private ICollection<DynamicTile> getTiles(float[] bounds) private ICollection<DynamicTile> GetTiles(float[] bounds)
{ {
if (bounds == null) if (bounds == null)
{ {
@ -198,7 +198,7 @@ namespace DotRecast.Detour.Dynamic
{ {
for (int x = minx; x <= maxx; ++x) for (int x = minx; x <= maxx; ++x)
{ {
DynamicTile tile = getTileAt(x, z); DynamicTile tile = GetTileAt(x, z);
if (tile != null) if (tile != null)
{ {
tiles.Add(tile); tiles.Add(tile);
@ -209,25 +209,25 @@ namespace DotRecast.Detour.Dynamic
return tiles; return tiles;
} }
private List<DynamicTile> getTilesByCollider(long cid) private List<DynamicTile> GetTilesByCollider(long cid)
{ {
return _tiles.Values.Where(t => t.containsCollider(cid)).ToList(); return _tiles.Values.Where(t => t.ContainsCollider(cid)).ToList();
} }
private void rebuild(DynamicTile tile) private void Rebuild(DynamicTile tile)
{ {
NavMeshDataCreateParams option = new NavMeshDataCreateParams(); NavMeshDataCreateParams option = new NavMeshDataCreateParams();
option.walkableHeight = config.walkableHeight; option.walkableHeight = config.walkableHeight;
dirty = dirty | tile.build(builder, config, telemetry); dirty = dirty | tile.Build(builder, config, telemetry);
} }
private bool updateNavMesh() private bool UpdateNavMesh()
{ {
if (dirty) if (dirty)
{ {
NavMesh navMesh = new NavMesh(navMeshParams, MAX_VERTS_PER_POLY); NavMesh navMesh = new NavMesh(navMeshParams, MAX_VERTS_PER_POLY);
foreach (var t in _tiles.Values) foreach (var t in _tiles.Values)
t.addTo(navMesh); t.AddTo(navMesh);
this._navMesh = navMesh; this._navMesh = navMesh;
dirty = false; dirty = false;
@ -237,24 +237,24 @@ namespace DotRecast.Detour.Dynamic
return false; return false;
} }
private DynamicTile getTileAt(int x, int z) private DynamicTile GetTileAt(int x, int z)
{ {
return _tiles.TryGetValue(lookupKey(x, z), out var tile) return _tiles.TryGetValue(LookupKey(x, z), out var tile)
? tile ? tile
: null; : null;
} }
private long lookupKey(long x, long z) private long LookupKey(long x, long z)
{ {
return (z << 32) | x; return (z << 32) | x;
} }
public List<VoxelTile> voxelTiles() public List<VoxelTile> VoxelTiles()
{ {
return _tiles.Values.Select(t => t.voxelTile).ToList(); return _tiles.Values.Select(t => t.voxelTile).ToList();
} }
public List<RecastBuilderResult> recastResults() public List<RecastBuilderResult> RecastResults()
{ {
return _tiles.Values.Select(t => t.recastResult).ToList(); return _tiles.Values.Select(t => t.recastResult).ToList();
} }

View File

@ -42,31 +42,31 @@ namespace DotRecast.Detour.Dynamic
this.voxelTile = voxelTile; this.voxelTile = voxelTile;
} }
public bool build(RecastBuilder builder, DynamicNavMeshConfig config, Telemetry telemetry) public bool Build(RecastBuilder builder, DynamicNavMeshConfig config, Telemetry telemetry)
{ {
if (dirty) if (dirty)
{ {
Heightfield heightfield = buildHeightfield(config, telemetry); Heightfield heightfield = BuildHeightfield(config, telemetry);
RecastBuilderResult r = buildRecast(builder, config, voxelTile, heightfield, telemetry); RecastBuilderResult r = BuildRecast(builder, config, voxelTile, heightfield, telemetry);
NavMeshDataCreateParams option = navMeshCreateParams(voxelTile.tileX, voxelTile.tileZ, voxelTile.cellSize, NavMeshDataCreateParams option = NavMeshCreateParams(voxelTile.tileX, voxelTile.tileZ, voxelTile.cellSize,
voxelTile.cellHeight, config, r); voxelTile.cellHeight, config, r);
meshData = NavMeshBuilder.createNavMeshData(option); meshData = NavMeshBuilder.CreateNavMeshData(option);
return true; return true;
} }
return false; return false;
} }
private Heightfield buildHeightfield(DynamicNavMeshConfig config, Telemetry telemetry) private Heightfield BuildHeightfield(DynamicNavMeshConfig config, Telemetry telemetry)
{ {
ICollection<long> rasterizedColliders = checkpoint != null ? checkpoint.colliders : ImmutableHashSet<long>.Empty; ICollection<long> rasterizedColliders = checkpoint != null ? checkpoint.colliders : ImmutableHashSet<long>.Empty;
Heightfield heightfield = checkpoint != null ? checkpoint.heightfield : voxelTile.heightfield(); Heightfield heightfield = checkpoint != null ? checkpoint.heightfield : voxelTile.Heightfield();
foreach (var (cid, c) in colliders) foreach (var (cid, c) in colliders)
{ {
if (!rasterizedColliders.Contains(cid)) if (!rasterizedColliders.Contains(cid))
{ {
heightfield.bmax.y = Math.Max(heightfield.bmax.y, c.bounds()[4] + heightfield.ch * 2); heightfield.bmax.y = Math.Max(heightfield.bmax.y, c.Bounds()[4] + heightfield.ch * 2);
c.rasterize(heightfield, telemetry); c.Rasterize(heightfield, telemetry);
} }
} }
@ -78,7 +78,7 @@ namespace DotRecast.Detour.Dynamic
return heightfield; return heightfield;
} }
private RecastBuilderResult buildRecast(RecastBuilder builder, DynamicNavMeshConfig config, VoxelTile vt, private RecastBuilderResult BuildRecast(RecastBuilder builder, DynamicNavMeshConfig config, VoxelTile vt,
Heightfield heightfield, Telemetry telemetry) Heightfield heightfield, Telemetry telemetry)
{ {
RecastConfig rcConfig = new RecastConfig(config.useTiles, config.tileSizeX, config.tileSizeZ, vt.borderSize, RecastConfig rcConfig = new RecastConfig(config.useTiles, config.tileSizeX, config.tileSizeZ, vt.borderSize,
@ -87,7 +87,7 @@ namespace DotRecast.Detour.Dynamic
config.maxEdgeLen, config.maxSimplificationError, config.maxEdgeLen, config.maxSimplificationError,
Math.Min(DynamicNavMesh.MAX_VERTS_PER_POLY, config.vertsPerPoly), true, config.detailSampleDistance, Math.Min(DynamicNavMesh.MAX_VERTS_PER_POLY, config.vertsPerPoly), true, config.detailSampleDistance,
config.detailSampleMaxError, null); config.detailSampleMaxError, null);
RecastBuilderResult r = builder.build(vt.tileX, vt.tileZ, null, rcConfig, heightfield, telemetry); RecastBuilderResult r = builder.Build(vt.tileX, vt.tileZ, null, rcConfig, heightfield, telemetry);
if (config.keepIntermediateResults) if (config.keepIntermediateResults)
{ {
recastResult = r; recastResult = r;
@ -96,18 +96,18 @@ namespace DotRecast.Detour.Dynamic
return r; return r;
} }
public void addCollider(long cid, Collider collider) public void AddCollider(long cid, Collider collider)
{ {
colliders[cid] = collider; colliders[cid] = collider;
dirty = true; dirty = true;
} }
public bool containsCollider(long cid) public bool ContainsCollider(long cid)
{ {
return colliders.ContainsKey(cid); return colliders.ContainsKey(cid);
} }
public void removeCollider(long colliderId) public void RemoveCollider(long colliderId)
{ {
if (colliders.TryRemove(colliderId, out var collider)) if (colliders.TryRemove(colliderId, out var collider))
{ {
@ -116,11 +116,11 @@ namespace DotRecast.Detour.Dynamic
} }
} }
private NavMeshDataCreateParams navMeshCreateParams(int tilex, int tileZ, float cellSize, float cellHeight, private NavMeshDataCreateParams NavMeshCreateParams(int tilex, int tileZ, float cellSize, float cellHeight,
DynamicNavMeshConfig config, RecastBuilderResult rcResult) DynamicNavMeshConfig config, RecastBuilderResult rcResult)
{ {
PolyMesh m_pmesh = rcResult.getMesh(); PolyMesh m_pmesh = rcResult.GetMesh();
PolyMeshDetail m_dmesh = rcResult.getMeshDetail(); PolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
NavMeshDataCreateParams option = new NavMeshDataCreateParams(); NavMeshDataCreateParams option = new NavMeshDataCreateParams();
for (int i = 0; i < m_pmesh.npolys; ++i) for (int i = 0; i < m_pmesh.npolys; ++i)
{ {
@ -164,15 +164,15 @@ namespace DotRecast.Detour.Dynamic
return option; return option;
} }
public void addTo(NavMesh navMesh) public void AddTo(NavMesh navMesh)
{ {
if (meshData != null) if (meshData != null)
{ {
id = navMesh.addTile(meshData, 0, 0); id = navMesh.AddTile(meshData, 0, 0);
} }
else else
{ {
navMesh.removeTile(id); navMesh.RemoveTile(id);
id = 0; id = 0;
} }
} }

View File

@ -30,10 +30,10 @@ namespace DotRecast.Detour.Dynamic
public DynamicTileCheckpoint(Heightfield heightfield, ISet<long> colliders) public DynamicTileCheckpoint(Heightfield heightfield, ISet<long> colliders)
{ {
this.colliders = colliders; this.colliders = colliders;
this.heightfield = clone(heightfield); this.heightfield = Clone(heightfield);
} }
private Heightfield clone(Heightfield source) private Heightfield Clone(Heightfield source)
{ {
Heightfield clone = new Heightfield(source.width, source.height, source.bmin, source.bmax, source.cs, Heightfield clone = new Heightfield(source.width, source.height, source.bmin, source.bmax, source.cs,
source.ch, source.borderSize); source.ch, source.borderSize);

View File

@ -22,39 +22,39 @@ namespace DotRecast.Detour.Dynamic.Io
{ {
public static class ByteUtils public static class ByteUtils
{ {
public static int getInt(byte[] data, int position, ByteOrder order) public static int GetInt(byte[] data, int position, ByteOrder order)
{ {
return order == ByteOrder.BIG_ENDIAN ? getIntBE(data, position) : getIntLE(data, position); return order == ByteOrder.BIG_ENDIAN ? GetIntBE(data, position) : GetIntLE(data, position);
} }
public static int getIntBE(byte[] data, int position) public static int GetIntBE(byte[] data, int position)
{ {
return ((data[position] & 0xff) << 24) | ((data[position + 1] & 0xff) << 16) | ((data[position + 2] & 0xff) << 8) return ((data[position] & 0xff) << 24) | ((data[position + 1] & 0xff) << 16) | ((data[position + 2] & 0xff) << 8)
| (data[position + 3] & 0xff); | (data[position + 3] & 0xff);
} }
public static int getIntLE(byte[] data, int position) public static int GetIntLE(byte[] data, int position)
{ {
return ((data[position + 3] & 0xff) << 24) | ((data[position + 2] & 0xff) << 16) | ((data[position + 1] & 0xff) << 8) return ((data[position + 3] & 0xff) << 24) | ((data[position + 2] & 0xff) << 16) | ((data[position + 1] & 0xff) << 8)
| (data[position] & 0xff); | (data[position] & 0xff);
} }
public static int getShort(byte[] data, int position, ByteOrder order) public static int GetShort(byte[] data, int position, ByteOrder order)
{ {
return order == ByteOrder.BIG_ENDIAN ? getShortBE(data, position) : getShortLE(data, position); return order == ByteOrder.BIG_ENDIAN ? GetShortBE(data, position) : GetShortLE(data, position);
} }
public static int getShortBE(byte[] data, int position) public static int GetShortBE(byte[] data, int position)
{ {
return ((data[position] & 0xff) << 8) | (data[position + 1] & 0xff); return ((data[position] & 0xff) << 8) | (data[position + 1] & 0xff);
} }
public static int getShortLE(byte[] data, int position) public static int GetShortLE(byte[] data, int position)
{ {
return ((data[position + 1] & 0xff) << 8) | (data[position] & 0xff); return ((data[position + 1] & 0xff) << 8) | (data[position] & 0xff);
} }
public static int putInt(int value, byte[] data, int position, ByteOrder order) public static int PutInt(int value, byte[] data, int position, ByteOrder order)
{ {
if (order == ByteOrder.BIG_ENDIAN) if (order == ByteOrder.BIG_ENDIAN)
{ {
@ -74,7 +74,7 @@ namespace DotRecast.Detour.Dynamic.Io
return position + 4; return position + 4;
} }
public static int putShort(int value, byte[] data, int position, ByteOrder order) public static int PutShort(int value, byte[] data, int position, ByteOrder order)
{ {
if (order == ByteOrder.BIG_ENDIAN) if (order == ByteOrder.BIG_ENDIAN)
{ {

View File

@ -24,17 +24,17 @@ namespace DotRecast.Detour.Dynamic.Io
{ {
public class LZ4VoxelTileCompressor public class LZ4VoxelTileCompressor
{ {
public byte[] decompress(byte[] data) public byte[] Decompress(byte[] data)
{ {
int compressedSize = ByteUtils.getIntBE(data, 0); int compressedSize = ByteUtils.GetIntBE(data, 0);
return LZ4Pickler.Unpickle(data.AsSpan(4, compressedSize)); return LZ4Pickler.Unpickle(data.AsSpan(4, compressedSize));
} }
public byte[] compress(byte[] data) public byte[] Compress(byte[] data)
{ {
byte[] compressed = LZ4Pickler.Pickle(data, LZ4Level.L12_MAX); byte[] compressed = LZ4Pickler.Pickle(data, LZ4Level.L12_MAX);
byte[] result = new byte[4 + compressed.Length]; byte[] result = new byte[4 + compressed.Length];
ByteUtils.putInt(compressed.Length, result, 0, ByteOrder.BIG_ENDIAN); ByteUtils.PutInt(compressed.Length, result, 0, ByteOrder.BIG_ENDIAN);
Array.Copy(compressed, 0, result, 4, compressed.Length); Array.Copy(compressed, 0, result, 4, compressed.Length);
return result; return result;
} }

View File

@ -56,12 +56,12 @@ namespace DotRecast.Detour.Dynamic.Io
public float[] bounds = new float[6]; public float[] bounds = new float[6];
public readonly List<VoxelTile> tiles = new List<VoxelTile>(); public readonly List<VoxelTile> tiles = new List<VoxelTile>();
public void addTile(VoxelTile tile) public void AddTile(VoxelTile tile)
{ {
tiles.Add(tile); tiles.Add(tile);
} }
public RecastConfig getConfig(VoxelTile tile, PartitionType partitionType, int maxPolyVerts, int regionMergeSize, public RecastConfig GetConfig(VoxelTile tile, PartitionType partitionType, int maxPolyVerts, int regionMergeSize,
bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans, bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans,
AreaModification walkbableAreaMod, bool buildMeshDetail, float detailSampleDist, float detailSampleMaxError) AreaModification walkbableAreaMod, bool buildMeshDetail, float detailSampleDist, float detailSampleMaxError)
{ {
@ -71,7 +71,7 @@ namespace DotRecast.Detour.Dynamic.Io
buildMeshDetail, detailSampleDist, detailSampleMaxError, walkbableAreaMod); buildMeshDetail, detailSampleDist, detailSampleMaxError, walkbableAreaMod);
} }
public static VoxelFile from(RecastConfig config, List<RecastBuilderResult> results) public static VoxelFile From(RecastConfig config, List<RecastBuilderResult> results)
{ {
VoxelFile f = new VoxelFile(); VoxelFile f = new VoxelFile();
f.version = 1; f.version = 1;
@ -102,19 +102,19 @@ namespace DotRecast.Detour.Dynamic.Io
}; };
foreach (RecastBuilderResult r in results) foreach (RecastBuilderResult r in results)
{ {
f.tiles.Add(new VoxelTile(r.tileX, r.tileZ, r.getSolidHeightfield())); f.tiles.Add(new VoxelTile(r.tileX, r.tileZ, r.GetSolidHeightfield()));
f.bounds[0] = Math.Min(f.bounds[0], r.getSolidHeightfield().bmin.x); f.bounds[0] = Math.Min(f.bounds[0], r.GetSolidHeightfield().bmin.x);
f.bounds[1] = Math.Min(f.bounds[1], r.getSolidHeightfield().bmin.y); f.bounds[1] = Math.Min(f.bounds[1], r.GetSolidHeightfield().bmin.y);
f.bounds[2] = Math.Min(f.bounds[2], r.getSolidHeightfield().bmin.z); f.bounds[2] = Math.Min(f.bounds[2], r.GetSolidHeightfield().bmin.z);
f.bounds[3] = Math.Max(f.bounds[3], r.getSolidHeightfield().bmax.x); f.bounds[3] = Math.Max(f.bounds[3], r.GetSolidHeightfield().bmax.x);
f.bounds[4] = Math.Max(f.bounds[4], r.getSolidHeightfield().bmax.y); f.bounds[4] = Math.Max(f.bounds[4], r.GetSolidHeightfield().bmax.y);
f.bounds[5] = Math.Max(f.bounds[5], r.getSolidHeightfield().bmax.z); f.bounds[5] = Math.Max(f.bounds[5], r.GetSolidHeightfield().bmax.z);
} }
return f; return f;
} }
public static VoxelFile from(DynamicNavMesh mesh) public static VoxelFile From(DynamicNavMesh mesh)
{ {
VoxelFile f = new VoxelFile(); VoxelFile f = new VoxelFile();
f.version = 1; f.version = 1;
@ -144,9 +144,9 @@ namespace DotRecast.Detour.Dynamic.Io
float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity,
float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity
}; };
foreach (VoxelTile vt in mesh.voxelTiles()) foreach (VoxelTile vt in mesh.VoxelTiles())
{ {
Heightfield heightfield = vt.heightfield(); Heightfield heightfield = vt.Heightfield();
f.tiles.Add(new VoxelTile(vt.tileX, vt.tileZ, heightfield)); f.tiles.Add(new VoxelTile(vt.tileX, vt.tileZ, heightfield));
f.bounds[0] = Math.Min(f.bounds[0], vt.boundsMin.x); f.bounds[0] = Math.Min(f.bounds[0], vt.boundsMin.x);
f.bounds[1] = Math.Min(f.bounds[1], vt.boundsMin.y); f.bounds[1] = Math.Min(f.bounds[1], vt.boundsMin.y);

View File

@ -26,40 +26,40 @@ namespace DotRecast.Detour.Dynamic.Io
{ {
private readonly LZ4VoxelTileCompressor compressor = new LZ4VoxelTileCompressor(); private readonly LZ4VoxelTileCompressor compressor = new LZ4VoxelTileCompressor();
public VoxelFile read(BinaryReader stream) public VoxelFile Read(BinaryReader stream)
{ {
ByteBuffer buf = IOUtils.toByteBuffer(stream); ByteBuffer buf = IOUtils.ToByteBuffer(stream);
VoxelFile file = new VoxelFile(); VoxelFile file = new VoxelFile();
int magic = buf.getInt(); int magic = buf.GetInt();
if (magic != VoxelFile.MAGIC) if (magic != VoxelFile.MAGIC)
{ {
magic = IOUtils.swapEndianness(magic); magic = IOUtils.SwapEndianness(magic);
if (magic != VoxelFile.MAGIC) if (magic != VoxelFile.MAGIC)
{ {
throw new IOException("Invalid magic"); throw new IOException("Invalid magic");
} }
buf.order(buf.order() == ByteOrder.BIG_ENDIAN ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); buf.Order(buf.Order() == ByteOrder.BIG_ENDIAN ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
} }
file.version = buf.getInt(); file.version = buf.GetInt();
bool isExportedFromAstar = (file.version & VoxelFile.VERSION_EXPORTER_MASK) == 0; bool isExportedFromAstar = (file.version & VoxelFile.VERSION_EXPORTER_MASK) == 0;
bool compression = (file.version & VoxelFile.VERSION_COMPRESSION_MASK) == VoxelFile.VERSION_COMPRESSION_LZ4; bool compression = (file.version & VoxelFile.VERSION_COMPRESSION_MASK) == VoxelFile.VERSION_COMPRESSION_LZ4;
file.walkableRadius = buf.getFloat(); file.walkableRadius = buf.GetFloat();
file.walkableHeight = buf.getFloat(); file.walkableHeight = buf.GetFloat();
file.walkableClimb = buf.getFloat(); file.walkableClimb = buf.GetFloat();
file.walkableSlopeAngle = buf.getFloat(); file.walkableSlopeAngle = buf.GetFloat();
file.cellSize = buf.getFloat(); file.cellSize = buf.GetFloat();
file.maxSimplificationError = buf.getFloat(); file.maxSimplificationError = buf.GetFloat();
file.maxEdgeLen = buf.getFloat(); file.maxEdgeLen = buf.GetFloat();
file.minRegionArea = (int)buf.getFloat(); file.minRegionArea = (int)buf.GetFloat();
if (!isExportedFromAstar) if (!isExportedFromAstar)
{ {
file.regionMergeArea = buf.getFloat(); file.regionMergeArea = buf.GetFloat();
file.vertsPerPoly = buf.getInt(); file.vertsPerPoly = buf.GetInt();
file.buildMeshDetail = buf.get() != 0; file.buildMeshDetail = buf.Get() != 0;
file.detailSampleDistance = buf.getFloat(); file.detailSampleDistance = buf.GetFloat();
file.detailSampleMaxError = buf.getFloat(); file.detailSampleMaxError = buf.GetFloat();
} }
else else
{ {
@ -70,18 +70,18 @@ namespace DotRecast.Detour.Dynamic.Io
file.detailSampleMaxError = file.maxSimplificationError * 0.8f; file.detailSampleMaxError = file.maxSimplificationError * 0.8f;
} }
file.useTiles = buf.get() != 0; file.useTiles = buf.Get() != 0;
file.tileSizeX = buf.getInt(); file.tileSizeX = buf.GetInt();
file.tileSizeZ = buf.getInt(); file.tileSizeZ = buf.GetInt();
file.rotation.x = buf.getFloat(); file.rotation.x = buf.GetFloat();
file.rotation.y = buf.getFloat(); file.rotation.y = buf.GetFloat();
file.rotation.z = buf.getFloat(); file.rotation.z = buf.GetFloat();
file.bounds[0] = buf.getFloat(); file.bounds[0] = buf.GetFloat();
file.bounds[1] = buf.getFloat(); file.bounds[1] = buf.GetFloat();
file.bounds[2] = buf.getFloat(); file.bounds[2] = buf.GetFloat();
file.bounds[3] = buf.getFloat(); file.bounds[3] = buf.GetFloat();
file.bounds[4] = buf.getFloat(); file.bounds[4] = buf.GetFloat();
file.bounds[5] = buf.getFloat(); file.bounds[5] = buf.GetFloat();
if (isExportedFromAstar) if (isExportedFromAstar)
{ {
// bounds are saved as center + size // bounds are saved as center + size
@ -93,22 +93,22 @@ namespace DotRecast.Detour.Dynamic.Io
file.bounds[5] += file.bounds[2]; file.bounds[5] += file.bounds[2];
} }
int tileCount = buf.getInt(); int tileCount = buf.GetInt();
for (int tile = 0; tile < tileCount; tile++) for (int tile = 0; tile < tileCount; tile++)
{ {
int tileX = buf.getInt(); int tileX = buf.GetInt();
int tileZ = buf.getInt(); int tileZ = buf.GetInt();
int width = buf.getInt(); int width = buf.GetInt();
int depth = buf.getInt(); int depth = buf.GetInt();
int borderSize = buf.getInt(); int borderSize = buf.GetInt();
Vector3f boundsMin = new Vector3f(); Vector3f boundsMin = new Vector3f();
boundsMin.x = buf.getFloat(); boundsMin.x = buf.GetFloat();
boundsMin.y = buf.getFloat(); boundsMin.y = buf.GetFloat();
boundsMin.z = buf.getFloat(); boundsMin.z = buf.GetFloat();
Vector3f boundsMax = new Vector3f(); Vector3f boundsMax = new Vector3f();
boundsMax.x = buf.getFloat(); boundsMax.x = buf.GetFloat();
boundsMax.y = buf.getFloat(); boundsMax.y = buf.GetFloat();
boundsMax.z = buf.getFloat(); boundsMax.z = buf.GetFloat();
if (isExportedFromAstar) if (isExportedFromAstar)
{ {
// bounds are local // bounds are local
@ -120,20 +120,20 @@ namespace DotRecast.Detour.Dynamic.Io
boundsMax.z += file.bounds[2]; boundsMax.z += file.bounds[2];
} }
float cellSize = buf.getFloat(); float cellSize = buf.GetFloat();
float cellHeight = buf.getFloat(); float cellHeight = buf.GetFloat();
int voxelSize = buf.getInt(); int voxelSize = buf.GetInt();
int position = buf.position(); int position = buf.Position();
byte[] bytes = buf.ReadBytes(voxelSize).ToArray(); byte[] bytes = buf.ReadBytes(voxelSize).ToArray();
if (compression) if (compression)
{ {
bytes = compressor.decompress(bytes); bytes = compressor.Decompress(bytes);
} }
ByteBuffer data = new ByteBuffer(bytes); ByteBuffer data = new ByteBuffer(bytes);
data.order(buf.order()); data.Order(buf.Order());
file.addTile(new VoxelTile(tileX, tileZ, width, depth, boundsMin, boundsMax, cellSize, cellHeight, borderSize, data)); file.AddTile(new VoxelTile(tileX, tileZ, width, depth, boundsMin, boundsMax, cellSize, cellHeight, borderSize, data));
buf.position(position + voxelSize); buf.Position(position + voxelSize);
} }
return file; return file;

View File

@ -26,69 +26,69 @@ namespace DotRecast.Detour.Dynamic.Io
{ {
private readonly LZ4VoxelTileCompressor compressor = new LZ4VoxelTileCompressor(); private readonly LZ4VoxelTileCompressor compressor = new LZ4VoxelTileCompressor();
public void write(BinaryWriter stream, VoxelFile f, bool compression) public void Write(BinaryWriter stream, VoxelFile f, bool compression)
{ {
write(stream, f, VoxelFile.PREFERRED_BYTE_ORDER, compression); Write(stream, f, VoxelFile.PREFERRED_BYTE_ORDER, compression);
} }
public void write(BinaryWriter stream, VoxelFile f, ByteOrder byteOrder, bool compression) public void Write(BinaryWriter stream, VoxelFile f, ByteOrder byteOrder, bool compression)
{ {
write(stream, VoxelFile.MAGIC, byteOrder); Write(stream, VoxelFile.MAGIC, byteOrder);
write(stream, VoxelFile.VERSION_EXPORTER_RECAST4J | (compression ? VoxelFile.VERSION_COMPRESSION_LZ4 : 0), byteOrder); Write(stream, VoxelFile.VERSION_EXPORTER_RECAST4J | (compression ? VoxelFile.VERSION_COMPRESSION_LZ4 : 0), byteOrder);
write(stream, f.walkableRadius, byteOrder); Write(stream, f.walkableRadius, byteOrder);
write(stream, f.walkableHeight, byteOrder); Write(stream, f.walkableHeight, byteOrder);
write(stream, f.walkableClimb, byteOrder); Write(stream, f.walkableClimb, byteOrder);
write(stream, f.walkableSlopeAngle, byteOrder); Write(stream, f.walkableSlopeAngle, byteOrder);
write(stream, f.cellSize, byteOrder); Write(stream, f.cellSize, byteOrder);
write(stream, f.maxSimplificationError, byteOrder); Write(stream, f.maxSimplificationError, byteOrder);
write(stream, f.maxEdgeLen, byteOrder); Write(stream, f.maxEdgeLen, byteOrder);
write(stream, f.minRegionArea, byteOrder); Write(stream, f.minRegionArea, byteOrder);
write(stream, f.regionMergeArea, byteOrder); Write(stream, f.regionMergeArea, byteOrder);
write(stream, f.vertsPerPoly, byteOrder); Write(stream, f.vertsPerPoly, byteOrder);
write(stream, f.buildMeshDetail); Write(stream, f.buildMeshDetail);
write(stream, f.detailSampleDistance, byteOrder); Write(stream, f.detailSampleDistance, byteOrder);
write(stream, f.detailSampleMaxError, byteOrder); Write(stream, f.detailSampleMaxError, byteOrder);
write(stream, f.useTiles); Write(stream, f.useTiles);
write(stream, f.tileSizeX, byteOrder); Write(stream, f.tileSizeX, byteOrder);
write(stream, f.tileSizeZ, byteOrder); Write(stream, f.tileSizeZ, byteOrder);
write(stream, f.rotation.x, byteOrder); Write(stream, f.rotation.x, byteOrder);
write(stream, f.rotation.y, byteOrder); Write(stream, f.rotation.y, byteOrder);
write(stream, f.rotation.z, byteOrder); Write(stream, f.rotation.z, byteOrder);
write(stream, f.bounds[0], byteOrder); Write(stream, f.bounds[0], byteOrder);
write(stream, f.bounds[1], byteOrder); Write(stream, f.bounds[1], byteOrder);
write(stream, f.bounds[2], byteOrder); Write(stream, f.bounds[2], byteOrder);
write(stream, f.bounds[3], byteOrder); Write(stream, f.bounds[3], byteOrder);
write(stream, f.bounds[4], byteOrder); Write(stream, f.bounds[4], byteOrder);
write(stream, f.bounds[5], byteOrder); Write(stream, f.bounds[5], byteOrder);
write(stream, f.tiles.Count, byteOrder); Write(stream, f.tiles.Count, byteOrder);
foreach (VoxelTile t in f.tiles) foreach (VoxelTile t in f.tiles)
{ {
writeTile(stream, t, byteOrder, compression); WriteTile(stream, t, byteOrder, compression);
} }
} }
public void writeTile(BinaryWriter stream, VoxelTile tile, ByteOrder byteOrder, bool compression) public void WriteTile(BinaryWriter stream, VoxelTile tile, ByteOrder byteOrder, bool compression)
{ {
write(stream, tile.tileX, byteOrder); Write(stream, tile.tileX, byteOrder);
write(stream, tile.tileZ, byteOrder); Write(stream, tile.tileZ, byteOrder);
write(stream, tile.width, byteOrder); Write(stream, tile.width, byteOrder);
write(stream, tile.depth, byteOrder); Write(stream, tile.depth, byteOrder);
write(stream, tile.borderSize, byteOrder); Write(stream, tile.borderSize, byteOrder);
write(stream, tile.boundsMin.x, byteOrder); Write(stream, tile.boundsMin.x, byteOrder);
write(stream, tile.boundsMin.y, byteOrder); Write(stream, tile.boundsMin.y, byteOrder);
write(stream, tile.boundsMin.z, byteOrder); Write(stream, tile.boundsMin.z, byteOrder);
write(stream, tile.boundsMax.x, byteOrder); Write(stream, tile.boundsMax.x, byteOrder);
write(stream, tile.boundsMax.y, byteOrder); Write(stream, tile.boundsMax.y, byteOrder);
write(stream, tile.boundsMax.z, byteOrder); Write(stream, tile.boundsMax.z, byteOrder);
write(stream, tile.cellSize, byteOrder); Write(stream, tile.cellSize, byteOrder);
write(stream, tile.cellHeight, byteOrder); Write(stream, tile.cellHeight, byteOrder);
byte[] bytes = tile.spanData; byte[] bytes = tile.spanData;
if (compression) if (compression)
{ {
bytes = compressor.compress(bytes); bytes = compressor.Compress(bytes);
} }
write(stream, bytes.Length, byteOrder); Write(stream, bytes.Length, byteOrder);
stream.Write(bytes); stream.Write(bytes);
} }
} }

View File

@ -48,7 +48,7 @@ namespace DotRecast.Detour.Dynamic.Io
this.cellSize = cellSize; this.cellSize = cellSize;
this.cellHeight = cellHeight; this.cellHeight = cellHeight;
this.borderSize = borderSize; this.borderSize = borderSize;
spanData = toByteArray(buffer, width, depth, VoxelFile.PREFERRED_BYTE_ORDER); spanData = ToByteArray(buffer, width, depth, VoxelFile.PREFERRED_BYTE_ORDER);
} }
public VoxelTile(int tileX, int tileZ, Heightfield heightfield) public VoxelTile(int tileX, int tileZ, Heightfield heightfield)
@ -62,15 +62,15 @@ namespace DotRecast.Detour.Dynamic.Io
cellSize = heightfield.cs; cellSize = heightfield.cs;
cellHeight = heightfield.ch; cellHeight = heightfield.ch;
borderSize = heightfield.borderSize; borderSize = heightfield.borderSize;
spanData = serializeSpans(heightfield, VoxelFile.PREFERRED_BYTE_ORDER); spanData = SerializeSpans(heightfield, VoxelFile.PREFERRED_BYTE_ORDER);
} }
public Heightfield heightfield() public Heightfield Heightfield()
{ {
return VoxelFile.PREFERRED_BYTE_ORDER == ByteOrder.BIG_ENDIAN ? heightfieldBE() : heightfieldLE(); return VoxelFile.PREFERRED_BYTE_ORDER == ByteOrder.BIG_ENDIAN ? HeightfieldBE() : HeightfieldLE();
} }
private Heightfield heightfieldBE() private Heightfield HeightfieldBE()
{ {
Heightfield hf = new Heightfield(width, depth, boundsMin, boundsMax, cellSize, cellHeight, borderSize); Heightfield hf = new Heightfield(width, depth, boundsMin, boundsMax, cellSize, cellHeight, borderSize);
int position = 0; int position = 0;
@ -79,16 +79,16 @@ namespace DotRecast.Detour.Dynamic.Io
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
Span prev = null; Span prev = null;
int spanCount = ByteUtils.getShortBE(spanData, position); int spanCount = ByteUtils.GetShortBE(spanData, position);
position += 2; position += 2;
for (int s = 0; s < spanCount; s++) for (int s = 0; s < spanCount; s++)
{ {
Span span = new Span(); Span span = new Span();
span.smin = ByteUtils.getIntBE(spanData, position); span.smin = ByteUtils.GetIntBE(spanData, position);
position += 4; position += 4;
span.smax = ByteUtils.getIntBE(spanData, position); span.smax = ByteUtils.GetIntBE(spanData, position);
position += 4; position += 4;
span.area = ByteUtils.getIntBE(spanData, position); span.area = ByteUtils.GetIntBE(spanData, position);
position += 4; position += 4;
if (prev == null) if (prev == null)
{ {
@ -107,7 +107,7 @@ namespace DotRecast.Detour.Dynamic.Io
return hf; return hf;
} }
private Heightfield heightfieldLE() private Heightfield HeightfieldLE()
{ {
Heightfield hf = new Heightfield(width, depth, boundsMin, boundsMax, cellSize, cellHeight, borderSize); Heightfield hf = new Heightfield(width, depth, boundsMin, boundsMax, cellSize, cellHeight, borderSize);
int position = 0; int position = 0;
@ -116,16 +116,16 @@ namespace DotRecast.Detour.Dynamic.Io
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
Span prev = null; Span prev = null;
int spanCount = ByteUtils.getShortLE(spanData, position); int spanCount = ByteUtils.GetShortLE(spanData, position);
position += 2; position += 2;
for (int s = 0; s < spanCount; s++) for (int s = 0; s < spanCount; s++)
{ {
Span span = new Span(); Span span = new Span();
span.smin = ByteUtils.getIntLE(spanData, position); span.smin = ByteUtils.GetIntLE(spanData, position);
position += 4; position += 4;
span.smax = ByteUtils.getIntLE(spanData, position); span.smax = ByteUtils.GetIntLE(spanData, position);
position += 4; position += 4;
span.area = ByteUtils.getIntLE(spanData, position); span.area = ByteUtils.GetIntLE(spanData, position);
position += 4; position += 4;
if (prev == null) if (prev == null)
{ {
@ -144,7 +144,7 @@ namespace DotRecast.Detour.Dynamic.Io
return hf; return hf;
} }
private byte[] serializeSpans(Heightfield heightfield, ByteOrder order) private byte[] SerializeSpans(Heightfield heightfield, ByteOrder order)
{ {
int[] counts = new int[heightfield.width * heightfield.height]; int[] counts = new int[heightfield.width * heightfield.height];
int totalCount = 0; int totalCount = 0;
@ -168,13 +168,13 @@ namespace DotRecast.Detour.Dynamic.Io
{ {
for (int x = 0; x < heightfield.width; x++) for (int x = 0; x < heightfield.width; x++)
{ {
position = ByteUtils.putShort(counts[pz + x], data, position, order); position = ByteUtils.PutShort(counts[pz + x], data, position, order);
Span span = heightfield.spans[pz + x]; Span span = heightfield.spans[pz + x];
while (span != null) while (span != null)
{ {
position = ByteUtils.putInt(span.smin, data, position, order); position = ByteUtils.PutInt(span.smin, data, position, order);
position = ByteUtils.putInt(span.smax, data, position, order); position = ByteUtils.PutInt(span.smax, data, position, order);
position = ByteUtils.putInt(span.area, data, position, order); position = ByteUtils.PutInt(span.area, data, position, order);
span = span.next; span = span.next;
} }
} }
@ -183,30 +183,30 @@ namespace DotRecast.Detour.Dynamic.Io
return data; return data;
} }
private byte[] toByteArray(ByteBuffer buf, int width, int height, ByteOrder order) private byte[] ToByteArray(ByteBuffer buf, int width, int height, ByteOrder order)
{ {
byte[] data; byte[] data;
if (buf.order() == order) if (buf.Order() == order)
{ {
data = buf.ReadBytes(buf.limit()).ToArray(); data = buf.ReadBytes(buf.Limit()).ToArray();
} }
else else
{ {
data = new byte[buf.limit()]; data = new byte[buf.Limit()];
int l = width * height; int l = width * height;
int position = 0; int position = 0;
for (int i = 0; i < l; i++) for (int i = 0; i < l; i++)
{ {
int count = buf.getShort(); int count = buf.GetShort();
ByteUtils.putShort(count, data, position, order); ByteUtils.PutShort(count, data, position, order);
position += 2; position += 2;
for (int j = 0; j < count; j++) for (int j = 0; j < count; j++)
{ {
ByteUtils.putInt(buf.getInt(), data, position, order); ByteUtils.PutInt(buf.GetInt(), data, position, order);
position += 4; position += 4;
ByteUtils.putInt(buf.getInt(), data, position, order); ByteUtils.PutInt(buf.GetInt(), data, position, order);
position += 4; position += 4;
ByteUtils.putInt(buf.getInt(), data, position, order); ByteUtils.PutInt(buf.GetInt(), data, position, order);
position += 4; position += 4;
} }
} }

View File

@ -31,14 +31,14 @@ namespace DotRecast.Detour.Dynamic
this._affectedTiles = affectedTiles; this._affectedTiles = affectedTiles;
} }
public ICollection<DynamicTile> affectedTiles() public ICollection<DynamicTile> AffectedTiles()
{ {
return _affectedTiles; return _affectedTiles;
} }
public void process(DynamicTile tile) public void Process(DynamicTile tile)
{ {
tile.removeCollider(colliderId); tile.RemoveCollider(colliderId);
} }
} }
} }

View File

@ -22,8 +22,8 @@ namespace DotRecast.Detour.Dynamic
{ {
public interface UpdateQueueItem public interface UpdateQueueItem
{ {
ICollection<DynamicTile> affectedTiles(); ICollection<DynamicTile> AffectedTiles();
void process(DynamicTile tile); void Process(DynamicTile tile);
} }
} }

View File

@ -47,12 +47,12 @@ namespace DotRecast.Detour.Dynamic
* *
* @return Optional with hit parameter (t) or empty if no hit found * @return Optional with hit parameter (t) or empty if no hit found
*/ */
public float? raycast(Vector3f start, Vector3f end) public float? Raycast(Vector3f start, Vector3f end)
{ {
return traverseTiles(start, end); return TraverseTiles(start, end);
} }
private float? traverseTiles(Vector3f start, Vector3f end) private float? TraverseTiles(Vector3f start, Vector3f end)
{ {
float relStartX = start.x - origin.x; float relStartX = start.x - origin.x;
float relStartZ = start.z - origin.z; float relStartZ = start.z - origin.z;
@ -79,7 +79,7 @@ namespace DotRecast.Detour.Dynamic
float t = 0; float t = 0;
while (true) while (true)
{ {
float? hit = traversHeightfield(sx, sz, start, end, t, Math.Min(1, Math.Min(tMaxX, tMaxZ))); float? hit = TraversHeightfield(sx, sz, start, end, t, Math.Min(1, Math.Min(tMaxX, tMaxZ)));
if (hit.HasValue) if (hit.HasValue)
{ {
return hit; return hit;
@ -107,7 +107,7 @@ namespace DotRecast.Detour.Dynamic
return null; return null;
} }
private float? traversHeightfield(int x, int z, Vector3f start, Vector3f end, float tMin, float tMax) private float? TraversHeightfield(int x, int z, Vector3f start, Vector3f end, float tMin, float tMax)
{ {
Heightfield hf = heightfieldProvider.Invoke(x, z); Heightfield hf = heightfieldProvider.Invoke(x, z);
if (null != hf) if (null != hf)

View File

@ -23,15 +23,15 @@ namespace DotRecast.Detour.Extras
{ {
public class BVTreeBuilder public class BVTreeBuilder
{ {
public void build(MeshData data) public void Build(MeshData data)
{ {
data.bvTree = new BVNode[data.header.polyCount * 2]; data.bvTree = new BVNode[data.header.polyCount * 2];
data.header.bvNodeCount = data.bvTree.Length == 0 data.header.bvNodeCount = data.bvTree.Length == 0
? 0 ? 0
: createBVTree(data, data.bvTree, data.header.bvQuantFactor); : CreateBVTree(data, data.bvTree, data.header.bvQuantFactor);
} }
private static int createBVTree(MeshData data, BVNode[] nodes, float quantFactor) private static int CreateBVTree(MeshData data, BVNode[] nodes, float quantFactor)
{ {
NavMeshBuilder.BVItem[] items = new NavMeshBuilder.BVItem[data.header.polyCount]; NavMeshBuilder.BVItem[] items = new NavMeshBuilder.BVItem[data.header.polyCount];
for (int i = 0; i < data.header.polyCount; i++) for (int i = 0; i < data.header.polyCount; i++)
@ -41,23 +41,23 @@ namespace DotRecast.Detour.Extras
it.i = i; it.i = i;
Vector3f bmin = new Vector3f(); Vector3f bmin = new Vector3f();
Vector3f bmax = new Vector3f(); Vector3f bmax = new Vector3f();
vCopy(ref bmin, data.verts, data.polys[i].verts[0] * 3); VCopy(ref bmin, data.verts, data.polys[i].verts[0] * 3);
vCopy(ref bmax, data.verts, data.polys[i].verts[0] * 3); VCopy(ref bmax, data.verts, data.polys[i].verts[0] * 3);
for (int j = 1; j < data.polys[i].vertCount; j++) for (int j = 1; j < data.polys[i].vertCount; j++)
{ {
vMin(ref bmin, data.verts, data.polys[i].verts[j] * 3); VMin(ref bmin, data.verts, data.polys[i].verts[j] * 3);
vMax(ref bmax, data.verts, data.polys[i].verts[j] * 3); VMax(ref bmax, data.verts, data.polys[i].verts[j] * 3);
} }
it.bmin[0] = clamp((int)((bmin.x - data.header.bmin.x) * quantFactor), 0, 0x7fffffff); it.bmin[0] = Clamp((int)((bmin.x - data.header.bmin.x) * quantFactor), 0, 0x7fffffff);
it.bmin[1] = clamp((int)((bmin.y - data.header.bmin.y) * quantFactor), 0, 0x7fffffff); it.bmin[1] = Clamp((int)((bmin.y - data.header.bmin.y) * quantFactor), 0, 0x7fffffff);
it.bmin[2] = clamp((int)((bmin.z - data.header.bmin.z) * quantFactor), 0, 0x7fffffff); it.bmin[2] = Clamp((int)((bmin.z - data.header.bmin.z) * quantFactor), 0, 0x7fffffff);
it.bmax[0] = clamp((int)((bmax.x - data.header.bmin.x) * quantFactor), 0, 0x7fffffff); it.bmax[0] = Clamp((int)((bmax.x - data.header.bmin.x) * quantFactor), 0, 0x7fffffff);
it.bmax[1] = clamp((int)((bmax.y - data.header.bmin.y) * quantFactor), 0, 0x7fffffff); it.bmax[1] = Clamp((int)((bmax.y - data.header.bmin.y) * quantFactor), 0, 0x7fffffff);
it.bmax[2] = clamp((int)((bmax.z - data.header.bmin.z) * quantFactor), 0, 0x7fffffff); it.bmax[2] = Clamp((int)((bmax.z - data.header.bmin.z) * quantFactor), 0, 0x7fffffff);
} }
return NavMeshBuilder.subdivide(items, data.header.polyCount, 0, data.header.polyCount, 0, nodes); return NavMeshBuilder.Subdivide(items, data.header.polyCount, 0, data.header.polyCount, 0, nodes);
} }
} }
} }

View File

@ -7,22 +7,22 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
public abstract class AbstractGroundSampler : GroundSampler public abstract class AbstractGroundSampler : GroundSampler
{ {
protected void sampleGround(JumpLinkBuilderConfig acfg, EdgeSampler es, protected void SampleGround(JumpLinkBuilderConfig acfg, EdgeSampler es,
Func<Vector3f, float, Tuple<bool, float>> heightFunc) Func<Vector3f, float, Tuple<bool, float>> heightFunc)
{ {
float cs = acfg.cellSize; float cs = acfg.cellSize;
float dist = (float)Math.Sqrt(vDist2DSqr(es.start.p, es.start.q)); float dist = (float)Math.Sqrt(VDist2DSqr(es.start.p, es.start.q));
int ngsamples = Math.Max(2, (int)Math.Ceiling(dist / cs)); int ngsamples = Math.Max(2, (int)Math.Ceiling(dist / cs));
sampleGroundSegment(heightFunc, es.start, ngsamples); SampleGroundSegment(heightFunc, es.start, ngsamples);
foreach (GroundSegment end in es.end) foreach (GroundSegment end in es.end)
{ {
sampleGroundSegment(heightFunc, end, ngsamples); SampleGroundSegment(heightFunc, end, ngsamples);
} }
} }
public abstract void sample(JumpLinkBuilderConfig acfg, RecastBuilderResult result, EdgeSampler es); public abstract void Sample(JumpLinkBuilderConfig acfg, RecastBuilderResult result, EdgeSampler es);
protected void sampleGroundSegment(Func<Vector3f, float, Tuple<bool, float>> heightFunc, GroundSegment seg, int nsamples) protected void SampleGroundSegment(Func<Vector3f, float, Tuple<bool, float>> heightFunc, GroundSegment seg, int nsamples)
{ {
seg.gsamples = new GroundSample[nsamples]; seg.gsamples = new GroundSample[nsamples];
@ -32,7 +32,7 @@ namespace DotRecast.Detour.Extras.Jumplink
GroundSample s = new GroundSample(); GroundSample s = new GroundSample();
seg.gsamples[i] = s; seg.gsamples[i] = s;
Vector3f pt = vLerp(seg.p, seg.q, u); Vector3f pt = VLerp(seg.p, seg.q, u);
Tuple<bool, float> height = heightFunc.Invoke(pt, seg.height); Tuple<bool, float> height = heightFunc.Invoke(pt, seg.height);
s.p.x = pt.x; s.p.x = pt.x;
s.p.y = height.Item2; s.p.y = height.Item2;

View File

@ -5,13 +5,13 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
public class ClimbTrajectory : Trajectory public class ClimbTrajectory : Trajectory
{ {
public override Vector3f apply(Vector3f start, Vector3f end, float u) public override Vector3f Apply(Vector3f start, Vector3f end, float u)
{ {
return new Vector3f() return new Vector3f()
{ {
x = lerp(start.x, end.x, Math.Min(2f * u, 1f)), x = Lerp(start.x, end.x, Math.Min(2f * u, 1f)),
y = lerp(start.y, end.y, Math.Max(0f, 2f * u - 1f)), y = Lerp(start.y, end.y, Math.Max(0f, 2f * u - 1f)),
z = lerp(start.z, end.z, Math.Min(2f * u, 1f)) z = Lerp(start.z, end.z, Math.Min(2f * u, 1f))
}; };
} }
} }

View File

@ -8,7 +8,7 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
public class EdgeExtractor public class EdgeExtractor
{ {
public Edge[] extractEdges(PolyMesh mesh) public Edge[] ExtractEdges(PolyMesh mesh)
{ {
List<Edge> edges = new List<Edge>(); List<Edge> edges = new List<Edge>();
if (mesh != null) if (mesh != null)

View File

@ -17,11 +17,11 @@ namespace DotRecast.Detour.Extras.Jumplink
public EdgeSampler(Edge edge, Trajectory trajectory) public EdgeSampler(Edge edge, Trajectory trajectory)
{ {
this.trajectory = trajectory; this.trajectory = trajectory;
ax = vSub(edge.sq, edge.sp); ax = VSub(edge.sq, edge.sp);
vNormalize(ref ax); VNormalize(ref ax);
vSet(ref az, ax.z, 0, -ax.x); VSet(ref az, ax.z, 0, -ax.x);
vNormalize(ref az); VNormalize(ref az);
vSet(ref ay, 0, 1, 0); VSet(ref ay, 0, 1, 0);
} }
} }
} }

View File

@ -5,16 +5,16 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
class EdgeSamplerFactory class EdgeSamplerFactory
{ {
public EdgeSampler get(JumpLinkBuilderConfig acfg, JumpLinkType type, Edge edge) public EdgeSampler Get(JumpLinkBuilderConfig acfg, JumpLinkType type, Edge edge)
{ {
EdgeSampler es = null; EdgeSampler es = null;
switch (type.Bit) switch (type.Bit)
{ {
case JumpLinkType.EDGE_JUMP_BIT: case JumpLinkType.EDGE_JUMP_BIT:
es = initEdgeJumpSampler(acfg, edge); es = InitEdgeJumpSampler(acfg, edge);
break; break;
case JumpLinkType.EDGE_CLIMB_DOWN_BIT: case JumpLinkType.EDGE_CLIMB_DOWN_BIT:
es = initClimbDownSampler(acfg, edge); es = InitClimbDownSampler(acfg, edge);
break; break;
case JumpLinkType.EDGE_JUMP_OVER_BIT: case JumpLinkType.EDGE_JUMP_OVER_BIT:
default: default:
@ -25,14 +25,14 @@ namespace DotRecast.Detour.Extras.Jumplink
} }
private EdgeSampler initEdgeJumpSampler(JumpLinkBuilderConfig acfg, Edge edge) private EdgeSampler InitEdgeJumpSampler(JumpLinkBuilderConfig acfg, Edge edge)
{ {
EdgeSampler es = new EdgeSampler(edge, new JumpTrajectory(acfg.jumpHeight)); EdgeSampler es = new EdgeSampler(edge, new JumpTrajectory(acfg.jumpHeight));
es.start.height = acfg.agentClimb * 2; es.start.height = acfg.agentClimb * 2;
Vector3f offset = new Vector3f(); Vector3f offset = new Vector3f();
trans2d(ref offset, es.az, es.ay, new Vector2f { x = acfg.startDistance, y = -acfg.agentClimb, }); Trans2d(ref offset, es.az, es.ay, new Vector2f { x = acfg.startDistance, y = -acfg.agentClimb, });
vadd(ref es.start.p, edge.sp, offset); Vadd(ref es.start.p, edge.sp, offset);
vadd(ref es.start.q, edge.sq, offset); Vadd(ref es.start.q, edge.sq, offset);
float dx = acfg.endDistance - 2 * acfg.agentRadius; float dx = acfg.endDistance - 2 * acfg.agentRadius;
float cs = acfg.cellSize; float cs = acfg.cellSize;
@ -42,43 +42,43 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
float v = (float)j / (float)(nsamples - 1); float v = (float)j / (float)(nsamples - 1);
float ox = 2 * acfg.agentRadius + dx * v; float ox = 2 * acfg.agentRadius + dx * v;
trans2d(ref offset, es.az, es.ay, new Vector2f { x = ox, y = acfg.minHeight }); Trans2d(ref offset, es.az, es.ay, new Vector2f { x = ox, y = acfg.minHeight });
GroundSegment end = new GroundSegment(); GroundSegment end = new GroundSegment();
end.height = acfg.heightRange; end.height = acfg.heightRange;
vadd(ref end.p, edge.sp, offset); Vadd(ref end.p, edge.sp, offset);
vadd(ref end.q, edge.sq, offset); Vadd(ref end.q, edge.sq, offset);
es.end.Add(end); es.end.Add(end);
} }
return es; return es;
} }
private EdgeSampler initClimbDownSampler(JumpLinkBuilderConfig acfg, Edge edge) private EdgeSampler InitClimbDownSampler(JumpLinkBuilderConfig acfg, Edge edge)
{ {
EdgeSampler es = new EdgeSampler(edge, new ClimbTrajectory()); EdgeSampler es = new EdgeSampler(edge, new ClimbTrajectory());
es.start.height = acfg.agentClimb * 2; es.start.height = acfg.agentClimb * 2;
Vector3f offset = new Vector3f(); Vector3f offset = new Vector3f();
trans2d(ref offset, es.az, es.ay, new Vector2f() { x = acfg.startDistance, y = -acfg.agentClimb }); Trans2d(ref offset, es.az, es.ay, new Vector2f() { x = acfg.startDistance, y = -acfg.agentClimb });
vadd(ref es.start.p, edge.sp, offset); Vadd(ref es.start.p, edge.sp, offset);
vadd(ref es.start.q, edge.sq, offset); Vadd(ref es.start.q, edge.sq, offset);
trans2d(ref offset, es.az, es.ay, new Vector2f() { x = acfg.endDistance, y = acfg.minHeight }); Trans2d(ref offset, es.az, es.ay, new Vector2f() { x = acfg.endDistance, y = acfg.minHeight });
GroundSegment end = new GroundSegment(); GroundSegment end = new GroundSegment();
end.height = acfg.heightRange; end.height = acfg.heightRange;
vadd(ref end.p, edge.sp, offset); Vadd(ref end.p, edge.sp, offset);
vadd(ref end.q, edge.sq, offset); Vadd(ref end.q, edge.sq, offset);
es.end.Add(end); es.end.Add(end);
return es; return es;
} }
private void vadd(float[] dest, float[] v1, float[] v2) private void Vadd(float[] dest, float[] v1, float[] v2)
{ {
dest[0] = v1[0] + v2[0]; dest[0] = v1[0] + v2[0];
dest[1] = v1[1] + v2[1]; dest[1] = v1[1] + v2[1];
dest[2] = v1[2] + v2[2]; dest[2] = v1[2] + v2[2];
} }
private void vadd(ref Vector3f dest, Vector3f v1, Vector3f v2) private void Vadd(ref Vector3f dest, Vector3f v1, Vector3f v2)
{ {
dest.x = v1.x + v2.x; dest.x = v1.x + v2.x;
dest.y = v1.y + v2.y; dest.y = v1.y + v2.y;
@ -86,14 +86,14 @@ namespace DotRecast.Detour.Extras.Jumplink
} }
private void trans2d(float[] dst, float[] ax, float[] ay, float[] pt) private void Trans2d(float[] dst, float[] ax, float[] ay, float[] pt)
{ {
dst[0] = ax[0] * pt[0] + ay[0] * pt[1]; dst[0] = ax[0] * pt[0] + ay[0] * pt[1];
dst[1] = ax[1] * pt[0] + ay[1] * pt[1]; dst[1] = ax[1] * pt[0] + ay[1] * pt[1];
dst[2] = ax[2] * pt[0] + ay[2] * pt[1]; dst[2] = ax[2] * pt[0] + ay[2] * pt[1];
} }
private void trans2d(ref Vector3f dst, Vector3f ax, Vector3f ay, Vector2f pt) private void Trans2d(ref Vector3f dst, Vector3f ax, Vector3f ay, Vector2f pt)
{ {
dst.x = ax.x * pt.x + ay.x * pt.y; dst.x = ax.x * pt.x + ay.x * pt.y;
dst.y = ax.y * pt.x + ay.y * pt.y; dst.y = ax.y * pt.x + ay.y * pt.y;

View File

@ -4,6 +4,6 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
public interface GroundSampler public interface GroundSampler
{ {
void sample(JumpLinkBuilderConfig acfg, RecastBuilderResult result, EdgeSampler es); void Sample(JumpLinkBuilderConfig acfg, RecastBuilderResult result, EdgeSampler es);
} }
} }

View File

@ -21,10 +21,10 @@ namespace DotRecast.Detour.Extras.Jumplink
public JumpLinkBuilder(IList<RecastBuilderResult> results) public JumpLinkBuilder(IList<RecastBuilderResult> results)
{ {
this.results = results; this.results = results;
edges = results.Select(r => edgeExtractor.extractEdges(r.getMesh())).ToList(); edges = results.Select(r => edgeExtractor.ExtractEdges(r.GetMesh())).ToList();
} }
public List<JumpLink> build(JumpLinkBuilderConfig acfg, JumpLinkType type) public List<JumpLink> Build(JumpLinkBuilderConfig acfg, JumpLinkType type)
{ {
List<JumpLink> links = new List<JumpLink>(); List<JumpLink> links = new List<JumpLink>();
for (int tile = 0; tile < results.Count; tile++) for (int tile = 0; tile < results.Count; tile++)
@ -32,24 +32,24 @@ namespace DotRecast.Detour.Extras.Jumplink
Edge[] edges = this.edges[tile]; Edge[] edges = this.edges[tile];
foreach (Edge edge in edges) foreach (Edge edge in edges)
{ {
links.AddRange(processEdge(acfg, results[tile], type, edge)); links.AddRange(ProcessEdge(acfg, results[tile], type, edge));
} }
} }
return links; return links;
} }
private List<JumpLink> processEdge(JumpLinkBuilderConfig acfg, RecastBuilderResult result, JumpLinkType type, Edge edge) private List<JumpLink> ProcessEdge(JumpLinkBuilderConfig acfg, RecastBuilderResult result, JumpLinkType type, Edge edge)
{ {
EdgeSampler es = edgeSamplerFactory.get(acfg, type, edge); EdgeSampler es = edgeSamplerFactory.Get(acfg, type, edge);
groundSampler.sample(acfg, result, es); groundSampler.Sample(acfg, result, es);
trajectorySampler.sample(acfg, result.getSolidHeightfield(), es); trajectorySampler.Sample(acfg, result.GetSolidHeightfield(), es);
JumpSegment[] jumpSegments = jumpSegmentBuilder.build(acfg, es); JumpSegment[] jumpSegments = jumpSegmentBuilder.Build(acfg, es);
return buildJumpLinks(acfg, es, jumpSegments); return BuildJumpLinks(acfg, es, jumpSegments);
} }
private List<JumpLink> buildJumpLinks(JumpLinkBuilderConfig acfg, EdgeSampler es, JumpSegment[] jumpSegments) private List<JumpLink> BuildJumpLinks(JumpLinkBuilderConfig acfg, EdgeSampler es, JumpSegment[] jumpSegments)
{ {
List<JumpLink> links = new List<JumpLink>(); List<JumpLink> links = new List<JumpLink>();
foreach (JumpSegment js in jumpSegments) foreach (JumpSegment js in jumpSegments)
@ -59,7 +59,7 @@ namespace DotRecast.Detour.Extras.Jumplink
GroundSegment end = es.end[js.groundSegment]; GroundSegment end = es.end[js.groundSegment];
Vector3f ep = end.gsamples[js.startSample].p; Vector3f ep = end.gsamples[js.startSample].p;
Vector3f eq = end.gsamples[js.startSample + js.samples - 1].p; Vector3f eq = end.gsamples[js.startSample + js.samples - 1].p;
float d = Math.Min(vDist2DSqr(sp, sq), vDist2DSqr(ep, eq)); float d = Math.Min(VDist2DSqr(sp, sq), VDist2DSqr(ep, eq));
if (d >= 4 * acfg.agentRadius * acfg.agentRadius) if (d >= 4 * acfg.agentRadius * acfg.agentRadius)
{ {
JumpLink link = new JumpLink(); JumpLink link = new JumpLink();
@ -72,12 +72,12 @@ namespace DotRecast.Detour.Extras.Jumplink
for (int j = 0; j < link.nspine; ++j) for (int j = 0; j < link.nspine; ++j)
{ {
float u = ((float)j) / (link.nspine - 1); float u = ((float)j) / (link.nspine - 1);
Vector3f p = es.trajectory.apply(sp, ep, u); Vector3f p = es.trajectory.Apply(sp, ep, u);
link.spine0[j * 3] = p.x; link.spine0[j * 3] = p.x;
link.spine0[j * 3 + 1] = p.y; link.spine0[j * 3 + 1] = p.y;
link.spine0[j * 3 + 2] = p.z; link.spine0[j * 3 + 2] = p.z;
p = es.trajectory.apply(sq, eq, u); p = es.trajectory.Apply(sq, eq, u);
link.spine1[j * 3] = p.x; link.spine1[j * 3] = p.x;
link.spine1[j * 3 + 1] = p.y; link.spine1[j * 3 + 1] = p.y;
link.spine1[j * 3 + 2] = p.z; link.spine1[j * 3 + 2] = p.z;
@ -88,7 +88,7 @@ namespace DotRecast.Detour.Extras.Jumplink
return links; return links;
} }
public List<Edge[]> getEdges() public List<Edge[]> GetEdges()
{ {
return edges; return edges;
} }

View File

@ -6,7 +6,7 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
class JumpSegmentBuilder class JumpSegmentBuilder
{ {
public JumpSegment[] build(JumpLinkBuilderConfig acfg, EdgeSampler es) public JumpSegment[] Build(JumpLinkBuilderConfig acfg, EdgeSampler es)
{ {
int n = es.end[0].gsamples.Length; int n = es.end[0].gsamples.Length;
int[][] sampleGrid = ArrayUtils.Of<int>(n, es.end.Count); int[][] sampleGrid = ArrayUtils.Of<int>(n, es.end.Count);
@ -35,7 +35,7 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
var queue = new Queue<int[]>(); var queue = new Queue<int[]>();
queue.Enqueue(new int[] { i, j }); queue.Enqueue(new int[] { i, j });
fill(es, sampleGrid, queue, acfg.agentClimb, region); Fill(es, sampleGrid, queue, acfg.agentClimb, region);
region++; region++;
} }
} }
@ -84,7 +84,7 @@ namespace DotRecast.Detour.Extras.Jumplink
return jumpSegments; return jumpSegments;
} }
private void fill(EdgeSampler es, int[][] sampleGrid, Queue<int[]> queue, float agentClimb, int region) private void Fill(EdgeSampler es, int[][] sampleGrid, Queue<int[]> queue, float agentClimb, int region)
{ {
while (queue.TryDequeue(out var ij)) while (queue.TryDequeue(out var ij))
{ {
@ -97,28 +97,28 @@ namespace DotRecast.Detour.Extras.Jumplink
float h = p.p.y; float h = p.p.y;
if (i < sampleGrid.Length - 1) if (i < sampleGrid.Length - 1)
{ {
addNeighbour(es, queue, agentClimb, h, i + 1, j); AddNeighbour(es, queue, agentClimb, h, i + 1, j);
} }
if (i > 0) if (i > 0)
{ {
addNeighbour(es, queue, agentClimb, h, i - 1, j); AddNeighbour(es, queue, agentClimb, h, i - 1, j);
} }
if (j < sampleGrid[0].Length - 1) if (j < sampleGrid[0].Length - 1)
{ {
addNeighbour(es, queue, agentClimb, h, i, j + 1); AddNeighbour(es, queue, agentClimb, h, i, j + 1);
} }
if (j > 0) if (j > 0)
{ {
addNeighbour(es, queue, agentClimb, h, i, j - 1); AddNeighbour(es, queue, agentClimb, h, i, j - 1);
} }
} }
} }
} }
private void addNeighbour(EdgeSampler es, Queue<int[]> queue, float agentClimb, float h, int i, int j) private void AddNeighbour(EdgeSampler es, Queue<int[]> queue, float agentClimb, float h, int i, int j)
{ {
GroundSample q = es.end[j].gsamples[i]; GroundSample q = es.end[j].gsamples[i];
if (q.validTrajectory && Math.Abs(q.p.y - h) < agentClimb) if (q.validTrajectory && Math.Abs(q.p.y - h) < agentClimb)

View File

@ -12,17 +12,17 @@ namespace DotRecast.Detour.Extras.Jumplink
this.jumpHeight = jumpHeight; this.jumpHeight = jumpHeight;
} }
public override Vector3f apply(Vector3f start, Vector3f end, float u) public override Vector3f Apply(Vector3f start, Vector3f end, float u)
{ {
return new Vector3f return new Vector3f
{ {
x = lerp(start.x, end.x, u), x = Lerp(start.x, end.x, u),
y = interpolateHeight(start.y, end.y, u), y = InterpolateHeight(start.y, end.y, u),
z = lerp(start.z, end.z, u) z = Lerp(start.z, end.z, u)
}; };
} }
private float interpolateHeight(float ys, float ye, float u) private float InterpolateHeight(float ys, float ye, float u)
{ {
if (u == 0f) if (u == 0f)
{ {

View File

@ -11,48 +11,48 @@ namespace DotRecast.Detour.Extras.Jumplink
private class NoOpFilter : QueryFilter private class NoOpFilter : QueryFilter
{ {
public bool passFilter(long refs, MeshTile tile, Poly poly) public bool PassFilter(long refs, MeshTile tile, Poly poly)
{ {
return true; return true;
} }
public float getCost(Vector3f pa, Vector3f pb, long prevRef, MeshTile prevTile, Poly prevPoly, long curRef, public float GetCost(Vector3f pa, Vector3f pb, long prevRef, MeshTile prevTile, Poly prevPoly, long curRef,
MeshTile curTile, Poly curPoly, long nextRef, MeshTile nextTile, Poly nextPoly) MeshTile curTile, Poly curPoly, long nextRef, MeshTile nextTile, Poly nextPoly)
{ {
return 0; return 0;
} }
} }
public override void sample(JumpLinkBuilderConfig acfg, RecastBuilderResult result, EdgeSampler es) public override void Sample(JumpLinkBuilderConfig acfg, RecastBuilderResult result, EdgeSampler es)
{ {
NavMeshQuery navMeshQuery = createNavMesh(result, acfg.agentRadius, acfg.agentHeight, acfg.agentClimb); NavMeshQuery navMeshQuery = CreateNavMesh(result, acfg.agentRadius, acfg.agentHeight, acfg.agentClimb);
sampleGround(acfg, es, (pt, h) => getNavMeshHeight(navMeshQuery, pt, acfg.cellSize, h)); SampleGround(acfg, es, (pt, h) => GetNavMeshHeight(navMeshQuery, pt, acfg.cellSize, h));
} }
private NavMeshQuery createNavMesh(RecastBuilderResult r, float agentRadius, float agentHeight, float agentClimb) private NavMeshQuery CreateNavMesh(RecastBuilderResult r, float agentRadius, float agentHeight, float agentClimb)
{ {
NavMeshDataCreateParams option = new NavMeshDataCreateParams(); NavMeshDataCreateParams option = new NavMeshDataCreateParams();
option.verts = r.getMesh().verts; option.verts = r.GetMesh().verts;
option.vertCount = r.getMesh().nverts; option.vertCount = r.GetMesh().nverts;
option.polys = r.getMesh().polys; option.polys = r.GetMesh().polys;
option.polyAreas = r.getMesh().areas; option.polyAreas = r.GetMesh().areas;
option.polyFlags = r.getMesh().flags; option.polyFlags = r.GetMesh().flags;
option.polyCount = r.getMesh().npolys; option.polyCount = r.GetMesh().npolys;
option.nvp = r.getMesh().nvp; option.nvp = r.GetMesh().nvp;
option.detailMeshes = r.getMeshDetail().meshes; option.detailMeshes = r.GetMeshDetail().meshes;
option.detailVerts = r.getMeshDetail().verts; option.detailVerts = r.GetMeshDetail().verts;
option.detailVertsCount = r.getMeshDetail().nverts; option.detailVertsCount = r.GetMeshDetail().nverts;
option.detailTris = r.getMeshDetail().tris; option.detailTris = r.GetMeshDetail().tris;
option.detailTriCount = r.getMeshDetail().ntris; option.detailTriCount = r.GetMeshDetail().ntris;
option.walkableRadius = agentRadius; option.walkableRadius = agentRadius;
option.walkableHeight = agentHeight; option.walkableHeight = agentHeight;
option.walkableClimb = agentClimb; option.walkableClimb = agentClimb;
option.bmin = r.getMesh().bmin; option.bmin = r.GetMesh().bmin;
option.bmax = r.getMesh().bmax; option.bmax = r.GetMesh().bmax;
option.cs = r.getMesh().cs; option.cs = r.GetMesh().cs;
option.ch = r.getMesh().ch; option.ch = r.GetMesh().ch;
option.buildBvTree = true; option.buildBvTree = true;
return new NavMeshQuery(new NavMesh(NavMeshBuilder.createNavMeshData(option), option.nvp, 0)); return new NavMeshQuery(new NavMesh(NavMeshBuilder.CreateNavMeshData(option), option.nvp, 0));
} }
public class PolyQueryInvoker : PolyQuery public class PolyQueryInvoker : PolyQuery
@ -64,32 +64,32 @@ namespace DotRecast.Detour.Extras.Jumplink
_callback = callback; _callback = callback;
} }
public void process(MeshTile tile, Poly poly, long refs) public void Process(MeshTile tile, Poly poly, long refs)
{ {
_callback?.Invoke(tile, poly, refs); _callback?.Invoke(tile, poly, refs);
} }
} }
private Tuple<bool, float> getNavMeshHeight(NavMeshQuery navMeshQuery, Vector3f pt, float cs, float heightRange) private Tuple<bool, float> GetNavMeshHeight(NavMeshQuery navMeshQuery, Vector3f pt, float cs, float heightRange)
{ {
Vector3f halfExtents = new Vector3f { x = cs, y = heightRange, z = cs }; Vector3f halfExtents = new Vector3f { x = cs, y = heightRange, z = cs };
float maxHeight = pt.y + heightRange; float maxHeight = pt.y + heightRange;
AtomicBoolean found = new AtomicBoolean(); AtomicBoolean found = new AtomicBoolean();
AtomicFloat minHeight = new AtomicFloat(pt.y); AtomicFloat minHeight = new AtomicFloat(pt.y);
navMeshQuery.queryPolygons(pt, halfExtents, filter, new PolyQueryInvoker((tile, poly, refs) => navMeshQuery.QueryPolygons(pt, halfExtents, filter, new PolyQueryInvoker((tile, poly, refs) =>
{ {
Result<float> h = navMeshQuery.getPolyHeight(refs, pt); Result<float> h = navMeshQuery.GetPolyHeight(refs, pt);
if (h.Succeeded()) if (h.Succeeded())
{ {
float y = h.result; float y = h.result;
if (y > minHeight.Get() && y < maxHeight) if (y > minHeight.Get() && y < maxHeight)
{ {
minHeight.Exchange(y); minHeight.Exchange(y);
found.set(true); found.Set(true);
} }
} }
})); }));
if (found.get()) if (found.Get())
{ {
return Tuple.Create(true, minHeight.Get()); return Tuple.Create(true, minHeight.Get());
} }

View File

@ -5,12 +5,12 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
public class Trajectory public class Trajectory
{ {
public float lerp(float f, float g, float u) public float Lerp(float f, float g, float u)
{ {
return u * g + (1f - u) * f; return u * g + (1f - u) * f;
} }
public virtual Vector3f apply(Vector3f start, Vector3f end, float u) public virtual Vector3f Apply(Vector3f start, Vector3f end, float u)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -7,7 +7,7 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
class TrajectorySampler class TrajectorySampler
{ {
public void sample(JumpLinkBuilderConfig acfg, Heightfield heightfield, EdgeSampler es) public void Sample(JumpLinkBuilderConfig acfg, Heightfield heightfield, EdgeSampler es)
{ {
int nsamples = es.start.gsamples.Length; int nsamples = es.start.gsamples.Length;
for (int i = 0; i < nsamples; ++i) for (int i = 0; i < nsamples; ++i)
@ -21,7 +21,7 @@ namespace DotRecast.Detour.Extras.Jumplink
continue; continue;
} }
if (!sampleTrajectory(acfg, heightfield, ssmp.p, esmp.p, es.trajectory)) if (!SampleTrajectory(acfg, heightfield, ssmp.p, esmp.p, es.trajectory))
{ {
continue; continue;
} }
@ -32,16 +32,16 @@ namespace DotRecast.Detour.Extras.Jumplink
} }
} }
private bool sampleTrajectory(JumpLinkBuilderConfig acfg, Heightfield solid, Vector3f pa, Vector3f pb, Trajectory tra) private bool SampleTrajectory(JumpLinkBuilderConfig acfg, Heightfield solid, Vector3f pa, Vector3f pb, Trajectory tra)
{ {
float cs = Math.Min(acfg.cellSize, acfg.cellHeight); float cs = Math.Min(acfg.cellSize, acfg.cellHeight);
float d = vDist2D(pa, pb) + Math.Abs(pa.y - pb.y); float d = VDist2D(pa, pb) + Math.Abs(pa.y - pb.y);
int nsamples = Math.Max(2, (int)Math.Ceiling(d / cs)); int nsamples = Math.Max(2, (int)Math.Ceiling(d / cs));
for (int i = 0; i < nsamples; ++i) for (int i = 0; i < nsamples; ++i)
{ {
float u = (float)i / (float)(nsamples - 1); float u = (float)i / (float)(nsamples - 1);
Vector3f p = tra.apply(pa, pb, u); Vector3f p = tra.Apply(pa, pb, u);
if (checkHeightfieldCollision(solid, p.x, p.y + acfg.groundTolerance, p.y + acfg.agentHeight, p.z)) if (CheckHeightfieldCollision(solid, p.x, p.y + acfg.groundTolerance, p.y + acfg.agentHeight, p.z))
{ {
return false; return false;
} }
@ -50,7 +50,7 @@ namespace DotRecast.Detour.Extras.Jumplink
return true; return true;
} }
private bool checkHeightfieldCollision(Heightfield solid, float x, float ymin, float ymax, float z) private bool CheckHeightfieldCollision(Heightfield solid, float x, float ymin, float ymax, float z)
{ {
int w = solid.width; int w = solid.width;
int h = solid.height; int h = solid.height;
@ -75,7 +75,7 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
float symin = orig.y + s.smin * ch; float symin = orig.y + s.smin * ch;
float symax = orig.y + s.smax * ch; float symax = orig.y + s.smax * ch;
if (overlapRange(ymin, ymax, symin, symax)) if (OverlapRange(ymin, ymax, symin, symax))
{ {
return true; return true;
} }
@ -86,7 +86,7 @@ namespace DotRecast.Detour.Extras.Jumplink
return false; return false;
} }
private bool overlapRange(float amin, float amax, float bmin, float bmax) private bool OverlapRange(float amin, float amax, float bmin, float bmax)
{ {
return (amin > bmax || amax < bmin) ? false : true; return (amin > bmax || amax < bmin) ? false : true;
} }

View File

@ -22,14 +22,14 @@ namespace DotRecast.Detour.Extras
{ {
public class ObjExporter public class ObjExporter
{ {
public void export(NavMesh mesh) public void Export(NavMesh mesh)
{ {
string filename = Path.Combine(Directory.GetCurrentDirectory(), "Demo", "astar.obj"); string filename = Path.Combine(Directory.GetCurrentDirectory(), "Demo", "astar.obj");
using var fs = new FileStream(filename, FileMode.CreateNew); using var fs = new FileStream(filename, FileMode.CreateNew);
using var fw = new StreamWriter(fs); using var fw = new StreamWriter(fs);
for (int i = 0; i < mesh.getTileCount(); i++) for (int i = 0; i < mesh.GetTileCount(); i++)
{ {
MeshTile tile = mesh.getTile(i); MeshTile tile = mesh.GetTile(i);
if (tile != null) if (tile != null)
{ {
for (int v = 0; v < tile.data.header.vertCount; v++) for (int v = 0; v < tile.data.header.vertCount; v++)
@ -41,9 +41,9 @@ namespace DotRecast.Detour.Extras
} }
int vertexOffset = 1; int vertexOffset = 1;
for (int i = 0; i < mesh.getTileCount(); i++) for (int i = 0; i < mesh.GetTileCount(); i++)
{ {
MeshTile tile = mesh.getTile(i); MeshTile tile = mesh.GetTile(i);
if (tile != null) if (tile != null)
{ {
for (int p = 0; p < tile.data.header.polyCount; p++) for (int p = 0; p < tile.data.header.polyCount; p++)
@ -67,8 +67,8 @@ namespace DotRecast.Detour.Extras
* *
MeshSetReader reader = new MeshSetReader(); MeshSetReader reader = new MeshSetReader();
ObjExporter exporter = new ObjExporter(); ObjExporter exporter = new ObjExporter();
exporter.export(mesh); exporter.Export(mesh);
reader.read(new FileInputStream("/home/piotr/Downloads/graph/all_tiles_navmesh.bin"), 3); reader.Read(new FileInputStream("/home/piotr/Downloads/graph/all_tiles_navmesh.bin"), 3);
*/ */

View File

@ -23,7 +23,7 @@ namespace DotRecast.Detour.Extras
/** /**
* Find edge shared by 2 polygons within the same tile * Find edge shared by 2 polygons within the same tile
*/ */
public static int findEdge(Poly node, Poly neighbour, MeshData tile, MeshData neighbourTile) public static int FindEdge(Poly node, Poly neighbour, MeshData tile, MeshData neighbourTile)
{ {
// Compare indices first assuming there are no duplicate vertices // Compare indices first assuming there are no duplicate vertices
for (int i = 0; i < node.vertCount; i++) for (int i = 0; i < node.vertCount; i++)
@ -47,10 +47,10 @@ namespace DotRecast.Detour.Extras
for (int k = 0; k < neighbour.vertCount; k++) for (int k = 0; k < neighbour.vertCount; k++)
{ {
int l = (k + 1) % neighbour.vertCount; int l = (k + 1) % neighbour.vertCount;
if ((samePosition(tile.verts, node.verts[i], neighbourTile.verts, neighbour.verts[l]) if ((SamePosition(tile.verts, node.verts[i], neighbourTile.verts, neighbour.verts[l])
&& samePosition(tile.verts, node.verts[j], neighbourTile.verts, neighbour.verts[k])) && SamePosition(tile.verts, node.verts[j], neighbourTile.verts, neighbour.verts[k]))
|| (samePosition(tile.verts, node.verts[i], neighbourTile.verts, neighbour.verts[k]) || (SamePosition(tile.verts, node.verts[i], neighbourTile.verts, neighbour.verts[k])
&& samePosition(tile.verts, node.verts[j], neighbourTile.verts, neighbour.verts[l]))) && SamePosition(tile.verts, node.verts[j], neighbourTile.verts, neighbour.verts[l])))
{ {
return i; return i;
} }
@ -60,7 +60,7 @@ namespace DotRecast.Detour.Extras
return -1; return -1;
} }
private static bool samePosition(float[] verts, int v, float[] verts2, int v2) private static bool SamePosition(float[] verts, int v, float[] verts2, int v2)
{ {
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
@ -76,7 +76,7 @@ namespace DotRecast.Detour.Extras
/** /**
* Find edge closest to the given coordinate * Find edge closest to the given coordinate
*/ */
public static int findEdge(Poly node, MeshData tile, float value, int comp) public static int FindEdge(Poly node, MeshData tile, float value, int comp)
{ {
float error = float.MaxValue; float error = float.MaxValue;
int edge = 0; int edge = 0;

View File

@ -22,11 +22,11 @@ namespace DotRecast.Detour.Extras.Unity.Astar
{ {
private readonly BVTreeBuilder builder = new BVTreeBuilder(); private readonly BVTreeBuilder builder = new BVTreeBuilder();
public void build(GraphMeshData graphData) public void Build(GraphMeshData graphData)
{ {
foreach (MeshData d in graphData.tiles) foreach (MeshData d in graphData.tiles)
{ {
builder.build(d); builder.Build(d);
} }
} }
} }

View File

@ -24,24 +24,24 @@ namespace DotRecast.Detour.Extras.Unity.Astar
{ {
class GraphConnectionReader : ZipBinaryReader class GraphConnectionReader : ZipBinaryReader
{ {
public List<int[]> read(ZipArchive file, string filename, Meta meta, int[] indexToNode) public List<int[]> Read(ZipArchive file, string filename, Meta meta, int[] indexToNode)
{ {
List<int[]> connections = new List<int[]>(); List<int[]> connections = new List<int[]>();
ByteBuffer buffer = toByteBuffer(file, filename); ByteBuffer buffer = ToByteBuffer(file, filename);
while (buffer.remaining() > 0) while (buffer.Remaining() > 0)
{ {
int count = buffer.getInt(); int count = buffer.GetInt();
int[] nodeConnections = new int[count]; int[] nodeConnections = new int[count];
connections.Add(nodeConnections); connections.Add(nodeConnections);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
int nodeIndex = buffer.getInt(); int nodeIndex = buffer.GetInt();
nodeConnections[i] = indexToNode[nodeIndex]; nodeConnections[i] = indexToNode[nodeIndex];
// XXX: Is there anything we can do with the cost? // XXX: Is there anything we can do with the cost?
int cost = buffer.getInt(); int cost = buffer.GetInt();
if (meta.isVersionAtLeast(Meta.UPDATED_STRUCT_VERSION)) if (meta.IsVersionAtLeast(Meta.UPDATED_STRUCT_VERSION))
{ {
byte shapeEdge = buffer.get(); byte shapeEdge = buffer.Get();
} }
} }
} }

View File

@ -31,7 +31,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
this.tiles = tiles; this.tiles = tiles;
} }
public int countNodes() public int CountNodes()
{ {
int polyCount = 0; int polyCount = 0;
foreach (MeshData t in tiles) foreach (MeshData t in tiles)
@ -42,7 +42,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
return polyCount; return polyCount;
} }
public Poly getNode(int node) public Poly GetNode(int node)
{ {
int index = 0; int index = 0;
foreach (MeshData t in tiles) foreach (MeshData t in tiles)
@ -58,7 +58,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
return null; return null;
} }
public MeshData getTile(int node) public MeshData GetTile(int node)
{ {
int index = 0; int index = 0;
foreach (MeshData t in tiles) foreach (MeshData t in tiles)

View File

@ -27,59 +27,59 @@ namespace DotRecast.Detour.Extras.Unity.Astar
{ {
public const float INT_PRECISION_FACTOR = 1000f; public const float INT_PRECISION_FACTOR = 1000f;
public GraphMeshData read(ZipArchive file, string filename, GraphMeta meta, int maxVertPerPoly) public GraphMeshData Read(ZipArchive file, string filename, GraphMeta meta, int maxVertPerPoly)
{ {
ByteBuffer buffer = toByteBuffer(file, filename); ByteBuffer buffer = ToByteBuffer(file, filename);
int tileXCount = buffer.getInt(); int tileXCount = buffer.GetInt();
if (tileXCount < 0) if (tileXCount < 0)
{ {
return null; return null;
} }
int tileZCount = buffer.getInt(); int tileZCount = buffer.GetInt();
MeshData[] tiles = new MeshData[tileXCount * tileZCount]; MeshData[] tiles = new MeshData[tileXCount * tileZCount];
for (int z = 0; z < tileZCount; z++) for (int z = 0; z < tileZCount; z++)
{ {
for (int x = 0; x < tileXCount; x++) for (int x = 0; x < tileXCount; x++)
{ {
int tileIndex = x + z * tileXCount; int tileIndex = x + z * tileXCount;
int tx = buffer.getInt(); int tx = buffer.GetInt();
int tz = buffer.getInt(); int tz = buffer.GetInt();
if (tx != x || tz != z) if (tx != x || tz != z)
{ {
throw new ArgumentException("Inconsistent tile positions"); throw new ArgumentException("Inconsistent tile positions");
} }
tiles[tileIndex] = new MeshData(); tiles[tileIndex] = new MeshData();
int width = buffer.getInt(); int width = buffer.GetInt();
int depth = buffer.getInt(); int depth = buffer.GetInt();
int trisCount = buffer.getInt(); int trisCount = buffer.GetInt();
int[] tris = new int[trisCount]; int[] tris = new int[trisCount];
for (int i = 0; i < tris.Length; i++) for (int i = 0; i < tris.Length; i++)
{ {
tris[i] = buffer.getInt(); tris[i] = buffer.GetInt();
} }
int vertsCount = buffer.getInt(); int vertsCount = buffer.GetInt();
float[] verts = new float[3 * vertsCount]; float[] verts = new float[3 * vertsCount];
for (int i = 0; i < verts.Length; i++) for (int i = 0; i < verts.Length; i++)
{ {
verts[i] = buffer.getInt() / INT_PRECISION_FACTOR; verts[i] = buffer.GetInt() / INT_PRECISION_FACTOR;
} }
int[] vertsInGraphSpace = new int[3 * buffer.getInt()]; int[] vertsInGraphSpace = new int[3 * buffer.GetInt()];
for (int i = 0; i < vertsInGraphSpace.Length; i++) for (int i = 0; i < vertsInGraphSpace.Length; i++)
{ {
vertsInGraphSpace[i] = buffer.getInt(); vertsInGraphSpace[i] = buffer.GetInt();
} }
int nodeCount = buffer.getInt(); int nodeCount = buffer.GetInt();
Poly[] nodes = new Poly[nodeCount]; Poly[] nodes = new Poly[nodeCount];
PolyDetail[] detailNodes = new PolyDetail[nodeCount]; PolyDetail[] detailNodes = new PolyDetail[nodeCount];
float[] detailVerts = new float[0]; float[] detailVerts = new float[0];
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;
float ymax = float.NegativeInfinity; float ymax = float.NegativeInfinity;
for (int i = 0; i < nodes.Length; i++) for (int i = 0; i < nodes.Length; i++)
@ -87,11 +87,11 @@ namespace DotRecast.Detour.Extras.Unity.Astar
nodes[i] = new Poly(i, maxVertPerPoly); nodes[i] = new Poly(i, maxVertPerPoly);
nodes[i].vertCount = 3; nodes[i].vertCount = 3;
// XXX: What can we do with the penalty? // XXX: What can we do with the penalty?
int penalty = buffer.getInt(); int penalty = buffer.GetInt();
nodes[i].flags = buffer.getInt(); nodes[i].flags = buffer.GetInt();
nodes[i].verts[0] = buffer.getInt() & vertMask; nodes[i].verts[0] = buffer.GetInt() & vertMask;
nodes[i].verts[1] = buffer.getInt() & vertMask; nodes[i].verts[1] = buffer.GetInt() & vertMask;
nodes[i].verts[2] = buffer.getInt() & vertMask; nodes[i].verts[2] = buffer.GetInt() & vertMask;
ymin = Math.Min(ymin, verts[nodes[i].verts[0] * 3 + 1]); ymin = Math.Min(ymin, verts[nodes[i].verts[0] * 3 + 1]);
ymin = Math.Min(ymin, verts[nodes[i].verts[1] * 3 + 1]); ymin = Math.Min(ymin, verts[nodes[i].verts[1] * 3 + 1]);
ymin = Math.Min(ymin, verts[nodes[i].verts[2] * 3 + 1]); ymin = Math.Min(ymin, verts[nodes[i].verts[2] * 3 + 1]);
@ -148,7 +148,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
return new GraphMeshData(tileXCount, tileZCount, tiles); return new GraphMeshData(tileXCount, tileZCount, tiles);
} }
public static int highestOneBit(uint i) public static int HighestOneBit(uint i)
{ {
i |= (i >> 1); i |= (i >> 1);
i |= (i >> 2); i |= (i >> 2);
@ -159,9 +159,9 @@ namespace DotRecast.Detour.Extras.Unity.Astar
} }
// See NavmeshBase.cs: ASTAR_RECAST_LARGER_TILES // See NavmeshBase.cs: ASTAR_RECAST_LARGER_TILES
private int getVertMask(int vertsCount) private int GetVertMask(int vertsCount)
{ {
int vertMask = highestOneBit((uint)vertsCount); int vertMask = HighestOneBit((uint)vertsCount);
if (vertMask != vertsCount) if (vertMask != vertsCount)
{ {
vertMask *= 2; vertMask *= 2;

View File

@ -24,7 +24,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
{ {
public class GraphMetaReader public class GraphMetaReader
{ {
public GraphMeta read(ZipArchive file, string filename) public GraphMeta Read(ZipArchive file, string filename)
{ {
ZipArchiveEntry entry = file.GetEntry(filename); ZipArchiveEntry entry = file.GetEntry(filename);
using StreamReader reader = new StreamReader(entry.Open()); using StreamReader reader = new StreamReader(entry.Open());

View File

@ -24,32 +24,32 @@ namespace DotRecast.Detour.Extras.Unity.Astar
public class LinkBuilder public class LinkBuilder
{ {
// Process connections and transform them into recast neighbour flags // Process connections and transform them into recast neighbour flags
public void build(int nodeOffset, GraphMeshData graphData, List<int[]> connections) public void Build(int nodeOffset, GraphMeshData graphData, List<int[]> connections)
{ {
for (int n = 0; n < connections.Count; n++) for (int n = 0; n < connections.Count; n++)
{ {
int[] nodeConnections = connections[n]; int[] nodeConnections = connections[n];
MeshData tile = graphData.getTile(n); MeshData tile = graphData.GetTile(n);
Poly node = graphData.getNode(n); Poly node = graphData.GetNode(n);
foreach (int connection in nodeConnections) foreach (int connection in nodeConnections)
{ {
MeshData neighbourTile = graphData.getTile(connection - nodeOffset); MeshData neighbourTile = graphData.GetTile(connection - nodeOffset);
if (neighbourTile != tile) if (neighbourTile != tile)
{ {
buildExternalLink(tile, node, neighbourTile); BuildExternalLink(tile, node, neighbourTile);
} }
else else
{ {
Poly neighbour = graphData.getNode(connection - nodeOffset); Poly neighbour = graphData.GetNode(connection - nodeOffset);
buildInternalLink(tile, node, neighbourTile, neighbour); BuildInternalLink(tile, node, neighbourTile, neighbour);
} }
} }
} }
} }
private void buildInternalLink(MeshData tile, Poly node, MeshData neighbourTile, Poly neighbour) private void BuildInternalLink(MeshData tile, Poly node, MeshData neighbourTile, Poly neighbour)
{ {
int edge = PolyUtils.findEdge(node, neighbour, tile, neighbourTile); int edge = PolyUtils.FindEdge(node, neighbour, tile, neighbourTile);
if (edge >= 0) if (edge >= 0)
{ {
node.neis[edge] = neighbour.index + 1; node.neis[edge] = neighbour.index + 1;
@ -61,23 +61,23 @@ namespace DotRecast.Detour.Extras.Unity.Astar
} }
// In case of external link to other tiles we must find the direction // In case of external link to other tiles we must find the direction
private void buildExternalLink(MeshData tile, Poly node, MeshData neighbourTile) private void BuildExternalLink(MeshData tile, Poly node, MeshData neighbourTile)
{ {
if (neighbourTile.header.bmin.x > tile.header.bmin.x) if (neighbourTile.header.bmin.x > tile.header.bmin.x)
{ {
node.neis[PolyUtils.findEdge(node, tile, neighbourTile.header.bmin.x, 0)] = NavMesh.DT_EXT_LINK; node.neis[PolyUtils.FindEdge(node, tile, neighbourTile.header.bmin.x, 0)] = NavMesh.DT_EXT_LINK;
} }
else if (neighbourTile.header.bmin.x < tile.header.bmin.x) else if (neighbourTile.header.bmin.x < tile.header.bmin.x)
{ {
node.neis[PolyUtils.findEdge(node, tile, tile.header.bmin.x, 0)] = NavMesh.DT_EXT_LINK | 4; node.neis[PolyUtils.FindEdge(node, tile, tile.header.bmin.x, 0)] = NavMesh.DT_EXT_LINK | 4;
} }
else if (neighbourTile.header.bmin.z > tile.header.bmin.z) else if (neighbourTile.header.bmin.z > tile.header.bmin.z)
{ {
node.neis[PolyUtils.findEdge(node, tile, neighbourTile.header.bmin.z, 2)] = NavMesh.DT_EXT_LINK | 2; node.neis[PolyUtils.FindEdge(node, tile, neighbourTile.header.bmin.z, 2)] = NavMesh.DT_EXT_LINK | 2;
} }
else else
{ {
node.neis[PolyUtils.findEdge(node, tile, tile.header.bmin.z, 2)] = NavMesh.DT_EXT_LINK | 6; node.neis[PolyUtils.FindEdge(node, tile, tile.header.bmin.z, 2)] = NavMesh.DT_EXT_LINK | 6;
} }
} }
} }

View File

@ -32,15 +32,15 @@ namespace DotRecast.Detour.Extras.Unity.Astar
public string[] guids { get; set; } public string[] guids { get; set; }
public string[] typeNames { get; set; } public string[] typeNames { get; set; }
public bool isSupportedVersion() public bool IsSupportedVersion()
{ {
return isVersionAtLeast(MIN_SUPPORTED_VERSION); return IsVersionAtLeast(MIN_SUPPORTED_VERSION);
} }
public bool isVersionAtLeast(string minVersion) public bool IsVersionAtLeast(string minVersion)
{ {
int[] actual = parseVersion(version); int[] actual = ParseVersion(version);
int[] minSupported = parseVersion(minVersion); int[] minSupported = ParseVersion(minVersion);
for (int i = 0; i < Math.Min(actual.Length, minSupported.Length); i++) for (int i = 0; i < Math.Min(actual.Length, minSupported.Length); i++)
{ {
if (actual[i] > minSupported[i]) if (actual[i] > minSupported[i])
@ -56,7 +56,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
return true; return true;
} }
private int[] parseVersion(string version) private int[] ParseVersion(string version)
{ {
Match m = VERSION_PATTERN.Match(version); Match m = VERSION_PATTERN.Match(version);
if (m.Success) if (m.Success)
@ -73,7 +73,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
throw new ArgumentException("Invalid version format: " + version); throw new ArgumentException("Invalid version format: " + version);
} }
public bool isSupportedType() public bool IsSupportedType()
{ {
foreach (string t in typeNames) foreach (string t in typeNames)
{ {

View File

@ -27,7 +27,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
{ {
public class MetaReader public class MetaReader
{ {
public Meta read(ZipArchive file, string filename) public Meta Read(ZipArchive file, string filename)
{ {
ZipArchiveEntry entry = file.GetEntry(filename); ZipArchiveEntry entry = file.GetEntry(filename);
using StreamReader reader = new StreamReader(entry.Open()); using StreamReader reader = new StreamReader(entry.Open());
@ -42,12 +42,12 @@ namespace DotRecast.Detour.Extras.Unity.Astar
json = regex.Replace(json, replacement); json = regex.Replace(json, replacement);
var meta = JsonSerializer.Deserialize<Meta>(json); var meta = JsonSerializer.Deserialize<Meta>(json);
if (!meta.isSupportedType()) if (!meta.IsSupportedType())
{ {
throw new ArgumentException("Unsupported graph type " + string.Join(", ", meta.typeNames)); throw new ArgumentException("Unsupported graph type " + string.Join(", ", meta.typeNames));
} }
if (!meta.isSupportedVersion()) if (!meta.IsSupportedVersion())
{ {
throw new ArgumentException("Unsupported version " + meta.version); throw new ArgumentException("Unsupported version " + meta.version);
} }

View File

@ -23,15 +23,15 @@ namespace DotRecast.Detour.Extras.Unity.Astar
{ {
class NodeIndexReader : ZipBinaryReader class NodeIndexReader : ZipBinaryReader
{ {
public int[] read(ZipArchive file, string filename) public int[] Read(ZipArchive file, string filename)
{ {
ByteBuffer buffer = toByteBuffer(file, filename); ByteBuffer buffer = ToByteBuffer(file, filename);
int maxNodeIndex = buffer.getInt(); int maxNodeIndex = buffer.GetInt();
int[] int2Node = new int[maxNodeIndex + 1]; int[] int2Node = new int[maxNodeIndex + 1];
int node = 0; int node = 0;
while (buffer.remaining() > 0) while (buffer.Remaining() > 0)
{ {
int index = buffer.getInt(); int index = buffer.GetInt();
int2Node[index] = node++; int2Node[index] = node++;
} }

View File

@ -23,27 +23,27 @@ namespace DotRecast.Detour.Extras.Unity.Astar
{ {
public class NodeLink2Reader : ZipBinaryReader public class NodeLink2Reader : ZipBinaryReader
{ {
public NodeLink2[] read(ZipArchive file, string filename, int[] indexToNode) public NodeLink2[] Read(ZipArchive file, string filename, int[] indexToNode)
{ {
ByteBuffer buffer = toByteBuffer(file, filename); ByteBuffer buffer = ToByteBuffer(file, filename);
int linkCount = buffer.getInt(); int linkCount = buffer.GetInt();
NodeLink2[] links = new NodeLink2[linkCount]; NodeLink2[] links = new NodeLink2[linkCount];
for (int i = 0; i < linkCount; i++) for (int i = 0; i < linkCount; i++)
{ {
long linkID = buffer.getLong(); long linkID = buffer.GetLong();
int startNode = indexToNode[buffer.getInt()]; int startNode = indexToNode[buffer.GetInt()];
int endNode = indexToNode[buffer.getInt()]; int endNode = indexToNode[buffer.GetInt()];
int connectedNode1 = buffer.getInt(); int connectedNode1 = buffer.GetInt();
int connectedNode2 = buffer.getInt(); int connectedNode2 = buffer.GetInt();
Vector3f clamped1 = new Vector3f(); Vector3f clamped1 = new Vector3f();
clamped1.x = buffer.getFloat(); clamped1.x = buffer.GetFloat();
clamped1.y = buffer.getFloat(); clamped1.y = buffer.GetFloat();
clamped1.z = buffer.getFloat(); clamped1.z = buffer.GetFloat();
Vector3f clamped2 = new Vector3f(); Vector3f clamped2 = new Vector3f();
clamped2.x = buffer.getFloat(); clamped2.x = buffer.GetFloat();
clamped2.y = buffer.getFloat(); clamped2.y = buffer.GetFloat();
clamped2.z = buffer.getFloat(); clamped2.z = buffer.GetFloat();
bool postScanCalled = buffer.get() != 0; bool postScanCalled = buffer.Get() != 0;
links[i] = new NodeLink2(linkID, startNode, endNode, clamped1, clamped2); links[i] = new NodeLink2(linkID, startNode, endNode, clamped1, clamped2);
} }

View File

@ -22,16 +22,16 @@ namespace DotRecast.Detour.Extras.Unity.Astar
{ {
public class OffMeshLinkCreator public class OffMeshLinkCreator
{ {
public void build(GraphMeshData graphData, NodeLink2[] links, int nodeOffset) public void Build(GraphMeshData graphData, NodeLink2[] links, int nodeOffset)
{ {
if (links.Length > 0) if (links.Length > 0)
{ {
foreach (NodeLink2 l in links) foreach (NodeLink2 l in links)
{ {
MeshData startTile = graphData.getTile(l.startNode - nodeOffset); MeshData startTile = graphData.GetTile(l.startNode - nodeOffset);
Poly startNode = graphData.getNode(l.startNode - nodeOffset); Poly startNode = graphData.GetNode(l.startNode - nodeOffset);
MeshData endTile = graphData.getTile(l.endNode - nodeOffset); MeshData endTile = graphData.GetTile(l.endNode - nodeOffset);
Poly endNode = graphData.getNode(l.endNode - nodeOffset); Poly endNode = graphData.GetNode(l.endNode - nodeOffset);
if (startNode != null && endNode != null) if (startNode != null && endNode != null)
{ {
// FIXME: Optimise // FIXME: Optimise
@ -40,7 +40,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
startTile.polys[poly] = new Poly(poly, 2); startTile.polys[poly] = new Poly(poly, 2);
startTile.polys[poly].verts[0] = startTile.header.vertCount; startTile.polys[poly].verts[0] = startTile.header.vertCount;
startTile.polys[poly].verts[1] = startTile.header.vertCount + 1; startTile.polys[poly].verts[1] = startTile.header.vertCount + 1;
startTile.polys[poly].setType(Poly.DT_POLYTYPE_OFFMESH_CONNECTION); startTile.polys[poly].SetType(Poly.DT_POLYTYPE_OFFMESH_CONNECTION);
startTile.verts = ArrayUtils.CopyOf(startTile.verts, startTile.verts.Length + 6); startTile.verts = ArrayUtils.CopyOf(startTile.verts, startTile.verts.Length + 6);
startTile.header.polyCount++; startTile.header.polyCount++;
startTile.header.vertCount += 2; startTile.header.vertCount += 2;
@ -54,7 +54,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
connection.rad = 0.1f; connection.rad = 0.1f;
connection.side = startTile == endTile connection.side = startTile == endTile
? 0xFF ? 0xFF
: NavMeshBuilder.classifyOffMeshPoint(new VectorPtr(connection.pos, 3), : NavMeshBuilder.ClassifyOffMeshPoint(new VectorPtr(connection.pos, 3),
startTile.header.bmin, startTile.header.bmax); startTile.header.bmin, startTile.header.bmax);
connection.userId = (int)l.linkID; connection.userId = (int)l.linkID;
if (startTile.offMeshCons == null) if (startTile.offMeshCons == null)

View File

@ -33,9 +33,9 @@ namespace DotRecast.Detour.Extras.Unity.Astar
private readonly LinkBuilder linkCreator = new LinkBuilder(); private readonly LinkBuilder linkCreator = new LinkBuilder();
private readonly OffMeshLinkCreator offMeshLinkCreator = new OffMeshLinkCreator(); private readonly OffMeshLinkCreator offMeshLinkCreator = new OffMeshLinkCreator();
public NavMesh[] load(FileStream zipFile) public NavMesh[] Load(FileStream zipFile)
{ {
GraphData graphData = reader.read(zipFile); GraphData graphData = reader.Read(zipFile);
Meta meta = graphData.meta; Meta meta = graphData.meta;
NodeLink2[] nodeLinks2 = graphData.nodeLinks2; NodeLink2[] nodeLinks2 = graphData.nodeLinks2;
NavMesh[] meshes = new NavMesh[meta.graphs]; NavMesh[] meshes = new NavMesh[meta.graphs];
@ -45,7 +45,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
GraphMeta graphMeta = graphData.graphMeta[graphIndex]; GraphMeta graphMeta = graphData.graphMeta[graphIndex];
GraphMeshData graphMeshData = graphData.graphMeshData[graphIndex]; GraphMeshData graphMeshData = graphData.graphMeshData[graphIndex];
List<int[]> connections = graphData.graphConnections[graphIndex]; List<int[]> connections = graphData.graphConnections[graphIndex];
int nodeCount = graphMeshData.countNodes(); int nodeCount = graphMeshData.CountNodes();
if (connections.Count != nodeCount) if (connections.Count != nodeCount)
{ {
throw new ArgumentException("Inconsistent number of nodes in data file: " + nodeCount throw new ArgumentException("Inconsistent number of nodes in data file: " + nodeCount
@ -53,11 +53,11 @@ namespace DotRecast.Detour.Extras.Unity.Astar
} }
// Build BV tree // Build BV tree
bvTreeCreator.build(graphMeshData); bvTreeCreator.Build(graphMeshData);
// Create links between nodes (both internal and portals between tiles) // Create links between nodes (both internal and portals between tiles)
linkCreator.build(nodeOffset, graphMeshData, connections); linkCreator.Build(nodeOffset, graphMeshData, connections);
// Finally, process all the off-mesh links that can be actually converted to detour data // Finally, process all the off-mesh links that can be actually converted to detour data
offMeshLinkCreator.build(graphMeshData, nodeLinks2, nodeOffset); offMeshLinkCreator.Build(graphMeshData, nodeLinks2, nodeOffset);
NavMeshParams option = new NavMeshParams(); NavMeshParams option = new NavMeshParams();
option.maxTiles = graphMeshData.tiles.Length; option.maxTiles = graphMeshData.tiles.Length;
option.maxPolys = 32768; option.maxPolys = 32768;
@ -69,11 +69,11 @@ namespace DotRecast.Detour.Extras.Unity.Astar
NavMesh mesh = new NavMesh(option, 3); NavMesh mesh = new NavMesh(option, 3);
foreach (MeshData t in graphMeshData.tiles) foreach (MeshData t in graphMeshData.tiles)
{ {
mesh.addTile(t, 0, 0); mesh.AddTile(t, 0, 0);
} }
meshes[graphIndex] = mesh; meshes[graphIndex] = mesh;
nodeOffset += graphMeshData.countNodes(); nodeOffset += graphMeshData.CountNodes();
} }
return meshes; return meshes;

View File

@ -38,27 +38,27 @@ namespace DotRecast.Detour.Extras.Unity.Astar
private readonly GraphConnectionReader graphConnectionReader = new GraphConnectionReader(); private readonly GraphConnectionReader graphConnectionReader = new GraphConnectionReader();
private readonly NodeLink2Reader nodeLink2Reader = new NodeLink2Reader(); private readonly NodeLink2Reader nodeLink2Reader = new NodeLink2Reader();
public GraphData read(FileStream zipFile) public GraphData Read(FileStream zipFile)
{ {
using ZipArchive file = new ZipArchive(zipFile); using ZipArchive file = new ZipArchive(zipFile);
// Read meta file and check version and graph type // Read meta file and check version and graph type
Meta meta = metaReader.read(file, META_FILE_NAME); Meta meta = metaReader.Read(file, META_FILE_NAME);
// Read index to node mapping // Read index to node mapping
int[] indexToNode = nodeIndexReader.read(file, NODE_INDEX_FILE_NAME); int[] indexToNode = nodeIndexReader.Read(file, NODE_INDEX_FILE_NAME);
// Read NodeLink2 data (off-mesh links) // Read NodeLink2 data (off-mesh links)
NodeLink2[] nodeLinks2 = nodeLink2Reader.read(file, NODE_LINK_2_FILE_NAME, indexToNode); NodeLink2[] nodeLinks2 = nodeLink2Reader.Read(file, NODE_LINK_2_FILE_NAME, indexToNode);
// Read graph by graph // Read graph by graph
List<GraphMeta> metaList = new List<GraphMeta>(); List<GraphMeta> metaList = new List<GraphMeta>();
List<GraphMeshData> meshDataList = new List<GraphMeshData>(); List<GraphMeshData> meshDataList = new List<GraphMeshData>();
List<List<int[]>> connectionsList = new List<List<int[]>>(); List<List<int[]>> connectionsList = new List<List<int[]>>();
for (int graphIndex = 0; graphIndex < meta.graphs; graphIndex++) for (int graphIndex = 0; graphIndex < meta.graphs; graphIndex++)
{ {
GraphMeta graphMeta = graphMetaReader.read(file, string.Format(GRAPH_META_FILE_NAME_PATTERN, graphIndex)); GraphMeta graphMeta = graphMetaReader.Read(file, string.Format(GRAPH_META_FILE_NAME_PATTERN, graphIndex));
// First graph mesh data - vertices and polygons // First graph mesh data - vertices and polygons
GraphMeshData graphData = graphDataReader.read(file, GraphMeshData graphData = graphDataReader.Read(file,
string.Format(GRAPH_DATA_FILE_NAME_PATTERN, graphIndex), graphMeta, MAX_VERTS_PER_POLY); string.Format(GRAPH_DATA_FILE_NAME_PATTERN, graphIndex), graphMeta, MAX_VERTS_PER_POLY);
// Then graph connection data - links between nodes located in both the same tile and other tiles // Then graph connection data - links between nodes located in both the same tile and other tiles
List<int[]> connections = graphConnectionReader.read(file, List<int[]> connections = graphConnectionReader.Read(file,
string.Format(GRAPH_CONNECTION_FILE_NAME_PATTERN, graphIndex), meta, indexToNode); string.Format(GRAPH_CONNECTION_FILE_NAME_PATTERN, graphIndex), meta, indexToNode);
metaList.Add(graphMeta); metaList.Add(graphMeta);
meshDataList.Add(graphData); meshDataList.Add(graphData);

View File

@ -25,13 +25,13 @@ namespace DotRecast.Detour.Extras.Unity.Astar
{ {
public abstract class ZipBinaryReader public abstract class ZipBinaryReader
{ {
protected ByteBuffer toByteBuffer(ZipArchive file, string filename) protected ByteBuffer ToByteBuffer(ZipArchive file, string filename)
{ {
ZipArchiveEntry graphReferences = file.GetEntry(filename); ZipArchiveEntry graphReferences = file.GetEntry(filename);
using var entryStream = graphReferences.Open(); using var entryStream = graphReferences.Open();
using var bis = new BinaryReader(entryStream); using var bis = new BinaryReader(entryStream);
ByteBuffer buffer = IOUtils.toByteBuffer(bis); ByteBuffer buffer = IOUtils.ToByteBuffer(bis);
buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.Order(ByteOrder.LITTLE_ENDIAN);
return buffer; return buffer;
} }
} }

View File

@ -29,31 +29,31 @@ namespace DotRecast.Detour.TileCache
{ {
public abstract class AbstractTileLayersBuilder public abstract class AbstractTileLayersBuilder
{ {
protected List<byte[]> build(ByteOrder order, bool cCompatibility, int threads, int tw, int th) protected List<byte[]> Build(ByteOrder order, bool cCompatibility, int threads, int tw, int th)
{ {
if (threads == 1) if (threads == 1)
{ {
return buildSingleThread(order, cCompatibility, tw, th); return BuildSingleThread(order, cCompatibility, tw, th);
} }
return buildMultiThread(order, cCompatibility, tw, th, threads); return BuildMultiThread(order, cCompatibility, tw, th, threads);
} }
private List<byte[]> buildSingleThread(ByteOrder order, bool cCompatibility, int tw, int th) private List<byte[]> BuildSingleThread(ByteOrder order, bool cCompatibility, int tw, int th)
{ {
List<byte[]> layers = new List<byte[]>(); List<byte[]> layers = new List<byte[]>();
for (int y = 0; y < th; ++y) for (int y = 0; y < th; ++y)
{ {
for (int x = 0; x < tw; ++x) for (int x = 0; x < tw; ++x)
{ {
layers.AddRange(build(x, y, order, cCompatibility)); layers.AddRange(Build(x, y, order, cCompatibility));
} }
} }
return layers; return layers;
} }
private List<byte[]> buildMultiThread(ByteOrder order, bool cCompatibility, int tw, int th, int threads) private List<byte[]> BuildMultiThread(ByteOrder order, bool cCompatibility, int tw, int th, int threads)
{ {
var tasks = new ConcurrentQueue<Task<Tuple<int, int, List<byte[]>>>>(); var tasks = new ConcurrentQueue<Task<Tuple<int, int, List<byte[]>>>>();
for (int y = 0; y < th; ++y) for (int y = 0; y < th; ++y)
@ -64,7 +64,7 @@ namespace DotRecast.Detour.TileCache
int ty = y; int ty = y;
var task = Task.Run(() => var task = Task.Run(() =>
{ {
var partial = build(tx, ty, order, cCompatibility); var partial = Build(tx, ty, order, cCompatibility);
return Tuple.Create(tx, ty, partial); return Tuple.Create(tx, ty, partial);
}); });
tasks.Enqueue(task); tasks.Enqueue(task);
@ -88,6 +88,6 @@ namespace DotRecast.Detour.TileCache
return layers; return layers;
} }
protected abstract List<byte[]> build(int tx, int ty, ByteOrder order, bool cCompatibility); protected abstract List<byte[]> Build(int tx, int ty, ByteOrder order, bool cCompatibility);
} }
} }

View File

@ -54,13 +54,13 @@ namespace DotRecast.Detour.TileCache.Io.Compress
static readonly int MAX_CHUNK_LENGTH = 0xFFFF; static readonly int MAX_CHUNK_LENGTH = 0xFFFF;
/** /**
* Do not call {@link #compress(byte[], int, int, byte[], int, int)} for input buffers * Do not call {@link #Compress(byte[], int, int, byte[], int, int)} for input buffers
* which length less than this value. * which length less than this value.
*/ */
static readonly int MIN_LENGTH_TO_COMPRESSION = 32; static readonly int MIN_LENGTH_TO_COMPRESSION = 32;
/** /**
* In this case {@link #compress(byte[], int, int, byte[], int, int)} will choose level * In this case {@link #Compress(byte[], int, int, byte[], int, int)} will choose level
* automatically depending on the length of the input buffer. If length less than * automatically depending on the length of the input buffer. If length less than
* {@link #MIN_RECOMENDED_LENGTH_FOR_LEVEL_2} {@link #LEVEL_1} will be choosen, * {@link #MIN_RECOMENDED_LENGTH_FOR_LEVEL_2} {@link #LEVEL_1} will be choosen,
* otherwise {@link #LEVEL_2}. * otherwise {@link #LEVEL_2}.
@ -82,7 +82,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
* @param inputLength length of input buffer * @param inputLength length of input buffer
* @return Maximum output buffer length * @return Maximum output buffer length
*/ */
public static int calculateOutputBufferLength(int inputLength) public static int CalculateOutputBufferLength(int inputLength)
{ {
int tempOutputLength = (int)(inputLength * 1.06); int tempOutputLength = (int)(inputLength * 1.06);
return Math.Max(tempOutputLength, 66); return Math.Max(tempOutputLength, 66);
@ -94,7 +94,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
* *
* If the input is not compressible, the return value might be larger than length (input buffer size). * If the input is not compressible, the return value might be larger than length (input buffer size).
*/ */
public static int compress(byte[] input, int inOffset, int inLength, public static int Compress(byte[] input, int inOffset, int inLength,
byte[] output, int outOffset, int proposedLevel) byte[] output, int outOffset, int proposedLevel)
{ {
int level; int level;
@ -178,9 +178,9 @@ namespace DotRecast.Detour.TileCache.Io.Compress
/* check for a run */ /* check for a run */
if (level == LEVEL_2) if (level == LEVEL_2)
{ {
//if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) //If(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1))
if (input[inOffset + ip] == input[inOffset + ip - 1] && if (input[inOffset + ip] == input[inOffset + ip - 1] &&
readU16(input, inOffset + ip - 1) == readU16(input, inOffset + ip + 1)) ReadU16(input, inOffset + ip - 1) == ReadU16(input, inOffset + ip + 1))
{ {
distance = 1; distance = 1;
ip += 3; ip += 3;
@ -197,7 +197,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
{ {
/* find potential match */ /* find potential match */
// HASH_FUNCTION(hval,ip); // HASH_FUNCTION(hval,ip);
hval = hashFunction(input, inOffset + ip); hval = HashFunction(input, inOffset + ip);
// hslot = htab + hval; // hslot = htab + hval;
hslot = hval; hslot = hval;
// refs = htab[hval]; // refs = htab[hval];
@ -258,7 +258,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
len += 2; len += 2;
} }
} }
} // end if(!matchLabel) } // end If(!matchLabel)
/* /*
* match: * match:
@ -440,11 +440,11 @@ namespace DotRecast.Detour.TileCache.Io.Compress
/* update the hash at match boundary */ /* update the hash at match boundary */
//HASH_FUNCTION(hval,ip); //HASH_FUNCTION(hval,ip);
hval = hashFunction(input, inOffset + ip); hval = HashFunction(input, inOffset + ip);
htab[hval] = ip++; htab[hval] = ip++;
//HASH_FUNCTION(hval,ip); //HASH_FUNCTION(hval,ip);
hval = hashFunction(input, inOffset + ip); hval = HashFunction(input, inOffset + ip);
htab[hval] = ip++; htab[hval] = ip++;
/* assuming literal copy */ /* assuming literal copy */
@ -459,7 +459,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
output[outOffset + op++] = input[inOffset + anchor++]; output[outOffset + op++] = input[inOffset + anchor++];
ip = anchor; ip = anchor;
copy++; copy++;
if(copy == MAX_COPY){ If(copy == MAX_COPY){
copy = 0; copy = 0;
output[outOffset + op++] = MAX_COPY-1; output[outOffset + op++] = MAX_COPY-1;
} }
@ -507,7 +507,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
* Decompression is memory safe and guaranteed not to write the output buffer * Decompression is memory safe and guaranteed not to write the output buffer
* more than what is specified in outLength. * more than what is specified in outLength.
*/ */
public static int decompress(byte[] input, int inOffset, int inLength, public static int Decompress(byte[] input, int inOffset, int inLength,
byte[] output, int outOffset, int outLength) byte[] output, int outOffset, int outLength)
{ {
//int level = ((*(const flzuint8*)input) >> 5) + 1; //int level = ((*(const flzuint8*)input) >> 5) + 1;
@ -569,8 +569,8 @@ namespace DotRecast.Detour.TileCache.Io.Compress
refs -= code; refs -= code;
/* match from 16-bit distance */ /* match from 16-bit distance */
// if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) // If(FASTLZ_UNEXPECT_CONDITIONAL(code==255))
// if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) // If(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8)))
if (code == 255 && ofs == 31 << 8) if (code == 255 && ofs == 31 << 8)
{ {
ofs = (input[inOffset + ip++] & 0xFF) << 8; ofs = (input[inOffset + ip++] & 0xFF) << 8;
@ -580,7 +580,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
} }
} }
// if the output index + length of block(?) + 3(?) is over the output limit? // if the output index + length of Block(?) + 3(?) is over the output limit?
if (op + len + 3 > outLength) if (op + len + 3 > outLength)
{ {
return 0; return 0;
@ -665,22 +665,22 @@ namespace DotRecast.Detour.TileCache.Io.Compress
} }
} }
// while(FASTLZ_EXPECT_CONDITIONAL(loop)); // While(FASTLZ_EXPECT_CONDITIONAL(loop));
} while (loop != 0); } while (loop != 0);
// return op - (flzuint8*)output; // return op - (flzuint8*)output;
return op; return op;
} }
private static int hashFunction(byte[] p, int offset) private static int HashFunction(byte[] p, int offset)
{ {
int v = readU16(p, offset); int v = ReadU16(p, offset);
v ^= readU16(p, offset + 1) ^ v >> 16 - HASH_LOG; v ^= ReadU16(p, offset + 1) ^ v >> 16 - HASH_LOG;
v &= HASH_MASK; v &= HASH_MASK;
return v; return v;
} }
private static int readU16(byte[] data, int offset) private static int ReadU16(byte[] data, int offset)
{ {
if (offset + 1 >= data.Length) if (offset + 1 >= data.Length)
{ {

View File

@ -24,17 +24,17 @@ namespace DotRecast.Detour.TileCache.Io.Compress
{ {
public class FastLzTileCacheCompressor : TileCacheCompressor public class FastLzTileCacheCompressor : TileCacheCompressor
{ {
public byte[] decompress(byte[] buf, int offset, int len, int outputlen) public byte[] Decompress(byte[] buf, int offset, int len, int outputlen)
{ {
byte[] output = new byte[outputlen]; byte[] output = new byte[outputlen];
FastLz.decompress(buf, offset, len, output, 0, outputlen); FastLz.Decompress(buf, offset, len, output, 0, outputlen);
return output; return output;
} }
public byte[] compress(byte[] buf) public byte[] Compress(byte[] buf)
{ {
byte[] output = new byte[FastLz.calculateOutputBufferLength(buf.Length)]; byte[] output = new byte[FastLz.CalculateOutputBufferLength(buf.Length)];
int len = FastLz.compress(buf, 0, buf.Length, output, 0, output.Length); int len = FastLz.Compress(buf, 0, buf.Length, output, 0, output.Length);
return ArrayUtils.CopyOf(output, len); return ArrayUtils.CopyOf(output, len);
} }
} }

View File

@ -24,12 +24,12 @@ namespace DotRecast.Detour.TileCache.Io.Compress
{ {
public class LZ4TileCacheCompressor : TileCacheCompressor public class LZ4TileCacheCompressor : TileCacheCompressor
{ {
public byte[] decompress(byte[] buf, int offset, int len, int outputlen) public byte[] Decompress(byte[] buf, int offset, int len, int outputlen)
{ {
return LZ4Pickler.Unpickle(buf, offset, len); return LZ4Pickler.Unpickle(buf, offset, len);
} }
public byte[] compress(byte[] buf) public byte[] Compress(byte[] buf)
{ {
return LZ4Pickler.Pickle(buf); return LZ4Pickler.Pickle(buf);
} }

View File

@ -22,7 +22,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
{ {
public static class TileCacheCompressorFactory public static class TileCacheCompressorFactory
{ {
public static TileCacheCompressor get(bool cCompatibility) public static TileCacheCompressor Get(bool cCompatibility)
{ {
if (cCompatibility) if (cCompatibility)
return new FastLzTileCacheCompressor(); return new FastLzTileCacheCompressor();

View File

@ -25,39 +25,39 @@ namespace DotRecast.Detour.TileCache.Io
{ {
public class TileCacheLayerHeaderReader public class TileCacheLayerHeaderReader
{ {
public TileCacheLayerHeader read(ByteBuffer data, bool cCompatibility) public TileCacheLayerHeader Read(ByteBuffer data, bool cCompatibility)
{ {
TileCacheLayerHeader header = new TileCacheLayerHeader(); TileCacheLayerHeader header = new TileCacheLayerHeader();
header.magic = data.getInt(); header.magic = data.GetInt();
header.version = data.getInt(); header.version = data.GetInt();
if (header.magic != TileCacheLayerHeader.DT_TILECACHE_MAGIC) if (header.magic != TileCacheLayerHeader.DT_TILECACHE_MAGIC)
throw new IOException("Invalid magic"); throw new IOException("Invalid magic");
if (header.version != TileCacheLayerHeader.DT_TILECACHE_VERSION) if (header.version != TileCacheLayerHeader.DT_TILECACHE_VERSION)
throw new IOException("Invalid version"); throw new IOException("Invalid version");
header.tx = data.getInt(); header.tx = data.GetInt();
header.ty = data.getInt(); header.ty = data.GetInt();
header.tlayer = data.getInt(); header.tlayer = data.GetInt();
header.bmin.x = data.getFloat(); header.bmin.x = data.GetFloat();
header.bmin.y = data.getFloat(); header.bmin.y = data.GetFloat();
header.bmin.z = data.getFloat(); header.bmin.z = data.GetFloat();
header.bmax.x = data.getFloat(); header.bmax.x = data.GetFloat();
header.bmax.y = data.getFloat(); header.bmax.y = data.GetFloat();
header.bmax.z = data.getFloat(); header.bmax.z = data.GetFloat();
header.hmin = data.getShort() & 0xFFFF; header.hmin = data.GetShort() & 0xFFFF;
header.hmax = data.getShort() & 0xFFFF; header.hmax = data.GetShort() & 0xFFFF;
header.width = data.get() & 0xFF; header.width = data.Get() & 0xFF;
header.height = data.get() & 0xFF; header.height = data.Get() & 0xFF;
header.minx = data.get() & 0xFF; header.minx = data.Get() & 0xFF;
header.maxx = data.get() & 0xFF; header.maxx = data.Get() & 0xFF;
header.miny = data.get() & 0xFF; header.miny = data.Get() & 0xFF;
header.maxy = data.get() & 0xFF; header.maxy = data.Get() & 0xFF;
if (cCompatibility) if (cCompatibility)
{ {
data.getShort(); // C struct padding data.GetShort(); // C struct padding
} }
return header; return header;

View File

@ -26,32 +26,32 @@ namespace DotRecast.Detour.TileCache.Io
{ {
public class TileCacheLayerHeaderWriter : DetourWriter public class TileCacheLayerHeaderWriter : DetourWriter
{ {
public void write(BinaryWriter stream, TileCacheLayerHeader header, ByteOrder order, bool cCompatibility) public void Write(BinaryWriter stream, TileCacheLayerHeader header, ByteOrder order, bool cCompatibility)
{ {
write(stream, header.magic, order); Write(stream, header.magic, order);
write(stream, header.version, order); Write(stream, header.version, order);
write(stream, header.tx, order); Write(stream, header.tx, order);
write(stream, header.ty, order); Write(stream, header.ty, order);
write(stream, header.tlayer, order); Write(stream, header.tlayer, order);
write(stream, header.bmin.x, order); Write(stream, header.bmin.x, order);
write(stream, header.bmin.y, order); Write(stream, header.bmin.y, order);
write(stream, header.bmin.z, order); Write(stream, header.bmin.z, order);
write(stream, header.bmax.x, order); Write(stream, header.bmax.x, order);
write(stream, header.bmax.y, order); Write(stream, header.bmax.y, order);
write(stream, header.bmax.z, order); Write(stream, header.bmax.z, order);
write(stream, (short)header.hmin, order); Write(stream, (short)header.hmin, order);
write(stream, (short)header.hmax, order); Write(stream, (short)header.hmax, order);
write(stream, (byte)header.width); Write(stream, (byte)header.width);
write(stream, (byte)header.height); Write(stream, (byte)header.height);
write(stream, (byte)header.minx); Write(stream, (byte)header.minx);
write(stream, (byte)header.maxx); Write(stream, (byte)header.maxx);
write(stream, (byte)header.miny); Write(stream, (byte)header.miny);
write(stream, (byte)header.maxy); Write(stream, (byte)header.maxy);
if (cCompatibility) if (cCompatibility)
{ {
write(stream, (short)0, order); // C struct padding Write(stream, (short)0, order); // C struct padding
} }
} }
} }

View File

@ -29,28 +29,28 @@ namespace DotRecast.Detour.TileCache.Io
{ {
private readonly NavMeshParamReader paramReader = new NavMeshParamReader(); private readonly NavMeshParamReader paramReader = new NavMeshParamReader();
public TileCache read(BinaryReader @is, int maxVertPerPoly, TileCacheMeshProcess meshProcessor) public TileCache Read(BinaryReader @is, int maxVertPerPoly, TileCacheMeshProcess meshProcessor)
{ {
ByteBuffer bb = IOUtils.toByteBuffer(@is); ByteBuffer bb = IOUtils.ToByteBuffer(@is);
return read(bb, maxVertPerPoly, meshProcessor); return Read(bb, maxVertPerPoly, meshProcessor);
} }
public TileCache read(ByteBuffer bb, int maxVertPerPoly, TileCacheMeshProcess meshProcessor) public TileCache Read(ByteBuffer bb, int maxVertPerPoly, TileCacheMeshProcess meshProcessor)
{ {
TileCacheSetHeader header = new TileCacheSetHeader(); TileCacheSetHeader header = new TileCacheSetHeader();
header.magic = bb.getInt(); header.magic = bb.GetInt();
if (header.magic != TileCacheSetHeader.TILECACHESET_MAGIC) if (header.magic != TileCacheSetHeader.TILECACHESET_MAGIC)
{ {
header.magic = IOUtils.swapEndianness(header.magic); header.magic = IOUtils.SwapEndianness(header.magic);
if (header.magic != TileCacheSetHeader.TILECACHESET_MAGIC) if (header.magic != TileCacheSetHeader.TILECACHESET_MAGIC)
{ {
throw new IOException("Invalid magic"); throw new IOException("Invalid magic");
} }
bb.order(bb.order() == ByteOrder.BIG_ENDIAN ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); bb.Order(bb.Order() == ByteOrder.BIG_ENDIAN ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
} }
header.version = bb.getInt(); header.version = bb.GetInt();
if (header.version != TileCacheSetHeader.TILECACHESET_VERSION) if (header.version != TileCacheSetHeader.TILECACHESET_VERSION)
{ {
if (header.version != TileCacheSetHeader.TILECACHESET_VERSION_RECAST4J) if (header.version != TileCacheSetHeader.TILECACHESET_VERSION_RECAST4J)
@ -60,52 +60,52 @@ namespace DotRecast.Detour.TileCache.Io
} }
bool cCompatibility = header.version == TileCacheSetHeader.TILECACHESET_VERSION; bool cCompatibility = header.version == TileCacheSetHeader.TILECACHESET_VERSION;
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);
NavMesh mesh = new NavMesh(header.meshParams, maxVertPerPoly); NavMesh mesh = new NavMesh(header.meshParams, maxVertPerPoly);
TileCacheCompressor compressor = TileCacheCompressorFactory.get(cCompatibility); TileCacheCompressor compressor = TileCacheCompressorFactory.Get(cCompatibility);
TileCache tc = new TileCache(header.cacheParams, new TileCacheStorageParams(bb.order(), cCompatibility), mesh, TileCache tc = new TileCache(header.cacheParams, new TileCacheStorageParams(bb.Order(), cCompatibility), mesh,
compressor, meshProcessor); compressor, meshProcessor);
// Read tiles. // Read tiles.
for (int i = 0; i < header.numTiles; ++i) for (int i = 0; i < header.numTiles; ++i)
{ {
long tileRef = bb.getInt(); long tileRef = bb.GetInt();
int dataSize = bb.getInt(); int dataSize = bb.GetInt();
if (tileRef == 0 || dataSize == 0) if (tileRef == 0 || dataSize == 0)
{ {
break; break;
} }
byte[] data = bb.ReadBytes(dataSize).ToArray(); byte[] data = bb.ReadBytes(dataSize).ToArray();
long tile = tc.addTile(data, 0); long tile = tc.AddTile(data, 0);
if (tile != 0) if (tile != 0)
{ {
tc.buildNavMeshTile(tile); tc.BuildNavMeshTile(tile);
} }
} }
return tc; return tc;
} }
private TileCacheParams readCacheParams(ByteBuffer bb, bool cCompatibility) private TileCacheParams ReadCacheParams(ByteBuffer bb, bool cCompatibility)
{ {
TileCacheParams option = new TileCacheParams(); TileCacheParams option = new TileCacheParams();
option.orig.x = bb.getFloat(); option.orig.x = bb.GetFloat();
option.orig.y = bb.getFloat(); option.orig.y = bb.GetFloat();
option.orig.z = bb.getFloat(); option.orig.z = bb.GetFloat();
option.cs = bb.getFloat(); option.cs = bb.GetFloat();
option.ch = bb.getFloat(); option.ch = bb.GetFloat();
option.width = bb.getInt(); option.width = bb.GetInt();
option.height = bb.getInt(); option.height = bb.GetInt();
option.walkableHeight = bb.getFloat(); option.walkableHeight = bb.GetFloat();
option.walkableRadius = bb.getFloat(); option.walkableRadius = bb.GetFloat();
option.walkableClimb = bb.getFloat(); option.walkableClimb = bb.GetFloat();
option.maxSimplificationError = bb.getFloat(); option.maxSimplificationError = bb.GetFloat();
option.maxTiles = bb.getInt(); option.maxTiles = bb.GetInt();
option.maxObstacles = bb.getInt(); option.maxObstacles = bb.GetInt();
return option; return option;
} }
} }

View File

@ -29,54 +29,54 @@ namespace DotRecast.Detour.TileCache.Io
private readonly NavMeshParamWriter paramWriter = new NavMeshParamWriter(); private readonly NavMeshParamWriter paramWriter = new NavMeshParamWriter();
private readonly TileCacheBuilder builder = new TileCacheBuilder(); private readonly TileCacheBuilder builder = new TileCacheBuilder();
public void write(BinaryWriter stream, TileCache cache, ByteOrder order, bool cCompatibility) public void Write(BinaryWriter stream, TileCache cache, ByteOrder order, bool cCompatibility)
{ {
write(stream, TileCacheSetHeader.TILECACHESET_MAGIC, order); Write(stream, TileCacheSetHeader.TILECACHESET_MAGIC, order);
write(stream, cCompatibility Write(stream, cCompatibility
? TileCacheSetHeader.TILECACHESET_VERSION ? TileCacheSetHeader.TILECACHESET_VERSION
: TileCacheSetHeader.TILECACHESET_VERSION_RECAST4J, order); : TileCacheSetHeader.TILECACHESET_VERSION_RECAST4J, order);
int numTiles = 0; int numTiles = 0;
for (int i = 0; i < cache.getTileCount(); ++i) for (int i = 0; i < cache.GetTileCount(); ++i)
{ {
CompressedTile tile = cache.getTile(i); CompressedTile tile = cache.GetTile(i);
if (tile == null || tile.data == null) if (tile == null || tile.data == null)
continue; continue;
numTiles++; numTiles++;
} }
write(stream, numTiles, order); Write(stream, numTiles, order);
paramWriter.write(stream, cache.getNavMesh().getParams(), order); paramWriter.Write(stream, cache.GetNavMesh().GetParams(), order);
writeCacheParams(stream, cache.getParams(), order); WriteCacheParams(stream, cache.GetParams(), order);
for (int i = 0; i < cache.getTileCount(); i++) for (int i = 0; i < cache.GetTileCount(); i++)
{ {
CompressedTile tile = cache.getTile(i); CompressedTile tile = cache.GetTile(i);
if (tile == null || tile.data == null) if (tile == null || tile.data == null)
continue; continue;
write(stream, (int)cache.getTileRef(tile), order); Write(stream, (int)cache.GetTileRef(tile), order);
byte[] data = tile.data; byte[] data = tile.data;
TileCacheLayer layer = cache.decompressTile(tile); TileCacheLayer layer = cache.DecompressTile(tile);
data = builder.compressTileCacheLayer(layer, order, cCompatibility); data = builder.CompressTileCacheLayer(layer, order, cCompatibility);
write(stream, data.Length, order); Write(stream, data.Length, order);
stream.Write(data); stream.Write(data);
} }
} }
private void writeCacheParams(BinaryWriter stream, TileCacheParams option, ByteOrder order) private void WriteCacheParams(BinaryWriter stream, TileCacheParams option, ByteOrder order)
{ {
write(stream, option.orig.x, order); Write(stream, option.orig.x, order);
write(stream, option.orig.y, order); Write(stream, option.orig.y, order);
write(stream, option.orig.z, order); Write(stream, option.orig.z, order);
write(stream, option.cs, order); Write(stream, option.cs, order);
write(stream, option.ch, order); Write(stream, option.ch, order);
write(stream, option.width, order); Write(stream, option.width, order);
write(stream, option.height, order); Write(stream, option.height, order);
write(stream, option.walkableHeight, order); Write(stream, option.walkableHeight, order);
write(stream, option.walkableRadius, order); Write(stream, option.walkableRadius, order);
write(stream, option.walkableClimb, order); Write(stream, option.walkableClimb, order);
write(stream, option.maxSimplificationError, order); Write(stream, option.maxSimplificationError, order);
write(stream, option.maxTiles, order); Write(stream, option.maxTiles, order);
write(stream, option.maxObstacles, order); Write(stream, option.maxObstacles, order);
} }
} }
} }

View File

@ -66,46 +66,46 @@ namespace DotRecast.Detour.TileCache
private readonly TileCacheBuilder builder = new TileCacheBuilder(); private readonly TileCacheBuilder builder = new TileCacheBuilder();
private readonly TileCacheLayerHeaderReader tileReader = new TileCacheLayerHeaderReader(); private readonly TileCacheLayerHeaderReader tileReader = new TileCacheLayerHeaderReader();
private bool contains(List<long> a, long v) private bool Contains(List<long> a, long v)
{ {
return a.Contains(v); return a.Contains(v);
} }
/// Encodes a tile id. /// Encodes a tile id.
private long encodeTileId(int salt, int it) private long EncodeTileId(int salt, int it)
{ {
return ((long)salt << m_tileBits) | it; return ((long)salt << m_tileBits) | it;
} }
/// Decodes a tile salt. /// Decodes a tile salt.
private int decodeTileIdSalt(long refs) private int DecodeTileIdSalt(long refs)
{ {
long saltMask = (1L << m_saltBits) - 1; long saltMask = (1L << m_saltBits) - 1;
return (int)((refs >> m_tileBits) & saltMask); return (int)((refs >> m_tileBits) & saltMask);
} }
/// Decodes a tile id. /// Decodes a tile id.
private int decodeTileIdTile(long refs) private int DecodeTileIdTile(long refs)
{ {
long tileMask = (1L << m_tileBits) - 1; long tileMask = (1L << m_tileBits) - 1;
return (int)(refs & tileMask); return (int)(refs & tileMask);
} }
/// Encodes an obstacle id. /// Encodes an obstacle id.
private long encodeObstacleId(int salt, int it) private long EncodeObstacleId(int salt, int it)
{ {
return ((long)salt << 16) | it; return ((long)salt << 16) | it;
} }
/// Decodes an obstacle salt. /// Decodes an obstacle salt.
private int decodeObstacleIdSalt(long refs) private int DecodeObstacleIdSalt(long refs)
{ {
long saltMask = ((long)1 << 16) - 1; long saltMask = ((long)1 << 16) - 1;
return (int)((refs >> 16) & saltMask); return (int)((refs >> 16) & saltMask);
} }
/// Decodes an obstacle id. /// Decodes an obstacle id.
private int decodeObstacleIdObstacle(long refs) private int DecodeObstacleIdObstacle(long refs)
{ {
long tileMask = ((long)1 << 16) - 1; long tileMask = ((long)1 << 16) - 1;
return (int)(refs & tileMask); return (int)(refs & tileMask);
@ -120,7 +120,7 @@ namespace DotRecast.Detour.TileCache
m_tcomp = tcomp; m_tcomp = tcomp;
m_tmproc = tmprocs; m_tmproc = tmprocs;
m_tileLutSize = nextPow2(m_params.maxTiles / 4); m_tileLutSize = NextPow2(m_params.maxTiles / 4);
if (m_tileLutSize == 0) if (m_tileLutSize == 0)
{ {
m_tileLutSize = 1; m_tileLutSize = 1;
@ -136,7 +136,7 @@ namespace DotRecast.Detour.TileCache
m_nextFreeTile = m_tiles[i]; m_nextFreeTile = m_tiles[i];
} }
m_tileBits = ilog2(nextPow2(m_params.maxTiles)); m_tileBits = Ilog2(NextPow2(m_params.maxTiles));
m_saltBits = Math.Min(31, 32 - m_tileBits); m_saltBits = Math.Min(31, 32 - m_tileBits);
if (m_saltBits < 10) if (m_saltBits < 10)
{ {
@ -144,15 +144,15 @@ namespace DotRecast.Detour.TileCache
} }
} }
public CompressedTile getTileByRef(long refs) public CompressedTile GetTileByRef(long refs)
{ {
if (refs == 0) if (refs == 0)
{ {
return null; return null;
} }
int tileIndex = decodeTileIdTile(refs); int tileIndex = DecodeTileIdTile(refs);
int tileSalt = decodeTileIdSalt(refs); int tileSalt = DecodeTileIdSalt(refs);
if (tileIndex >= m_params.maxTiles) if (tileIndex >= m_params.maxTiles)
{ {
return null; return null;
@ -167,18 +167,18 @@ namespace DotRecast.Detour.TileCache
return tile; return tile;
} }
public List<long> getTilesAt(int tx, int ty) public List<long> GetTilesAt(int tx, int ty)
{ {
List<long> tiles = new List<long>(); List<long> tiles = new List<long>();
// Find tile based on hash. // Find tile based on hash.
int h = NavMesh.computeTileHash(tx, ty, m_tileLutMask); int h = NavMesh.ComputeTileHash(tx, ty, m_tileLutMask);
CompressedTile tile = m_posLookup[h]; CompressedTile tile = m_posLookup[h];
while (tile != null) while (tile != null)
{ {
if (tile.header != null && tile.header.tx == tx && tile.header.ty == ty) if (tile.header != null && tile.header.tx == tx && tile.header.ty == ty)
{ {
tiles.Add(getTileRef(tile)); tiles.Add(GetTileRef(tile));
} }
tile = tile.next; tile = tile.next;
@ -187,10 +187,10 @@ namespace DotRecast.Detour.TileCache
return tiles; return tiles;
} }
CompressedTile getTileAt(int tx, int ty, int tlayer) CompressedTile GetTileAt(int tx, int ty, int tlayer)
{ {
// Find tile based on hash. // Find tile based on hash.
int h = NavMesh.computeTileHash(tx, ty, m_tileLutMask); int h = NavMesh.ComputeTileHash(tx, ty, m_tileLutMask);
CompressedTile tile = m_posLookup[h]; CompressedTile tile = m_posLookup[h];
while (tile != null) while (tile != null)
{ {
@ -205,7 +205,7 @@ namespace DotRecast.Detour.TileCache
return null; return null;
} }
public long getTileRef(CompressedTile tile) public long GetTileRef(CompressedTile tile)
{ {
if (tile == null) if (tile == null)
{ {
@ -213,10 +213,10 @@ namespace DotRecast.Detour.TileCache
} }
int it = tile.index; int it = tile.index;
return encodeTileId(tile.salt, it); return EncodeTileId(tile.salt, it);
} }
public long getObstacleRef(TileCacheObstacle ob) public long GetObstacleRef(TileCacheObstacle ob)
{ {
if (ob == null) if (ob == null)
{ {
@ -224,24 +224,24 @@ namespace DotRecast.Detour.TileCache
} }
int idx = ob.index; int idx = ob.index;
return encodeObstacleId(ob.salt, idx); return EncodeObstacleId(ob.salt, idx);
} }
public TileCacheObstacle getObstacleByRef(long refs) public TileCacheObstacle GetObstacleByRef(long refs)
{ {
if (refs == 0) if (refs == 0)
{ {
return null; return null;
} }
int idx = decodeObstacleIdObstacle(refs); int idx = DecodeObstacleIdObstacle(refs);
if (idx >= m_obstacles.Count) if (idx >= m_obstacles.Count)
{ {
return null; return null;
} }
TileCacheObstacle ob = m_obstacles[idx]; TileCacheObstacle ob = m_obstacles[idx];
int salt = decodeObstacleIdSalt(refs); int salt = DecodeObstacleIdSalt(refs);
if (ob.salt != salt) if (ob.salt != salt)
{ {
return null; return null;
@ -250,14 +250,14 @@ namespace DotRecast.Detour.TileCache
return ob; return ob;
} }
public long addTile(byte[] data, int flags) public long AddTile(byte[] data, int flags)
{ {
// Make sure the data is in right format. // Make sure the data is in right format.
ByteBuffer buf = new ByteBuffer(data); ByteBuffer buf = new ByteBuffer(data);
buf.order(m_storageParams.byteOrder); buf.Order(m_storageParams.byteOrder);
TileCacheLayerHeader header = tileReader.read(buf, m_storageParams.cCompatibility); TileCacheLayerHeader header = tileReader.Read(buf, m_storageParams.cCompatibility);
// Make sure the location is free. // Make sure the location is free.
if (getTileAt(header.tx, header.ty, header.tlayer) != null) if (GetTileAt(header.tx, header.ty, header.tlayer) != null)
{ {
return 0; return 0;
} }
@ -278,33 +278,33 @@ namespace DotRecast.Detour.TileCache
} }
// Insert tile into the position lut. // Insert tile into the position lut.
int h = NavMesh.computeTileHash(header.tx, header.ty, m_tileLutMask); int h = NavMesh.ComputeTileHash(header.tx, header.ty, m_tileLutMask);
tile.next = m_posLookup[h]; tile.next = m_posLookup[h];
m_posLookup[h] = tile; m_posLookup[h] = tile;
// Init tile. // Init tile.
tile.header = header; tile.header = header;
tile.data = data; tile.data = data;
tile.compressed = align4(buf.position()); tile.compressed = Align4(buf.Position());
tile.flags = flags; tile.flags = flags;
return getTileRef(tile); return GetTileRef(tile);
} }
private int align4(int i) private int Align4(int i)
{ {
return (i + 3) & (~3); return (i + 3) & (~3);
} }
public void removeTile(long refs) public void RemoveTile(long refs)
{ {
if (refs == 0) if (refs == 0)
{ {
throw new Exception("Invalid tile ref"); throw new Exception("Invalid tile ref");
} }
int tileIndex = decodeTileIdTile(refs); int tileIndex = DecodeTileIdTile(refs);
int tileSalt = decodeTileIdSalt(refs); int tileSalt = DecodeTileIdSalt(refs);
if (tileIndex >= m_params.maxTiles) if (tileIndex >= m_params.maxTiles)
{ {
throw new Exception("Invalid tile index"); throw new Exception("Invalid tile index");
@ -317,7 +317,7 @@ namespace DotRecast.Detour.TileCache
} }
// Remove tile from hash lookup. // Remove tile from hash lookup.
int h = NavMesh.computeTileHash(tile.header.tx, tile.header.ty, m_tileLutMask); int h = NavMesh.ComputeTileHash(tile.header.tx, tile.header.ty, m_tileLutMask);
CompressedTile prev = null; CompressedTile prev = null;
CompressedTile cur = m_posLookup[h]; CompressedTile cur = m_posLookup[h];
while (cur != null) while (cur != null)
@ -358,34 +358,34 @@ namespace DotRecast.Detour.TileCache
} }
// Cylinder obstacle // Cylinder obstacle
public long addObstacle(Vector3f pos, float radius, float height) public long AddObstacle(Vector3f pos, float radius, float height)
{ {
TileCacheObstacle ob = allocObstacle(); TileCacheObstacle ob = AllocObstacle();
ob.type = TileCacheObstacle.TileCacheObstacleType.CYLINDER; ob.type = TileCacheObstacle.TileCacheObstacleType.CYLINDER;
ob.pos = pos; ob.pos = pos;
ob.radius = radius; ob.radius = radius;
ob.height = height; ob.height = height;
return addObstacleRequest(ob).refs; return AddObstacleRequest(ob).refs;
} }
// Aabb obstacle // Aabb obstacle
public long addBoxObstacle(Vector3f bmin, Vector3f bmax) public long AddBoxObstacle(Vector3f bmin, Vector3f bmax)
{ {
TileCacheObstacle ob = allocObstacle(); TileCacheObstacle ob = AllocObstacle();
ob.type = TileCacheObstacle.TileCacheObstacleType.BOX; ob.type = TileCacheObstacle.TileCacheObstacleType.BOX;
ob.bmin = bmin; ob.bmin = bmin;
ob.bmax = bmax; ob.bmax = bmax;
return addObstacleRequest(ob).refs; return AddObstacleRequest(ob).refs;
} }
// Box obstacle: can be rotated in Y // Box obstacle: can be rotated in Y
public long addBoxObstacle(Vector3f center, Vector3f extents, float yRadians) public long AddBoxObstacle(Vector3f center, Vector3f extents, float yRadians)
{ {
TileCacheObstacle ob = allocObstacle(); TileCacheObstacle ob = AllocObstacle();
ob.type = TileCacheObstacle.TileCacheObstacleType.ORIENTED_BOX; ob.type = TileCacheObstacle.TileCacheObstacleType.ORIENTED_BOX;
ob.center = center; ob.center = center;
ob.extents = extents; ob.extents = extents;
@ -393,19 +393,19 @@ namespace DotRecast.Detour.TileCache
float sinhalf = (float)Math.Sin(-0.5f * yRadians); float sinhalf = (float)Math.Sin(-0.5f * yRadians);
ob.rotAux[0] = coshalf * sinhalf; ob.rotAux[0] = coshalf * sinhalf;
ob.rotAux[1] = coshalf * coshalf - 0.5f; ob.rotAux[1] = coshalf * coshalf - 0.5f;
return addObstacleRequest(ob).refs; return AddObstacleRequest(ob).refs;
} }
private ObstacleRequest addObstacleRequest(TileCacheObstacle ob) private ObstacleRequest AddObstacleRequest(TileCacheObstacle ob)
{ {
ObstacleRequest req = new ObstacleRequest(); ObstacleRequest req = new ObstacleRequest();
req.action = ObstacleRequestAction.REQUEST_ADD; req.action = ObstacleRequestAction.REQUEST_ADD;
req.refs = getObstacleRef(ob); req.refs = GetObstacleRef(ob);
m_reqs.Add(req); m_reqs.Add(req);
return req; return req;
} }
public void removeObstacle(long refs) public void RemoveObstacle(long refs)
{ {
if (refs == 0) if (refs == 0)
{ {
@ -418,7 +418,7 @@ namespace DotRecast.Detour.TileCache
m_reqs.Add(req); m_reqs.Add(req);
} }
private TileCacheObstacle allocObstacle() private TileCacheObstacle AllocObstacle()
{ {
TileCacheObstacle o = m_nextFreeObstacle; TileCacheObstacle o = m_nextFreeObstacle;
if (o == null) if (o == null)
@ -438,7 +438,7 @@ namespace DotRecast.Detour.TileCache
return o; return o;
} }
List<long> queryTiles(Vector3f bmin, Vector3f bmax) List<long> QueryTiles(Vector3f bmin, Vector3f bmax)
{ {
List<long> results = new List<long>(); List<long> results = new List<long>();
float tw = m_params.width * m_params.cs; float tw = m_params.width * m_params.cs;
@ -451,14 +451,14 @@ namespace DotRecast.Detour.TileCache
{ {
for (int tx = tx0; tx <= tx1; ++tx) for (int tx = tx0; tx <= tx1; ++tx)
{ {
List<long> tiles = getTilesAt(tx, ty); List<long> tiles = GetTilesAt(tx, ty);
foreach (long i in tiles) foreach (long i in tiles)
{ {
CompressedTile tile = m_tiles[decodeTileIdTile(i)]; CompressedTile tile = m_tiles[DecodeTileIdTile(i)];
Vector3f tbmin = new Vector3f(); Vector3f tbmin = new Vector3f();
Vector3f tbmax = new Vector3f(); Vector3f tbmax = new Vector3f();
calcTightTileBounds(tile.header, ref tbmin, ref tbmax); CalcTightTileBounds(tile.header, ref tbmin, ref tbmax);
if (overlapBounds(bmin, bmax, tbmin, tbmax)) if (OverlapBounds(bmin, bmax, tbmin, tbmax))
{ {
results.Add(i); results.Add(i);
} }
@ -476,21 +476,21 @@ namespace DotRecast.Detour.TileCache
* cache is up to date another (immediate) call to update will have no effect; otherwise another call will * cache is up to date another (immediate) call to update will have no effect; otherwise another call will
* continue processing obstacle requests and tile rebuilds. * continue processing obstacle requests and tile rebuilds.
*/ */
public bool update() public bool Update()
{ {
if (0 == m_update.Count) if (0 == m_update.Count)
{ {
// Process requests. // Process requests.
foreach (ObstacleRequest req in m_reqs) foreach (ObstacleRequest req in m_reqs)
{ {
int idx = decodeObstacleIdObstacle(req.refs); int idx = DecodeObstacleIdObstacle(req.refs);
if (idx >= m_obstacles.Count) if (idx >= m_obstacles.Count)
{ {
continue; continue;
} }
TileCacheObstacle ob = m_obstacles[idx]; TileCacheObstacle ob = m_obstacles[idx];
int salt = decodeObstacleIdSalt(req.refs); int salt = DecodeObstacleIdSalt(req.refs);
if (ob.salt != salt) if (ob.salt != salt)
{ {
continue; continue;
@ -501,13 +501,13 @@ namespace DotRecast.Detour.TileCache
// Find touched tiles. // Find touched tiles.
Vector3f bmin = new Vector3f(); Vector3f bmin = new Vector3f();
Vector3f bmax = new Vector3f(); Vector3f bmax = new Vector3f();
getObstacleBounds(ob, ref bmin, ref bmax); GetObstacleBounds(ob, ref bmin, ref bmax);
ob.touched = queryTiles(bmin, bmax); ob.touched = QueryTiles(bmin, bmax);
// Add tiles to update list. // Add tiles to update list.
ob.pending.Clear(); ob.pending.Clear();
foreach (long j in ob.touched) foreach (long j in ob.touched)
{ {
if (!contains(m_update, j)) if (!Contains(m_update, j))
{ {
m_update.Add(j); m_update.Add(j);
} }
@ -523,7 +523,7 @@ namespace DotRecast.Detour.TileCache
ob.pending.Clear(); ob.pending.Clear();
foreach (long j in ob.touched) foreach (long j in ob.touched)
{ {
if (!contains(m_update, j)) if (!Contains(m_update, j))
{ {
m_update.Add(j); m_update.Add(j);
} }
@ -542,7 +542,7 @@ namespace DotRecast.Detour.TileCache
long refs = m_update[0]; long refs = m_update[0];
m_update.RemoveAt(0); m_update.RemoveAt(0);
// Build mesh // Build mesh
buildNavMeshTile(refs); BuildNavMeshTile(refs);
// Update obstacle states. // Update obstacle states.
for (int i = 0; i < m_obstacles.Count; ++i) for (int i = 0; i < m_obstacles.Count; ++i)
@ -583,16 +583,16 @@ namespace DotRecast.Detour.TileCache
return 0 == m_update.Count && 0 == m_reqs.Count; return 0 == m_update.Count && 0 == m_reqs.Count;
} }
public void buildNavMeshTile(long refs) public void BuildNavMeshTile(long refs)
{ {
int idx = decodeTileIdTile(refs); int idx = DecodeTileIdTile(refs);
if (idx > m_params.maxTiles) if (idx > m_params.maxTiles)
{ {
throw new Exception("Invalid tile index"); throw new Exception("Invalid tile index");
} }
CompressedTile tile = m_tiles[idx]; CompressedTile tile = m_tiles[idx];
int salt = decodeTileIdSalt(refs); int salt = DecodeTileIdSalt(refs);
if (tile.salt != salt) if (tile.salt != salt)
{ {
throw new Exception("Invalid tile salt"); throw new Exception("Invalid tile salt");
@ -601,7 +601,7 @@ namespace DotRecast.Detour.TileCache
int walkableClimbVx = (int)(m_params.walkableClimb / m_params.ch); int walkableClimbVx = (int)(m_params.walkableClimb / m_params.ch);
// Decompress tile layer data. // Decompress tile layer data.
TileCacheLayer layer = decompressTile(tile); TileCacheLayer layer = DecompressTile(tile);
// Rasterize obstacles. // Rasterize obstacles.
for (int i = 0; i < m_obstacles.Count; ++i) for (int i = 0; i < m_obstacles.Count; ++i)
@ -612,32 +612,32 @@ namespace DotRecast.Detour.TileCache
continue; continue;
} }
if (contains(ob.touched, refs)) if (Contains(ob.touched, refs))
{ {
if (ob.type == TileCacheObstacle.TileCacheObstacleType.CYLINDER) if (ob.type == TileCacheObstacle.TileCacheObstacleType.CYLINDER)
{ {
builder.markCylinderArea(layer, tile.header.bmin, m_params.cs, m_params.ch, ob.pos, ob.radius, ob.height, 0); builder.MarkCylinderArea(layer, tile.header.bmin, m_params.cs, m_params.ch, ob.pos, ob.radius, ob.height, 0);
} }
else if (ob.type == TileCacheObstacle.TileCacheObstacleType.BOX) else if (ob.type == TileCacheObstacle.TileCacheObstacleType.BOX)
{ {
builder.markBoxArea(layer, tile.header.bmin, m_params.cs, m_params.ch, ob.bmin, ob.bmax, 0); builder.MarkBoxArea(layer, tile.header.bmin, m_params.cs, m_params.ch, ob.bmin, ob.bmax, 0);
} }
else if (ob.type == TileCacheObstacle.TileCacheObstacleType.ORIENTED_BOX) else if (ob.type == TileCacheObstacle.TileCacheObstacleType.ORIENTED_BOX)
{ {
builder.markBoxArea(layer, tile.header.bmin, m_params.cs, m_params.ch, ob.center, ob.extents, ob.rotAux, 0); builder.MarkBoxArea(layer, tile.header.bmin, m_params.cs, m_params.ch, ob.center, ob.extents, ob.rotAux, 0);
} }
} }
} }
// Build navmesh // Build navmesh
builder.buildTileCacheRegions(layer, walkableClimbVx); builder.BuildTileCacheRegions(layer, walkableClimbVx);
TileCacheContourSet lcset = builder.buildTileCacheContours(layer, walkableClimbVx, TileCacheContourSet lcset = builder.BuildTileCacheContours(layer, walkableClimbVx,
m_params.maxSimplificationError); m_params.maxSimplificationError);
TileCachePolyMesh polyMesh = builder.buildTileCachePolyMesh(lcset, m_navmesh.getMaxVertsPerPoly()); TileCachePolyMesh polyMesh = builder.BuildTileCachePolyMesh(lcset, m_navmesh.GetMaxVertsPerPoly());
// Early out if the mesh tile is empty. // Early out if the mesh tile is empty.
if (polyMesh.npolys == 0) if (polyMesh.npolys == 0)
{ {
m_navmesh.removeTile(m_navmesh.getTileRefAt(tile.header.tx, tile.header.ty, tile.header.tlayer)); m_navmesh.RemoveTile(m_navmesh.GetTileRefAt(tile.header.tx, tile.header.ty, tile.header.tlayer));
return; return;
} }
@ -648,7 +648,7 @@ namespace DotRecast.Detour.TileCache
option.polyAreas = polyMesh.areas; option.polyAreas = polyMesh.areas;
option.polyFlags = polyMesh.flags; option.polyFlags = polyMesh.flags;
option.polyCount = polyMesh.npolys; option.polyCount = polyMesh.npolys;
option.nvp = m_navmesh.getMaxVertsPerPoly(); option.nvp = m_navmesh.GetMaxVertsPerPoly();
option.walkableHeight = m_params.walkableHeight; option.walkableHeight = m_params.walkableHeight;
option.walkableRadius = m_params.walkableRadius; option.walkableRadius = m_params.walkableRadius;
option.walkableClimb = m_params.walkableClimb; option.walkableClimb = m_params.walkableClimb;
@ -662,27 +662,27 @@ namespace DotRecast.Detour.TileCache
option.bmax = tile.header.bmax; option.bmax = tile.header.bmax;
if (m_tmproc != null) if (m_tmproc != null)
{ {
m_tmproc.process(option); m_tmproc.Process(option);
} }
MeshData meshData = NavMeshBuilder.createNavMeshData(option); MeshData meshData = NavMeshBuilder.CreateNavMeshData(option);
// Remove existing tile. // Remove existing tile.
m_navmesh.removeTile(m_navmesh.getTileRefAt(tile.header.tx, tile.header.ty, tile.header.tlayer)); m_navmesh.RemoveTile(m_navmesh.GetTileRefAt(tile.header.tx, tile.header.ty, tile.header.tlayer));
// 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);
} }
} }
public TileCacheLayer decompressTile(CompressedTile tile) public TileCacheLayer DecompressTile(CompressedTile tile)
{ {
TileCacheLayer layer = builder.decompressTileCacheLayer(m_tcomp, tile.data, m_storageParams.byteOrder, TileCacheLayer layer = builder.DecompressTileCacheLayer(m_tcomp, tile.data, m_storageParams.byteOrder,
m_storageParams.cCompatibility); m_storageParams.cCompatibility);
return layer; return layer;
} }
void calcTightTileBounds(TileCacheLayerHeader header, ref Vector3f bmin, ref Vector3f bmax) void CalcTightTileBounds(TileCacheLayerHeader header, ref Vector3f bmin, ref Vector3f bmax)
{ {
float cs = m_params.cs; float cs = m_params.cs;
bmin.x = header.bmin.x + header.minx * cs; bmin.x = header.bmin.x + header.minx * cs;
@ -693,7 +693,7 @@ namespace DotRecast.Detour.TileCache
bmax.z = header.bmin.z + (header.maxy + 1) * cs; bmax.z = header.bmin.z + (header.maxy + 1) * cs;
} }
void getObstacleBounds(TileCacheObstacle ob, ref Vector3f bmin, ref Vector3f bmax) void GetObstacleBounds(TileCacheObstacle ob, ref Vector3f bmin, ref Vector3f bmax)
{ {
if (ob.type == TileCacheObstacle.TileCacheObstacleType.CYLINDER) if (ob.type == TileCacheObstacle.TileCacheObstacleType.CYLINDER)
{ {
@ -721,27 +721,27 @@ namespace DotRecast.Detour.TileCache
} }
} }
public TileCacheParams getParams() public TileCacheParams GetParams()
{ {
return m_params; return m_params;
} }
public TileCacheCompressor getCompressor() public TileCacheCompressor GetCompressor()
{ {
return m_tcomp; return m_tcomp;
} }
public int getTileCount() public int GetTileCount()
{ {
return m_params.maxTiles; return m_params.maxTiles;
} }
public CompressedTile getTile(int i) public CompressedTile GetTile(int i)
{ {
return m_tiles[i]; return m_tiles[i];
} }
public NavMesh getNavMesh() public NavMesh GetNavMesh()
{ {
return m_navmesh; return m_navmesh;
} }

View File

@ -62,12 +62,12 @@ namespace DotRecast.Detour.TileCache
poly = new List<int>(); poly = new List<int>();
} }
public int npoly() public int Npoly()
{ {
return poly.Count; return poly.Count;
} }
public void clear() public void Clear()
{ {
nverts = 0; nverts = 0;
verts.Clear(); verts.Clear();
@ -83,7 +83,7 @@ namespace DotRecast.Detour.TileCache
private readonly TileCacheLayerHeaderReader reader = new TileCacheLayerHeaderReader(); private readonly TileCacheLayerHeaderReader reader = new TileCacheLayerHeaderReader();
public void buildTileCacheRegions(TileCacheLayer layer, int walkableClimb) public void BuildTileCacheRegions(TileCacheLayer layer, int walkableClimb)
{ {
int w = layer.header.width; int w = layer.header.width;
int h = layer.header.height; int h = layer.header.height;
@ -107,7 +107,7 @@ namespace DotRecast.Detour.TileCache
Array.Fill(prevCount, 0, 0, regId); Array.Fill(prevCount, 0, 0, regId);
} }
// memset(prevCount,0,sizeof(char)*regId); // Memset(prevCount,0,Sizeof(char)*regId);
int sweepId = 0; int sweepId = 0;
for (int x = 0; x < w; ++x) for (int x = 0; x < w; ++x)
@ -120,7 +120,7 @@ namespace DotRecast.Detour.TileCache
// -x // -x
int xidx = (x - 1) + y * w; int xidx = (x - 1) + y * w;
if (x > 0 && isConnected(layer, idx, xidx, walkableClimb)) if (x > 0 && IsConnected(layer, idx, xidx, walkableClimb))
{ {
if (layer.regs[xidx] != 0xff) if (layer.regs[xidx] != 0xff)
sid = layer.regs[xidx]; sid = layer.regs[xidx];
@ -135,7 +135,7 @@ namespace DotRecast.Detour.TileCache
// -y // -y
int yidx = x + (y - 1) * w; int yidx = x + (y - 1) * w;
if (y > 0 && isConnected(layer, idx, yidx, walkableClimb)) if (y > 0 && IsConnected(layer, idx, yidx, walkableClimb))
{ {
int nr = layer.regs[yidx]; int nr = layer.regs[yidx];
if (nr != 0xff) if (nr != 0xff)
@ -221,13 +221,13 @@ namespace DotRecast.Detour.TileCache
// Update neighbours // Update neighbours
int ymi = x + (y - 1) * w; int ymi = x + (y - 1) * w;
if (y > 0 && isConnected(layer, idx, ymi, walkableClimb)) if (y > 0 && IsConnected(layer, idx, ymi, walkableClimb))
{ {
int rai = layer.regs[ymi]; int rai = layer.regs[ymi];
if (rai != 0xff && rai != ri) if (rai != 0xff && rai != ri)
{ {
addUniqueLast(regs[ri].neis, rai); AddUniqueLast(regs[ri].neis, rai);
addUniqueLast(regs[rai].neis, ri); AddUniqueLast(regs[rai].neis, ri);
} }
} }
} }
@ -251,7 +251,7 @@ namespace DotRecast.Detour.TileCache
continue; continue;
if (regn.area > mergea) if (regn.area > mergea)
{ {
if (canMerge(reg.regId, regn.regId, regs, nregs)) if (CanMerge(reg.regId, regn.regId, regs, nregs))
{ {
mergea = regn.area; mergea = regn.area;
merge = nei; merge = nei;
@ -291,7 +291,7 @@ namespace DotRecast.Detour.TileCache
} }
} }
void addUniqueLast(List<int> a, int v) void AddUniqueLast(List<int> a, int v)
{ {
int n = a.Count; int n = a.Count;
if (n > 0 && a[n - 1] == v) if (n > 0 && a[n - 1] == v)
@ -299,7 +299,7 @@ namespace DotRecast.Detour.TileCache
a.Add(v); a.Add(v);
} }
bool isConnected(TileCacheLayer layer, int ia, int ib, int walkableClimb) bool IsConnected(TileCacheLayer layer, int ia, int ib, int walkableClimb)
{ {
if (layer.areas[ia] != layer.areas[ib]) if (layer.areas[ia] != layer.areas[ib])
return false; return false;
@ -308,7 +308,7 @@ namespace DotRecast.Detour.TileCache
return true; return true;
} }
bool canMerge(int oldRegId, int newRegId, LayerMonotoneRegion[] regs, int nregs) bool CanMerge(int oldRegId, int newRegId, LayerMonotoneRegion[] regs, int nregs)
{ {
int count = 0; int count = 0;
for (int i = 0; i < nregs; ++i) for (int i = 0; i < nregs; ++i)
@ -326,7 +326,7 @@ namespace DotRecast.Detour.TileCache
return count == 1; return count == 1;
} }
private void appendVertex(TempContour cont, int x, int y, int z, int r) private void AppendVertex(TempContour cont, int x, int y, int z, int r)
{ {
// Try to merge with existing segments. // Try to merge with existing segments.
if (cont.nverts > 1) if (cont.nverts > 1)
@ -360,7 +360,7 @@ namespace DotRecast.Detour.TileCache
cont.nverts++; cont.nverts++;
} }
private int getNeighbourReg(TileCacheLayer layer, int ax, int ay, int dir) private int GetNeighbourReg(TileCacheLayer layer, int ax, int ay, int dir)
{ {
int w = layer.header.width; int w = layer.header.width;
int ia = ax + ay * w; int ia = ax + ay * w;
@ -377,30 +377,30 @@ namespace DotRecast.Detour.TileCache
return 0xff; return 0xff;
} }
int bx = ax + getDirOffsetX(dir); int bx = ax + GetDirOffsetX(dir);
int by = ay + getDirOffsetY(dir); int by = ay + GetDirOffsetY(dir);
int ib = bx + by * w; int ib = bx + by * w;
return layer.regs[ib]; return layer.regs[ib];
} }
private int getDirOffsetX(int dir) private int GetDirOffsetX(int dir)
{ {
int[] offset = new int[] { -1, 0, 1, 0, }; int[] offset = new int[] { -1, 0, 1, 0, };
return offset[dir & 0x03]; return offset[dir & 0x03];
} }
private int getDirOffsetY(int dir) private int GetDirOffsetY(int dir)
{ {
int[] offset = new int[] { 0, 1, 0, -1 }; int[] offset = new int[] { 0, 1, 0, -1 };
return offset[dir & 0x03]; return offset[dir & 0x03];
} }
private void walkContour(TileCacheLayer layer, int x, int y, TempContour cont) private void WalkContour(TileCacheLayer layer, int x, int y, TempContour cont)
{ {
int w = layer.header.width; int w = layer.header.width;
int h = layer.header.height; int h = layer.header.height;
cont.clear(); cont.Clear();
int startX = x; int startX = x;
int startY = y; int startY = y;
@ -409,7 +409,7 @@ namespace DotRecast.Detour.TileCache
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
int ndir = (i + 3) & 3; int ndir = (i + 3) & 3;
int rn = getNeighbourReg(layer, x, y, ndir); int rn = GetNeighbourReg(layer, x, y, ndir);
if (rn != layer.regs[x + y * w]) if (rn != layer.regs[x + y * w])
{ {
startDir = ndir; startDir = ndir;
@ -425,7 +425,7 @@ namespace DotRecast.Detour.TileCache
int iter = 0; int iter = 0;
while (iter < maxIter) while (iter < maxIter)
{ {
int rn = getNeighbourReg(layer, x, y, dir); int rn = GetNeighbourReg(layer, x, y, dir);
int nx = x; int nx = x;
int ny = y; int ny = y;
@ -451,14 +451,14 @@ namespace DotRecast.Detour.TileCache
} }
// Try to merge with previous vertex. // Try to merge with previous vertex.
appendVertex(cont, px, layer.heights[x + y * w], pz, rn); AppendVertex(cont, px, layer.heights[x + y * w], pz, rn);
ndir = (dir + 1) & 0x3; // Rotate CW ndir = (dir + 1) & 0x3; // Rotate CW
} }
else else
{ {
// Move to next. // Move to next.
nx = x + getDirOffsetX(dir); nx = x + GetDirOffsetX(dir);
ny = y + getDirOffsetY(dir); ny = y + GetDirOffsetY(dir);
ndir = (dir + 3) & 0x3; // Rotate CCW ndir = (dir + 3) & 0x3; // Rotate CCW
} }
@ -480,7 +480,7 @@ namespace DotRecast.Detour.TileCache
cont.nverts--; cont.nverts--;
} }
private float distancePtSeg(int x, int z, int px, int pz, int qx, int qz) private float DistancePtSeg(int x, int z, int px, int pz, int qx, int qz)
{ {
float pqx = qx - px; float pqx = qx - px;
float pqz = qz - pz; float pqz = qz - pz;
@ -501,7 +501,7 @@ namespace DotRecast.Detour.TileCache
return dx * dx + dz * dz; return dx * dx + dz * dz;
} }
private void simplifyContour(TempContour cont, float maxError) private void SimplifyContour(TempContour cont, float maxError)
{ {
cont.poly.Clear(); cont.poly.Clear();
@ -515,7 +515,7 @@ namespace DotRecast.Detour.TileCache
cont.poly.Add(i); cont.poly.Add(i);
} }
if (cont.npoly() < 2) if (cont.Npoly() < 2)
{ {
// If there is no transitions at all, // If there is no transitions at all,
// create some initial points for the simplification process. // create some initial points for the simplification process.
@ -552,9 +552,9 @@ namespace DotRecast.Detour.TileCache
// Add points until all raw points are within // Add points until all raw points are within
// error tolerance to the simplified shape. // error tolerance to the simplified shape.
for (int i = 0; i < cont.npoly();) for (int i = 0; i < cont.Npoly();)
{ {
int ii = (i + 1) % cont.npoly(); int ii = (i + 1) % cont.Npoly();
int ai = cont.poly[i]; int ai = cont.poly[i];
int ax = cont.verts[ai * 4]; int ax = cont.verts[ai * 4];
@ -588,7 +588,7 @@ namespace DotRecast.Detour.TileCache
// Tessellate only outer edges or edges between areas. // Tessellate only outer edges or edges between areas.
while (ci != endi) while (ci != endi)
{ {
float d = distancePtSeg(cont.verts[ci * 4], cont.verts[ci * 4 + 2], ax, az, bx, bz); float d = DistancePtSeg(cont.verts[ci * 4], cont.verts[ci * 4 + 2], ax, az, bx, bz);
if (d > maxd) if (d > maxd)
{ {
maxd = d; maxd = d;
@ -612,14 +612,14 @@ namespace DotRecast.Detour.TileCache
// Remap vertices // Remap vertices
int start = 0; int start = 0;
for (int i = 1; i < cont.npoly(); ++i) for (int i = 1; i < cont.Npoly(); ++i)
if (cont.poly[i] < cont.poly[start]) if (cont.poly[i] < cont.poly[start])
start = i; start = i;
cont.nverts = 0; cont.nverts = 0;
for (int i = 0; i < cont.npoly(); ++i) for (int i = 0; i < cont.Npoly(); ++i)
{ {
int j = (start + i) % cont.npoly(); int j = (start + i) % cont.Npoly();
int src = cont.poly[j] * 4; int src = cont.poly[j] * 4;
int dst = cont.nverts * 4; int dst = cont.nverts * 4;
cont.verts[dst] = cont.verts[src]; cont.verts[dst] = cont.verts[src];
@ -630,7 +630,7 @@ namespace DotRecast.Detour.TileCache
} }
} }
static Tuple<int, bool> getCornerHeight(TileCacheLayer layer, int x, int y, int z, int walkableClimb) static Tuple<int, bool> GetCornerHeight(TileCacheLayer layer, int x, int y, int z, int walkableClimb)
{ {
int w = layer.header.width; int w = layer.header.width;
int h = layer.header.height; int h = layer.header.height;
@ -680,7 +680,7 @@ namespace DotRecast.Detour.TileCache
} }
// TODO: move this somewhere else, once the layer meshing is done. // TODO: move this somewhere else, once the layer meshing is done.
public TileCacheContourSet buildTileCacheContours(TileCacheLayer layer, int walkableClimb, float maxError) public TileCacheContourSet BuildTileCacheContours(TileCacheLayer layer, int walkableClimb, float maxError)
{ {
int w = layer.header.width; int w = layer.header.width;
int h = layer.header.height; int h = layer.header.height;
@ -714,9 +714,9 @@ namespace DotRecast.Detour.TileCache
cont.reg = ri; cont.reg = ri;
cont.area = layer.areas[idx]; cont.area = layer.areas[idx];
walkContour(layer, x, y, temp); WalkContour(layer, x, y, temp);
simplifyContour(temp, maxError); SimplifyContour(temp, maxError);
// Store contour. // Store contour.
cont.nverts = temp.nverts; cont.nverts = temp.nverts;
@ -734,7 +734,7 @@ namespace DotRecast.Detour.TileCache
// stored at segment // stored at segment
// vertex of a // vertex of a
// segment. // segment.
Tuple<int, bool> res = getCornerHeight(layer, temp.verts[v], temp.verts[v + 1], Tuple<int, bool> res = GetCornerHeight(layer, temp.verts[v], temp.verts[v + 1],
temp.verts[v + 2], walkableClimb); temp.verts[v + 2], walkableClimb);
int lh = res.Item1; int lh = res.Item1;
bool shouldRemove = res.Item2; bool shouldRemove = res.Item2;
@ -759,7 +759,7 @@ namespace DotRecast.Detour.TileCache
const uint VERTEX_BUCKET_COUNT2 = (1 << 8); const uint VERTEX_BUCKET_COUNT2 = (1 << 8);
private int computeVertexHash2(int x, int y, int z) private int ComputeVertexHash2(int x, int y, int z)
{ {
uint h1 = 0x8da6b343; // Large multiplicative constants; uint h1 = 0x8da6b343; // Large multiplicative constants;
uint h2 = 0xd8163841; // here arbitrarily chosen primes uint h2 = 0xd8163841; // here arbitrarily chosen primes
@ -768,9 +768,9 @@ namespace DotRecast.Detour.TileCache
return (int)(n & (VERTEX_BUCKET_COUNT2 - 1)); return (int)(n & (VERTEX_BUCKET_COUNT2 - 1));
} }
private int addVertex(int x, int y, int z, int[] verts, int[] firstVert, int[] nextVert, int nv) private int AddVertex(int x, int y, int z, int[] verts, int[] firstVert, int[] nextVert, int nv)
{ {
int bucket = computeVertexHash2(x, 0, z); int bucket = ComputeVertexHash2(x, 0, z);
int i = firstVert[bucket]; int i = firstVert[bucket];
while (i != DT_TILECACHE_NULL_IDX) while (i != DT_TILECACHE_NULL_IDX)
{ {
@ -791,7 +791,7 @@ namespace DotRecast.Detour.TileCache
return i; return i;
} }
private void buildMeshAdjacency(int[] polys, int npolys, int[] verts, int nverts, TileCacheContourSet lcset, private void BuildMeshAdjacency(int[] polys, int npolys, int[] verts, int nverts, TileCacheContourSet lcset,
int maxVertsPerPoly) int maxVertsPerPoly)
{ {
// Based on code by Eric Lengyel from: // Based on code by Eric Lengyel from:
@ -932,7 +932,7 @@ namespace DotRecast.Detour.TileCache
ezmax = tmp; ezmax = tmp;
} }
if (overlapRangeExl(zmin, zmax, ezmin, ezmax)) if (OverlapRangeExl(zmin, zmax, ezmin, ezmax))
{ {
// Reuse the other polyedge to store dir. // Reuse the other polyedge to store dir.
e.polyEdge[1] = dir; e.polyEdge[1] = dir;
@ -972,7 +972,7 @@ namespace DotRecast.Detour.TileCache
exmax = tmp; exmax = tmp;
} }
if (overlapRangeExl(xmin, xmax, exmin, exmax)) if (OverlapRangeExl(xmin, xmax, exmin, exmax))
{ {
// Reuse the other polyedge to store dir. // Reuse the other polyedge to store dir.
e.polyEdge[1] = dir; e.polyEdge[1] = dir;
@ -1002,22 +1002,22 @@ namespace DotRecast.Detour.TileCache
} }
} }
private bool overlapRangeExl(int amin, int amax, int bmin, int bmax) private bool OverlapRangeExl(int amin, int amax, int bmin, int bmax)
{ {
return (amin >= bmax || amax <= bmin) ? false : true; return (amin >= bmax || amax <= bmin) ? false : true;
} }
private int prev(int i, int n) private int Prev(int i, int n)
{ {
return i - 1 >= 0 ? i - 1 : n - 1; return i - 1 >= 0 ? i - 1 : n - 1;
} }
private int next(int i, int n) private int Next(int i, int n)
{ {
return i + 1 < n ? i + 1 : 0; return i + 1 < n ? i + 1 : 0;
} }
private int area2(int[] verts, int a, int b, int c) private int Area2(int[] verts, int a, int b, int c)
{ {
return (verts[b] - verts[a]) * (verts[c + 2] - verts[a + 2]) return (verts[b] - verts[a]) * (verts[c + 2] - verts[a + 2])
- (verts[c] - verts[a]) * (verts[b + 2] - verts[a + 2]); - (verts[c] - verts[a]) * (verts[b + 2] - verts[a + 2]);
@ -1025,39 +1025,39 @@ namespace DotRecast.Detour.TileCache
// Returns true iff c is strictly to the left of the directed // Returns true iff c is strictly to the left of the directed
// line through a to b. // line through a to b.
private bool left(int[] verts, int a, int b, int c) private bool Left(int[] verts, int a, int b, int c)
{ {
return area2(verts, a, b, c) < 0; return Area2(verts, a, b, c) < 0;
} }
private bool leftOn(int[] verts, int a, int b, int c) private bool LeftOn(int[] verts, int a, int b, int c)
{ {
return area2(verts, a, b, c) <= 0; return Area2(verts, a, b, c) <= 0;
} }
private bool collinear(int[] verts, int a, int b, int c) private bool Collinear(int[] verts, int a, int b, int c)
{ {
return area2(verts, a, b, c) == 0; return Area2(verts, a, b, c) == 0;
} }
// Returns true iff ab properly intersects cd: they share // Returns true iff ab properly intersects cd: they share
// a point interior to both segments. The properness of the // a point interior to both segments. The properness of the
// intersection is ensured by using strict leftness. // intersection is ensured by using strict leftness.
private bool intersectProp(int[] verts, int a, int b, int c, int d) private bool IntersectProp(int[] verts, int a, int b, int c, int d)
{ {
// Eliminate improper cases. // Eliminate improper cases.
if (collinear(verts, a, b, c) || collinear(verts, a, b, d) || collinear(verts, c, d, a) if (Collinear(verts, a, b, c) || Collinear(verts, a, b, d) || Collinear(verts, c, d, a)
|| collinear(verts, c, d, b)) || Collinear(verts, c, d, b))
return false; return false;
return (left(verts, a, b, c) ^ left(verts, a, b, d)) && (left(verts, c, d, a) ^ left(verts, c, d, b)); return (Left(verts, a, b, c) ^ Left(verts, a, b, d)) && (Left(verts, c, d, a) ^ Left(verts, c, d, b));
} }
// Returns T iff (a,b,c) are collinear and point c lies // Returns T iff (a,b,c) are collinear and point c lies
// on the closed segement ab. // on the closed segement ab.
private bool between(int[] verts, int a, int b, int c) private bool Between(int[] verts, int a, int b, int c)
{ {
if (!collinear(verts, a, b, c)) if (!Collinear(verts, a, b, c))
return false; return false;
// If ab not vertical, check betweenness on x; else on y. // If ab not vertical, check betweenness on x; else on y.
if (verts[a] != verts[b]) if (verts[a] != verts[b])
@ -1069,25 +1069,25 @@ namespace DotRecast.Detour.TileCache
} }
// Returns true iff segments ab and cd intersect, properly or improperly. // Returns true iff segments ab and cd intersect, properly or improperly.
private bool intersect(int[] verts, int a, int b, int c, int d) private bool Intersect(int[] verts, int a, int b, int c, int d)
{ {
if (intersectProp(verts, a, b, c, d)) if (IntersectProp(verts, a, b, c, d))
return true; return true;
else if (between(verts, a, b, c) || between(verts, a, b, d) || between(verts, c, d, a) else if (Between(verts, a, b, c) || Between(verts, a, b, d) || Between(verts, c, d, a)
|| between(verts, c, d, b)) || Between(verts, c, d, b))
return true; return true;
else else
return false; return false;
} }
private bool vequal(int[] verts, int a, int b) private bool Vequal(int[] verts, int a, int b)
{ {
return verts[a] == verts[b] && verts[a + 2] == verts[b + 2]; return verts[a] == verts[b] && verts[a + 2] == verts[b + 2];
} }
// Returns T iff (v_i, v_j) is a proper internal *or* external // Returns T iff (v_i, v_j) is a proper internal *or* external
// diagonal of P, *ignoring edges incident to v_i and v_j*. // diagonal of P, *ignoring edges incident to v_i and v_j*.
private bool diagonalie(int i, int j, int n, int[] verts, int[] indices) private bool Diagonalie(int i, int j, int n, int[] verts, int[] indices)
{ {
int d0 = (indices[i] & 0x7fff) * 4; int d0 = (indices[i] & 0x7fff) * 4;
int d1 = (indices[j] & 0x7fff) * 4; int d1 = (indices[j] & 0x7fff) * 4;
@ -1095,17 +1095,17 @@ namespace DotRecast.Detour.TileCache
// For each edge (k,k+1) of P // For each edge (k,k+1) of P
for (int k = 0; k < n; k++) for (int k = 0; k < n; k++)
{ {
int k1 = next(k, n); int k1 = Next(k, n);
// Skip edges incident to i or j // Skip edges incident to i or j
if (!((k == i) || (k1 == i) || (k == j) || (k1 == j))) if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
{ {
int p0 = (indices[k] & 0x7fff) * 4; int p0 = (indices[k] & 0x7fff) * 4;
int p1 = (indices[k1] & 0x7fff) * 4; int p1 = (indices[k1] & 0x7fff) * 4;
if (vequal(verts, d0, p0) || vequal(verts, d1, p0) || vequal(verts, d0, p1) || vequal(verts, d1, p1)) if (Vequal(verts, d0, p0) || Vequal(verts, d1, p0) || Vequal(verts, d0, p1) || Vequal(verts, d1, p1))
continue; continue;
if (intersect(verts, d0, d1, p0, p1)) if (Intersect(verts, d0, d1, p0, p1))
return false; return false;
} }
} }
@ -1115,29 +1115,29 @@ namespace DotRecast.Detour.TileCache
// Returns true iff the diagonal (i,j) is strictly internal to the // Returns true iff the diagonal (i,j) is strictly internal to the
// polygon P in the neighborhood of the i endpoint. // polygon P in the neighborhood of the i endpoint.
private bool inCone(int i, int j, int n, int[] verts, int[] indices) private bool InCone(int i, int j, int n, int[] verts, int[] indices)
{ {
int pi = (indices[i] & 0x7fff) * 4; int pi = (indices[i] & 0x7fff) * 4;
int pj = (indices[j] & 0x7fff) * 4; int pj = (indices[j] & 0x7fff) * 4;
int pi1 = (indices[next(i, n)] & 0x7fff) * 4; int pi1 = (indices[Next(i, n)] & 0x7fff) * 4;
int pin1 = (indices[prev(i, n)] & 0x7fff) * 4; int pin1 = (indices[Prev(i, n)] & 0x7fff) * 4;
// If P[i] is a convex vertex [ i+1 left or on (i-1,i) ]. // If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
if (leftOn(verts, pin1, pi, pi1)) if (LeftOn(verts, pin1, pi, pi1))
return left(verts, pi, pj, pin1) && left(verts, pj, pi, pi1); return Left(verts, pi, pj, pin1) && Left(verts, pj, pi, pi1);
// Assume (i-1,i,i+1) not collinear. // Assume (i-1,i,i+1) not collinear.
// else P[i] is reflex. // else P[i] is reflex.
return !(leftOn(verts, pi, pj, pi1) && leftOn(verts, pj, pi, pin1)); return !(LeftOn(verts, pi, pj, pi1) && LeftOn(verts, pj, pi, pin1));
} }
// Returns T iff (v_i, v_j) is a proper internal // Returns T iff (v_i, v_j) is a proper internal
// diagonal of P. // diagonal of P.
private bool diagonal(int i, int j, int n, int[] verts, int[] indices) private bool Diagonal(int i, int j, int n, int[] verts, int[] indices)
{ {
return inCone(i, j, n, verts, indices) && diagonalie(i, j, n, verts, indices); return InCone(i, j, n, verts, indices) && Diagonalie(i, j, n, verts, indices);
} }
private int triangulate(int n, int[] verts, int[] indices, int[] tris) private int Triangulate(int n, int[] verts, int[] indices, int[] tris)
{ {
int ntris = 0; int ntris = 0;
int dst = 0; // tris; int dst = 0; // tris;
@ -1145,9 +1145,9 @@ namespace DotRecast.Detour.TileCache
// removed. // removed.
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
{ {
int i1 = next(i, n); int i1 = Next(i, n);
int i2 = next(i1, n); int i2 = Next(i1, n);
if (diagonal(i, i2, n, verts, indices)) if (Diagonal(i, i2, n, verts, indices))
indices[i1] |= 0x8000; indices[i1] |= 0x8000;
} }
@ -1157,11 +1157,11 @@ namespace DotRecast.Detour.TileCache
int mini = -1; int mini = -1;
for (int mi = 0; mi < n; mi++) for (int mi = 0; mi < n; mi++)
{ {
int mi1 = next(mi, n); int mi1 = Next(mi, n);
if ((indices[mi1] & 0x8000) != 0) if ((indices[mi1] & 0x8000) != 0)
{ {
int p0 = (indices[mi] & 0x7fff) * 4; int p0 = (indices[mi] & 0x7fff) * 4;
int p2 = (indices[next(mi1, n)] & 0x7fff) * 4; int p2 = (indices[Next(mi1, n)] & 0x7fff) * 4;
int dx = verts[p2] - verts[p0]; int dx = verts[p2] - verts[p0];
int dz = verts[p2 + 2] - verts[p0 + 2]; int dz = verts[p2 + 2] - verts[p0 + 2];
@ -1178,15 +1178,15 @@ namespace DotRecast.Detour.TileCache
{ {
// Should not happen. // Should not happen.
/* /*
* printf("mini == -1 ntris=%d n=%d\n", ntris, n); for (int i = 0; i < n; i++) { printf("%d ", * Printf("mini == -1 ntris=%d n=%d\n", ntris, n); for (int i = 0; i < n; i++) { Printf("%d ",
* indices[i] & 0x0fffffff); } printf("\n"); * indices[i] & 0x0fffffff); } Printf("\n");
*/ */
return -ntris; return -ntris;
} }
int i = mini; int i = mini;
int i1 = next(i, n); int i1 = Next(i, n);
int i2 = next(i1, n); int i2 = Next(i1, n);
tris[dst++] = indices[i] & 0x7fff; tris[dst++] = indices[i] & 0x7fff;
tris[dst++] = indices[i1] & 0x7fff; tris[dst++] = indices[i1] & 0x7fff;
@ -1200,14 +1200,14 @@ namespace DotRecast.Detour.TileCache
if (i1 >= n) if (i1 >= n)
i1 = 0; i1 = 0;
i = prev(i1, n); i = Prev(i1, n);
// Update diagonal flags. // Update diagonal flags.
if (diagonal(prev(i, n), i1, n, verts, indices)) if (Diagonal(Prev(i, n), i1, n, verts, indices))
indices[i] |= 0x8000; indices[i] |= 0x8000;
else else
indices[i] &= 0x7fff; indices[i] &= 0x7fff;
if (diagonal(i, next(i1, n), n, verts, indices)) if (Diagonal(i, Next(i1, n), n, verts, indices))
indices[i1] |= 0x8000; indices[i1] |= 0x8000;
else else
indices[i1] &= 0x7fff; indices[i1] &= 0x7fff;
@ -1222,7 +1222,7 @@ namespace DotRecast.Detour.TileCache
return ntris; return ntris;
} }
private int countPolyVerts(int[] polys, int p, int maxVertsPerPoly) private int CountPolyVerts(int[] polys, int p, int maxVertsPerPoly)
{ {
for (int i = 0; i < maxVertsPerPoly; ++i) for (int i = 0; i < maxVertsPerPoly; ++i)
if (polys[p + i] == DT_TILECACHE_NULL_IDX) if (polys[p + i] == DT_TILECACHE_NULL_IDX)
@ -1230,16 +1230,16 @@ namespace DotRecast.Detour.TileCache
return maxVertsPerPoly; return maxVertsPerPoly;
} }
private bool uleft(int[] verts, int a, int b, int c) private bool Uleft(int[] verts, int a, int b, int c)
{ {
return (verts[b] - verts[a]) * (verts[c + 2] - verts[a + 2]) return (verts[b] - verts[a]) * (verts[c + 2] - verts[a + 2])
- (verts[c] - verts[a]) * (verts[b + 2] - verts[a + 2]) < 0; - (verts[c] - verts[a]) * (verts[b + 2] - verts[a + 2]) < 0;
} }
private int[] getPolyMergeValue(int[] polys, int pa, int pb, int[] verts, int maxVertsPerPoly) private int[] GetPolyMergeValue(int[] polys, int pa, int pb, int[] verts, int maxVertsPerPoly)
{ {
int na = countPolyVerts(polys, pa, maxVertsPerPoly); int na = CountPolyVerts(polys, pa, maxVertsPerPoly);
int nb = countPolyVerts(polys, pb, maxVertsPerPoly); int nb = CountPolyVerts(polys, pb, maxVertsPerPoly);
// If the merged polygon would be too big, do not merge. // If the merged polygon would be too big, do not merge.
if (na + nb - 2 > maxVertsPerPoly) if (na + nb - 2 > maxVertsPerPoly)
@ -1290,13 +1290,13 @@ namespace DotRecast.Detour.TileCache
va = polys[pa + (ea + na - 1) % na]; va = polys[pa + (ea + na - 1) % na];
vb = polys[pa + ea]; vb = polys[pa + ea];
vc = polys[pb + (eb + 2) % nb]; vc = polys[pb + (eb + 2) % nb];
if (!uleft(verts, va * 3, vb * 3, vc * 3)) if (!Uleft(verts, va * 3, vb * 3, vc * 3))
return new int[] { -1, ea, eb }; return new int[] { -1, ea, eb };
va = polys[pb + (eb + nb - 1) % nb]; va = polys[pb + (eb + nb - 1) % nb];
vb = polys[pb + eb]; vb = polys[pb + eb];
vc = polys[pa + (ea + 2) % na]; vc = polys[pa + (ea + 2) % na];
if (!uleft(verts, va * 3, vb * 3, vc * 3)) if (!Uleft(verts, va * 3, vb * 3, vc * 3))
return new int[] { -1, ea, eb }; return new int[] { -1, ea, eb };
va = polys[pa + ea]; va = polys[pa + ea];
@ -1308,12 +1308,12 @@ namespace DotRecast.Detour.TileCache
return new int[] { dx * dx + dy * dy, ea, eb }; return new int[] { dx * dx + dy * dy, ea, eb };
} }
private void mergePolys(int[] polys, int pa, int pb, int ea, int eb, int maxVertsPerPoly) private void MergePolys(int[] polys, int pa, int pb, int ea, int eb, int maxVertsPerPoly)
{ {
int[] tmp = new int[maxVertsPerPoly * 2]; int[] tmp = new int[maxVertsPerPoly * 2];
int na = countPolyVerts(polys, pa, maxVertsPerPoly); int na = CountPolyVerts(polys, pa, maxVertsPerPoly);
int nb = countPolyVerts(polys, pb, maxVertsPerPoly); int nb = CountPolyVerts(polys, pb, maxVertsPerPoly);
// Merge polygons. // Merge polygons.
Array.Fill(tmp, DT_TILECACHE_NULL_IDX); Array.Fill(tmp, DT_TILECACHE_NULL_IDX);
@ -1327,19 +1327,19 @@ namespace DotRecast.Detour.TileCache
Array.Copy(tmp, 0, polys, pa, maxVertsPerPoly); Array.Copy(tmp, 0, polys, pa, maxVertsPerPoly);
} }
private int pushFront(int v, List<int> arr) private int PushFront(int v, List<int> arr)
{ {
arr.Insert(0, v); arr.Insert(0, v);
return arr.Count; return arr.Count;
} }
private int pushBack(int v, List<int> arr) private int PushBack(int v, List<int> arr)
{ {
arr.Add(v); arr.Add(v);
return arr.Count; return arr.Count;
} }
private bool canRemoveVertex(TileCachePolyMesh mesh, int rem) private bool CanRemoveVertex(TileCachePolyMesh mesh, int rem)
{ {
// Count number of polygons to remove. // Count number of polygons to remove.
int maxVertsPerPoly = mesh.nvp; int maxVertsPerPoly = mesh.nvp;
@ -1347,7 +1347,7 @@ namespace DotRecast.Detour.TileCache
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
{ {
int p = i * mesh.nvp * 2; int p = i * mesh.nvp * 2;
int nv = countPolyVerts(mesh.polys, p, maxVertsPerPoly); int nv = CountPolyVerts(mesh.polys, p, maxVertsPerPoly);
int numRemoved = 0; int numRemoved = 0;
int numVerts = 0; int numVerts = 0;
for (int j = 0; j < nv; ++j) for (int j = 0; j < nv; ++j)
@ -1380,7 +1380,7 @@ namespace DotRecast.Detour.TileCache
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
{ {
int p = i * mesh.nvp * 2; int p = i * mesh.nvp * 2;
int nv = countPolyVerts(mesh.polys, p, maxVertsPerPoly); int nv = CountPolyVerts(mesh.polys, p, maxVertsPerPoly);
// Collect edges which touches the removed vertex. // Collect edges which touches the removed vertex.
for (int j = 0, k = nv - 1; j < nv; k = j++) for (int j = 0, k = nv - 1; j < nv; k = j++)
@ -1437,7 +1437,7 @@ namespace DotRecast.Detour.TileCache
return true; return true;
} }
private void removeVertex(TileCachePolyMesh mesh, int rem, int maxTris) private void RemoveVertex(TileCachePolyMesh mesh, int rem, int maxTris)
{ {
// Count number of polygons to remove. // Count number of polygons to remove.
int maxVertsPerPoly = mesh.nvp; int maxVertsPerPoly = mesh.nvp;
@ -1445,7 +1445,7 @@ namespace DotRecast.Detour.TileCache
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
{ {
int p = i * maxVertsPerPoly * 2; int p = i * maxVertsPerPoly * 2;
int nv = countPolyVerts(mesh.polys, p, maxVertsPerPoly); int nv = CountPolyVerts(mesh.polys, p, maxVertsPerPoly);
for (int j = 0; j < nv; ++j) for (int j = 0; j < nv; ++j)
{ {
if (mesh.polys[p + j] == rem) if (mesh.polys[p + j] == rem)
@ -1462,7 +1462,7 @@ namespace DotRecast.Detour.TileCache
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
{ {
int p = i * maxVertsPerPoly * 2; int p = i * maxVertsPerPoly * 2;
int nv = countPolyVerts(mesh.polys, p, maxVertsPerPoly); int nv = CountPolyVerts(mesh.polys, p, maxVertsPerPoly);
bool hasRem = false; bool hasRem = false;
for (int j = 0; j < nv; ++j) for (int j = 0; j < nv; ++j)
if (mesh.polys[p + j] == rem) if (mesh.polys[p + j] == rem)
@ -1505,7 +1505,7 @@ namespace DotRecast.Detour.TileCache
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
{ {
int p = i * maxVertsPerPoly * 2; int p = i * maxVertsPerPoly * 2;
int nv = countPolyVerts(mesh.polys, p, maxVertsPerPoly); int nv = CountPolyVerts(mesh.polys, p, maxVertsPerPoly);
for (int j = 0; j < nv; ++j) for (int j = 0; j < nv; ++j)
if (mesh.polys[p + j] > rem) if (mesh.polys[p + j] > rem)
mesh.polys[p + j]--; mesh.polys[p + j]--;
@ -1524,8 +1524,8 @@ namespace DotRecast.Detour.TileCache
// Start with one vertex, keep appending connected // Start with one vertex, keep appending connected
// segments to the start and end of the hole. // segments to the start and end of the hole.
nhole = pushBack(edges[0], hole); nhole = PushBack(edges[0], hole);
pushBack(edges[2], harea); PushBack(edges[2], harea);
while (nedges != 0) while (nedges != 0)
{ {
@ -1540,15 +1540,15 @@ namespace DotRecast.Detour.TileCache
if (hole[0] == eb) if (hole[0] == eb)
{ {
// The segment matches the beginning of the hole boundary. // The segment matches the beginning of the hole boundary.
nhole = pushFront(ea, hole); nhole = PushFront(ea, hole);
pushFront(a, harea); PushFront(a, harea);
add = true; add = true;
} }
else if (hole[nhole - 1] == ea) else if (hole[nhole - 1] == ea)
{ {
// The segment matches the end of the hole boundary. // The segment matches the end of the hole boundary.
nhole = pushBack(eb, hole); nhole = PushBack(eb, hole);
pushBack(a, harea); PushBack(a, harea);
add = true; add = true;
} }
@ -1584,7 +1584,7 @@ namespace DotRecast.Detour.TileCache
} }
// Triangulate the hole. // Triangulate the hole.
int ntris = triangulate(nhole, tverts, tpoly, tris); int ntris = Triangulate(nhole, tverts, tpoly, tris);
if (ntris < 0) if (ntris < 0)
{ {
// TODO: issue warning! // TODO: issue warning!
@ -1628,7 +1628,7 @@ namespace DotRecast.Detour.TileCache
for (int k = j + 1; k < npolys; ++k) for (int k = j + 1; k < npolys; ++k)
{ {
int pk = k * maxVertsPerPoly; int pk = k * maxVertsPerPoly;
int[] pm = getPolyMergeValue(polys, pj, pk, mesh.verts, maxVertsPerPoly); int[] pm = GetPolyMergeValue(polys, pj, pk, mesh.verts, maxVertsPerPoly);
int v = pm[0]; int v = pm[0];
int ea = pm[1]; int ea = pm[1];
int eb = pm[2]; int eb = pm[2];
@ -1648,7 +1648,7 @@ namespace DotRecast.Detour.TileCache
// Found best, merge. // Found best, merge.
int pa = bestPa * maxVertsPerPoly; int pa = bestPa * maxVertsPerPoly;
int pb = bestPb * maxVertsPerPoly; int pb = bestPb * maxVertsPerPoly;
mergePolys(polys, pa, pb, bestEa, bestEb, maxVertsPerPoly); MergePolys(polys, pa, pb, bestEa, bestEb, maxVertsPerPoly);
Array.Copy(polys, (npolys - 1) * maxVertsPerPoly, polys, pb, maxVertsPerPoly); Array.Copy(polys, (npolys - 1) * maxVertsPerPoly, polys, pb, maxVertsPerPoly);
pareas[bestPb] = pareas[npolys - 1]; pareas[bestPb] = pareas[npolys - 1];
npolys--; npolys--;
@ -1679,7 +1679,7 @@ namespace DotRecast.Detour.TileCache
} }
} }
public TileCachePolyMesh buildTileCachePolyMesh(TileCacheContourSet lcset, int maxVertsPerPoly) public TileCachePolyMesh BuildTileCachePolyMesh(TileCacheContourSet lcset, int maxVertsPerPoly)
{ {
int maxVertices = 0; int maxVertices = 0;
int maxTris = 0; int maxTris = 0;
@ -1733,7 +1733,7 @@ namespace DotRecast.Detour.TileCache
for (int j = 0; j < cont.nverts; ++j) for (int j = 0; j < cont.nverts; ++j)
indices[j] = j; indices[j] = j;
int ntris = triangulate(cont.nverts, cont.verts, indices, tris); int ntris = Triangulate(cont.nverts, cont.verts, indices, tris);
if (ntris <= 0) if (ntris <= 0)
{ {
// TODO: issue warning! // TODO: issue warning!
@ -1744,7 +1744,7 @@ namespace DotRecast.Detour.TileCache
for (int j = 0; j < cont.nverts; ++j) for (int j = 0; j < cont.nverts; ++j)
{ {
int v = j * 4; int v = j * 4;
indices[j] = addVertex(cont.verts[v], cont.verts[v + 1], cont.verts[v + 2], mesh.verts, firstVert, indices[j] = AddVertex(cont.verts[v], cont.verts[v + 1], cont.verts[v + 2], mesh.verts, firstVert,
nextVert, mesh.nverts); nextVert, mesh.nverts);
mesh.nverts = Math.Max(mesh.nverts, indices[j] + 1); mesh.nverts = Math.Max(mesh.nverts, indices[j] + 1);
if ((cont.verts[v + 3] & 0x80) != 0) if ((cont.verts[v + 3] & 0x80) != 0)
@ -1787,7 +1787,7 @@ namespace DotRecast.Detour.TileCache
for (int k = j + 1; k < npolys; ++k) for (int k = j + 1; k < npolys; ++k)
{ {
int pk = k * maxVertsPerPoly; int pk = k * maxVertsPerPoly;
int[] pm = getPolyMergeValue(polys, pj, pk, mesh.verts, maxVertsPerPoly); int[] pm = GetPolyMergeValue(polys, pj, pk, mesh.verts, maxVertsPerPoly);
int v = pm[0]; int v = pm[0];
int ea = pm[1]; int ea = pm[1];
int eb = pm[2]; int eb = pm[2];
@ -1807,7 +1807,7 @@ namespace DotRecast.Detour.TileCache
// Found best, merge. // Found best, merge.
int pa = bestPa * maxVertsPerPoly; int pa = bestPa * maxVertsPerPoly;
int pb = bestPb * maxVertsPerPoly; int pb = bestPb * maxVertsPerPoly;
mergePolys(polys, pa, pb, bestEa, bestEb, maxVertsPerPoly); MergePolys(polys, pa, pb, bestEa, bestEb, maxVertsPerPoly);
Array.Copy(polys, (npolys - 1) * maxVertsPerPoly, polys, pb, maxVertsPerPoly); Array.Copy(polys, (npolys - 1) * maxVertsPerPoly, polys, pb, maxVertsPerPoly);
npolys--; npolys--;
} }
@ -1838,12 +1838,12 @@ namespace DotRecast.Detour.TileCache
{ {
if (vflags[i] != 0) if (vflags[i] != 0)
{ {
if (!canRemoveVertex(mesh, i)) if (!CanRemoveVertex(mesh, i))
continue; continue;
removeVertex(mesh, i, maxTris); RemoveVertex(mesh, i, maxTris);
// Remove vertex // Remove vertex
// Note: mesh.nverts is already decremented inside // Note: mesh.nverts is already decremented inside
// removeVertex()! // RemoveVertex()!
for (int j = i; j < mesh.nverts; ++j) for (int j = i; j < mesh.nverts; ++j)
vflags[j] = vflags[j + 1]; vflags[j] = vflags[j + 1];
--i; --i;
@ -1851,12 +1851,12 @@ namespace DotRecast.Detour.TileCache
} }
// Calculate adjacency. // Calculate adjacency.
buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.verts, mesh.nverts, lcset, maxVertsPerPoly); BuildMeshAdjacency(mesh.polys, mesh.npolys, mesh.verts, mesh.nverts, lcset, maxVertsPerPoly);
return mesh; return mesh;
} }
public void markCylinderArea(TileCacheLayer layer, Vector3f orig, float cs, float ch, Vector3f pos, float radius, float height, int areaId) public void MarkCylinderArea(TileCacheLayer layer, Vector3f orig, float cs, float ch, Vector3f pos, float radius, float height, int areaId)
{ {
Vector3f bmin = new Vector3f(); Vector3f bmin = new Vector3f();
Vector3f bmax = new Vector3f(); Vector3f bmax = new Vector3f();
@ -1866,7 +1866,7 @@ namespace DotRecast.Detour.TileCache
bmax.x = pos.x + radius; bmax.x = pos.x + radius;
bmax.y = pos.y + height; bmax.y = pos.y + height;
bmax.z = pos.z + radius; bmax.z = pos.z + radius;
float r2 = sqr(radius / cs + 0.5f); float r2 = Sqr(radius / cs + 0.5f);
int w = layer.header.width; int w = layer.header.width;
int h = layer.header.height; int h = layer.header.height;
@ -1917,7 +1917,7 @@ namespace DotRecast.Detour.TileCache
} }
} }
public void markBoxArea(TileCacheLayer layer, Vector3f orig, float cs, float ch, Vector3f bmin, Vector3f bmax, int areaId) public void MarkBoxArea(TileCacheLayer layer, Vector3f orig, float cs, float ch, Vector3f bmin, Vector3f bmax, int areaId)
{ {
int w = layer.header.width; int w = layer.header.width;
int h = layer.header.height; int h = layer.header.height;
@ -1961,14 +1961,14 @@ namespace DotRecast.Detour.TileCache
} }
} }
public byte[] compressTileCacheLayer(TileCacheLayer layer, ByteOrder order, bool cCompatibility) public byte[] CompressTileCacheLayer(TileCacheLayer layer, ByteOrder order, bool cCompatibility)
{ {
using var ms = new MemoryStream(); using var ms = new MemoryStream();
using var baos = new BinaryWriter(ms); using var baos = new BinaryWriter(ms);
TileCacheLayerHeaderWriter hw = new TileCacheLayerHeaderWriter(); TileCacheLayerHeaderWriter hw = new TileCacheLayerHeaderWriter();
try try
{ {
hw.write(baos, layer.header, order, cCompatibility); hw.Write(baos, layer.header, order, cCompatibility);
int gridSize = layer.header.width * layer.header.height; int gridSize = layer.header.width * layer.header.height;
byte[] buffer = new byte[gridSize * 3]; byte[] buffer = new byte[gridSize * 3];
for (int i = 0; i < gridSize; i++) for (int i = 0; i < gridSize; i++)
@ -1978,7 +1978,7 @@ namespace DotRecast.Detour.TileCache
buffer[gridSize * 2 + i] = (byte)layer.cons[i]; buffer[gridSize * 2 + i] = (byte)layer.cons[i];
} }
baos.Write(TileCacheCompressorFactory.get(cCompatibility).compress(buffer)); baos.Write(TileCacheCompressorFactory.Get(cCompatibility).Compress(buffer));
return ms.ToArray(); return ms.ToArray();
} }
catch (IOException e) catch (IOException e)
@ -1987,7 +1987,7 @@ namespace DotRecast.Detour.TileCache
} }
} }
public byte[] compressTileCacheLayer(TileCacheLayerHeader header, int[] heights, int[] areas, int[] cons, public byte[] CompressTileCacheLayer(TileCacheLayerHeader header, int[] heights, int[] areas, int[] cons,
ByteOrder order, bool cCompatibility) ByteOrder order, bool cCompatibility)
{ {
using var ms = new MemoryStream(); using var ms = new MemoryStream();
@ -1995,7 +1995,7 @@ namespace DotRecast.Detour.TileCache
TileCacheLayerHeaderWriter hw = new TileCacheLayerHeaderWriter(); TileCacheLayerHeaderWriter hw = new TileCacheLayerHeaderWriter();
try try
{ {
hw.write(baos, header, order, cCompatibility); hw.Write(baos, header, order, cCompatibility);
int gridSize = header.width * header.height; int gridSize = header.width * header.height;
byte[] buffer = new byte[gridSize * 3]; byte[] buffer = new byte[gridSize * 3];
for (int i = 0; i < gridSize; i++) for (int i = 0; i < gridSize; i++)
@ -2005,7 +2005,7 @@ namespace DotRecast.Detour.TileCache
buffer[gridSize * 2 + i] = (byte)cons[i]; buffer[gridSize * 2 + i] = (byte)cons[i];
} }
baos.Write(TileCacheCompressorFactory.get(cCompatibility).compress(buffer)); baos.Write(TileCacheCompressorFactory.Get(cCompatibility).Compress(buffer));
return ms.ToArray(); return ms.ToArray();
} }
catch (IOException e) catch (IOException e)
@ -2014,15 +2014,15 @@ namespace DotRecast.Detour.TileCache
} }
} }
public TileCacheLayer decompressTileCacheLayer(TileCacheCompressor comp, byte[] compressed, ByteOrder order, public TileCacheLayer DecompressTileCacheLayer(TileCacheCompressor comp, byte[] compressed, ByteOrder order,
bool cCompatibility) bool cCompatibility)
{ {
ByteBuffer buf = new ByteBuffer(compressed); ByteBuffer buf = new ByteBuffer(compressed);
buf.order(order); buf.Order(order);
TileCacheLayer layer = new TileCacheLayer(); TileCacheLayer layer = new TileCacheLayer();
try try
{ {
layer.header = reader.read(buf, cCompatibility); layer.header = reader.Read(buf, cCompatibility);
} }
catch (IOException e) catch (IOException e)
{ {
@ -2030,7 +2030,7 @@ namespace DotRecast.Detour.TileCache
} }
int gridSize = layer.header.width * layer.header.height; int gridSize = layer.header.width * layer.header.height;
byte[] grids = comp.decompress(compressed, buf.position(), compressed.Length - buf.position(), gridSize * 3); byte[] grids = comp.Decompress(compressed, buf.Position(), compressed.Length - buf.Position(), gridSize * 3);
layer.heights = new short[gridSize]; layer.heights = new short[gridSize];
layer.areas = new short[gridSize]; layer.areas = new short[gridSize];
layer.cons = new short[gridSize]; layer.cons = new short[gridSize];
@ -2045,7 +2045,7 @@ namespace DotRecast.Detour.TileCache
return layer; return layer;
} }
public void markBoxArea(TileCacheLayer layer, Vector3f orig, float cs, float ch, Vector3f center, Vector3f extents, public void MarkBoxArea(TileCacheLayer layer, Vector3f orig, float cs, float ch, Vector3f center, Vector3f extents,
float[] rotAux, int areaId) float[] rotAux, int areaId)
{ {
int w = layer.header.width; int w = layer.header.width;

View File

@ -22,8 +22,8 @@ namespace DotRecast.Detour.TileCache
{ {
public interface TileCacheCompressor public interface TileCacheCompressor
{ {
byte[] decompress(byte[] buf, int offset, int len, int outputlen); byte[] Decompress(byte[] buf, int offset, int len, int outputlen);
byte[] compress(byte[] buf); byte[] Compress(byte[] buf);
} }
} }

View File

@ -22,6 +22,6 @@ namespace DotRecast.Detour.TileCache
{ {
public interface TileCacheMeshProcess public interface TileCacheMeshProcess
{ {
void process(NavMeshDataCreateParams option); void Process(NavMeshDataCreateParams option);
} }
} }

View File

@ -40,7 +40,7 @@ namespace DotRecast.Detour.TileCache
public float radius, height; public float radius, height;
public Vector3f center = new Vector3f(); public Vector3f center = new Vector3f();
public Vector3f extents = new Vector3f(); public Vector3f extents = new Vector3f();
public readonly float[] rotAux = new float[2]; // { cos(0.5f*angle)*sin(-0.5f*angle); cos(0.5f*angle)*cos(0.5f*angle) - 0.5 } public readonly float[] rotAux = new float[2]; // { Cos(0.5f*angle)*Sin(-0.5f*angle); Cos(0.5f*angle)*Cos(0.5f*angle) - 0.5 }
public List<long> touched = new List<long>(); public List<long> touched = new List<long>();
public readonly List<long> pending = new List<long>(); public readonly List<long> pending = new List<long>();
public int salt; public int salt;

View File

@ -44,7 +44,7 @@ namespace DotRecast.Detour
Overlap, Overlap,
} }
public static float[] intersect(float[] p, float[] q) public static float[] Intersect(float[] p, float[] q)
{ {
int n = p.Length / 3; int n = p.Length / 3;
int m = q.Length / 3; int m = q.Length / 3;
@ -68,24 +68,24 @@ namespace DotRecast.Detour
do do
{ {
vCopy(ref a, p, 3 * (ai % n)); VCopy(ref a, p, 3 * (ai % n));
vCopy(ref b, q, 3 * (bi % m)); VCopy(ref b, q, 3 * (bi % m));
vCopy(ref a1, p, 3 * ((ai + n - 1) % n)); // prev a VCopy(ref a1, p, 3 * ((ai + n - 1) % n)); // prev a
vCopy(ref b1, q, 3 * ((bi + m - 1) % m)); // prev b VCopy(ref b1, q, 3 * ((bi + m - 1) % m)); // prev b
Vector3f A = vSub(a, a1); Vector3f A = VSub(a, a1);
Vector3f B = vSub(b, b1); Vector3f B = VSub(b, b1);
float cross = B.x * A.z - A.x * B.z; // triArea2D({0, 0}, A, B); float cross = B.x * A.z - A.x * B.z; // TriArea2D({0, 0}, A, B);
float aHB = triArea2D(b1, b, a); float aHB = TriArea2D(b1, b, a);
float bHA = triArea2D(a1, a, b); float bHA = TriArea2D(a1, a, b);
if (Math.Abs(cross) < EPSILON) if (Math.Abs(cross) < EPSILON)
{ {
cross = 0f; cross = 0f;
} }
bool parallel = cross == 0f; bool parallel = cross == 0f;
Intersection code = parallel ? parallelInt(a1, a, b1, b, ref ip, ref iq) : segSegInt(a1, a, b1, b, ref ip, ref iq); Intersection code = parallel ? ParallelInt(a1, a, b1, b, ref ip, ref iq) : SegSegInt(a1, a, b1, b, ref ip, ref iq);
if (code == Intersection.Single) if (code == Intersection.Single)
{ {
@ -95,17 +95,17 @@ namespace DotRecast.Detour
aa = ba = 0; aa = ba = 0;
} }
ii = addVertex(inters, ii, ip); ii = AddVertex(inters, ii, ip);
f = inOut(f, aHB, bHA); f = InOut(f, aHB, bHA);
} }
/*-----Advance rules-----*/ /*-----Advance rules-----*/
/* Special case: A & B overlap and oppositely oriented. */ /* Special case: A & B overlap and oppositely oriented. */
if (code == Intersection.Overlap && vDot2D(A, B) < 0) if (code == Intersection.Overlap && VDot2D(A, B) < 0)
{ {
ii = addVertex(inters, ii, ip); ii = AddVertex(inters, ii, ip);
ii = addVertex(inters, ii, iq); ii = AddVertex(inters, ii, iq);
break; break;
} }
@ -136,7 +136,7 @@ namespace DotRecast.Detour
{ {
if (f == InFlag.Pin) if (f == InFlag.Pin)
{ {
ii = addVertex(inters, ii, a); ii = AddVertex(inters, ii, a);
} }
aa++; aa++;
@ -146,7 +146,7 @@ namespace DotRecast.Detour
{ {
if (f == InFlag.Qin) if (f == InFlag.Qin)
{ {
ii = addVertex(inters, ii, b); ii = AddVertex(inters, ii, b);
} }
ba++; ba++;
@ -159,7 +159,7 @@ namespace DotRecast.Detour
{ {
if (f == InFlag.Qin) if (f == InFlag.Qin)
{ {
ii = addVertex(inters, ii, b); ii = AddVertex(inters, ii, b);
} }
ba++; ba++;
@ -169,7 +169,7 @@ namespace DotRecast.Detour
{ {
if (f == InFlag.Pin) if (f == InFlag.Pin)
{ {
ii = addVertex(inters, ii, a); ii = AddVertex(inters, ii, a);
} }
aa++; aa++;
@ -190,7 +190,7 @@ namespace DotRecast.Detour
return copied; return copied;
} }
private static int addVertex(float[] inters, int ii, float[] p) private static int AddVertex(float[] inters, int ii, float[] p)
{ {
if (ii > 0) if (ii > 0)
{ {
@ -211,7 +211,7 @@ namespace DotRecast.Detour
return ii + 3; return ii + 3;
} }
private static int addVertex(float[] inters, int ii, Vector3f p) private static int AddVertex(float[] inters, int ii, Vector3f p)
{ {
if (ii > 0) if (ii > 0)
{ {
@ -233,7 +233,7 @@ namespace DotRecast.Detour
} }
private static InFlag inOut(InFlag inflag, float aHB, float bHA) private static InFlag InOut(InFlag inflag, float aHB, float bHA)
{ {
if (aHB > 0) if (aHB > 0)
{ {
@ -247,9 +247,9 @@ namespace DotRecast.Detour
return inflag; return inflag;
} }
private static Intersection segSegInt(Vector3f a, Vector3f b, Vector3f c, Vector3f d, ref Vector3f p, ref Vector3f q) private static Intersection SegSegInt(Vector3f a, Vector3f b, Vector3f c, Vector3f d, ref Vector3f p, ref Vector3f q)
{ {
var isec = intersectSegSeg2D(a, b, c, d); var isec = IntersectSegSeg2D(a, b, c, d);
if (null != isec) if (null != isec)
{ {
float s = isec.Item1; float s = isec.Item1;
@ -266,44 +266,44 @@ namespace DotRecast.Detour
return Intersection.None; return Intersection.None;
} }
private static Intersection parallelInt(Vector3f a, Vector3f b, Vector3f c, Vector3f d, ref Vector3f p, ref Vector3f q) private static Intersection ParallelInt(Vector3f a, Vector3f b, Vector3f c, Vector3f d, ref Vector3f p, ref Vector3f q)
{ {
if (between(a, b, c) && between(a, b, d)) if (Between(a, b, c) && Between(a, b, d))
{ {
p = c; p = c;
q = d; q = d;
return Intersection.Overlap; return Intersection.Overlap;
} }
if (between(c, d, a) && between(c, d, b)) if (Between(c, d, a) && Between(c, d, b))
{ {
p = a; p = a;
q = b; q = b;
return Intersection.Overlap; return Intersection.Overlap;
} }
if (between(a, b, c) && between(c, d, b)) if (Between(a, b, c) && Between(c, d, b))
{ {
p = c; p = c;
q = b; q = b;
return Intersection.Overlap; return Intersection.Overlap;
} }
if (between(a, b, c) && between(c, d, a)) if (Between(a, b, c) && Between(c, d, a))
{ {
p = c; p = c;
q = a; q = a;
return Intersection.Overlap; return Intersection.Overlap;
} }
if (between(a, b, d) && between(c, d, b)) if (Between(a, b, d) && Between(c, d, b))
{ {
p = d; p = d;
q = b; q = b;
return Intersection.Overlap; return Intersection.Overlap;
} }
if (between(a, b, d) && between(c, d, a)) if (Between(a, b, d) && Between(c, d, a))
{ {
p = d; p = d;
q = a; q = a;
@ -313,7 +313,7 @@ namespace DotRecast.Detour
return Intersection.None; return Intersection.None;
} }
private static bool between(Vector3f a, Vector3f b, Vector3f c) private static bool Between(Vector3f a, Vector3f b, Vector3f c)
{ {
if (Math.Abs(a.x - b.x) > Math.Abs(a.z - b.z)) if (Math.Abs(a.x - b.x) > Math.Abs(a.z - b.z))
{ {

View File

@ -39,7 +39,7 @@ namespace DotRecast.Detour
* *
* <b>Custom Implementations</b> * <b>Custom Implementations</b>
* *
* Implement a custom query filter by overriding the virtual passFilter() and getCost() functions. If this is done, both * Implement a custom query filter by overriding the virtual PassFilter() and GetCost() functions. If this is done, both
* functions should be as fast as possible. Use cached local copies of data rather than accessing your own objects where * functions should be as fast as possible. Use cached local copies of data rather than accessing your own objects where
* possible. * possible.
* *
@ -81,33 +81,33 @@ namespace DotRecast.Detour
} }
} }
public bool passFilter(long refs, MeshTile tile, Poly poly) public bool PassFilter(long refs, MeshTile tile, Poly poly)
{ {
return (poly.flags & m_includeFlags) != 0 && (poly.flags & m_excludeFlags) == 0; return (poly.flags & m_includeFlags) != 0 && (poly.flags & m_excludeFlags) == 0;
} }
public float getCost(Vector3f pa, Vector3f pb, long prevRef, MeshTile prevTile, Poly prevPoly, long curRef, public float GetCost(Vector3f pa, Vector3f pb, long prevRef, MeshTile prevTile, Poly prevPoly, long curRef,
MeshTile curTile, Poly curPoly, long nextRef, MeshTile nextTile, Poly nextPoly) MeshTile curTile, Poly curPoly, long nextRef, MeshTile nextTile, Poly nextPoly)
{ {
return vDist(pa, pb) * m_areaCost[curPoly.getArea()]; return VDist(pa, pb) * m_areaCost[curPoly.GetArea()];
} }
public int getIncludeFlags() public int GetIncludeFlags()
{ {
return m_includeFlags; return m_includeFlags;
} }
public void setIncludeFlags(int flags) public void SetIncludeFlags(int flags)
{ {
m_includeFlags = flags; m_includeFlags = flags;
} }
public int getExcludeFlags() public int GetExcludeFlags()
{ {
return m_excludeFlags; return m_excludeFlags;
} }
public void setExcludeFlags(int flags) public void SetExcludeFlags(int flags)
{ {
m_excludeFlags = flags; m_excludeFlags = flags;
} }

View File

@ -35,9 +35,9 @@ namespace DotRecast.Detour
this.scale = scale; this.scale = scale;
} }
public float getCost(Vector3f neighbourPos, Vector3f endPos) public float GetCost(Vector3f neighbourPos, Vector3f endPos)
{ {
return vDist(neighbourPos, endPos) * scale; return VDist(neighbourPos, endPos) * scale;
} }
} }
} }

View File

@ -22,9 +22,9 @@ namespace DotRecast.Detour
{ {
public class DetourBuilder public class DetourBuilder
{ {
public MeshData build(NavMeshDataCreateParams option, int tileX, int tileY) public MeshData Build(NavMeshDataCreateParams option, int tileX, int tileY)
{ {
MeshData data = NavMeshBuilder.createNavMeshData(option); MeshData data = NavMeshBuilder.CreateNavMeshData(option);
if (data != null) if (data != null)
{ {
data.header.x = tileX; data.header.x = tileX;

View File

@ -23,17 +23,17 @@ namespace DotRecast.Detour
nearestPt = center; nearestPt = center;
} }
public void process(MeshTile tile, Poly poly, long refs) public void Process(MeshTile tile, Poly poly, long refs)
{ {
// Find nearest polygon amongst the nearby polygons. // Find nearest polygon amongst the nearby polygons.
Result<ClosestPointOnPolyResult> closest = query.closestPointOnPoly(refs, center); Result<ClosestPointOnPolyResult> closest = query.ClosestPointOnPoly(refs, center);
bool posOverPoly = closest.result.isPosOverPoly(); bool posOverPoly = closest.result.IsPosOverPoly();
var closestPtPoly = closest.result.getClosest(); var closestPtPoly = closest.result.GetClosest();
// If a point is directly over a polygon and closer than // If a point is directly over a polygon and closer than
// climb height, favor that instead of straight line nearest point. // climb height, favor that instead of straight line nearest point.
float d = 0; float d = 0;
Vector3f diff = vSub(center, closestPtPoly); Vector3f diff = VSub(center, closestPtPoly);
if (posOverPoly) if (posOverPoly)
{ {
d = Math.Abs(diff.y) - tile.data.header.walkableClimb; d = Math.Abs(diff.y) - tile.data.header.walkableClimb;
@ -41,7 +41,7 @@ namespace DotRecast.Detour
} }
else else
{ {
d = vLenSqr(diff); d = VLenSqr(diff);
} }
if (d < nearestDistanceSqr) if (d < nearestDistanceSqr)
@ -53,7 +53,7 @@ namespace DotRecast.Detour
} }
} }
public FindNearestPolyResult result() public FindNearestPolyResult Result()
{ {
return new FindNearestPolyResult(nearestRef, nearestPt, overPoly); return new FindNearestPolyResult(nearestRef, nearestPt, overPoly);
} }

View File

@ -24,14 +24,14 @@ namespace DotRecast.Detour.Io
{ {
public abstract class DetourWriter public abstract class DetourWriter
{ {
protected void write(BinaryWriter stream, float value, ByteOrder order) protected void Write(BinaryWriter stream, float value, ByteOrder order)
{ {
byte[] bytes = BitConverter.GetBytes(value); byte[] bytes = BitConverter.GetBytes(value);
int i = BitConverter.ToInt32(bytes, 0); int i = BitConverter.ToInt32(bytes, 0);
write(stream, i, order); Write(stream, i, order);
} }
protected void write(BinaryWriter stream, short value, ByteOrder order) protected void Write(BinaryWriter stream, short value, ByteOrder order)
{ {
if (order == ByteOrder.BIG_ENDIAN) if (order == ByteOrder.BIG_ENDIAN)
{ {
@ -45,21 +45,21 @@ namespace DotRecast.Detour.Io
} }
} }
protected void write(BinaryWriter stream, long value, ByteOrder order) protected void Write(BinaryWriter stream, long value, ByteOrder order)
{ {
if (order == ByteOrder.BIG_ENDIAN) if (order == ByteOrder.BIG_ENDIAN)
{ {
write(stream, (int)((ulong)value >> 32), order); Write(stream, (int)((ulong)value >> 32), order);
write(stream, (int)(value & 0xFFFFFFFF), order); Write(stream, (int)(value & 0xFFFFFFFF), order);
} }
else else
{ {
write(stream, (int)(value & 0xFFFFFFFF), order); Write(stream, (int)(value & 0xFFFFFFFF), order);
write(stream, (int)((ulong)value >> 32), order); Write(stream, (int)((ulong)value >> 32), order);
} }
} }
protected void write(BinaryWriter stream, int value, ByteOrder order) protected void Write(BinaryWriter stream, int value, ByteOrder order)
{ {
if (order == ByteOrder.BIG_ENDIAN) if (order == ByteOrder.BIG_ENDIAN)
{ {
@ -77,17 +77,17 @@ namespace DotRecast.Detour.Io
} }
} }
protected void write(BinaryWriter stream, bool @bool) protected void Write(BinaryWriter stream, bool @bool)
{ {
write(stream, (byte)(@bool ? 1 : 0)); Write(stream, (byte)(@bool ? 1 : 0));
} }
protected void write(BinaryWriter stream, byte value) protected void Write(BinaryWriter stream, byte value)
{ {
stream.Write(value); stream.Write(value);
} }
protected void write(BinaryWriter stream, MemoryStream data) protected void Write(BinaryWriter stream, MemoryStream data)
{ {
data.Position = 0; data.Position = 0;
byte[] buffer = new byte[data.Length]; byte[] buffer = new byte[data.Length];

View File

@ -24,9 +24,9 @@ namespace DotRecast.Detour.Io
{ {
public static class IOUtils public static class IOUtils
{ {
public static ByteBuffer toByteBuffer(BinaryReader @is, bool direct) public static ByteBuffer ToByteBuffer(BinaryReader @is, bool direct)
{ {
byte[] data = toByteArray(@is); byte[] data = ToByteArray(@is);
if (direct) if (direct)
{ {
Array.Reverse(data); Array.Reverse(data);
@ -35,7 +35,7 @@ namespace DotRecast.Detour.Io
return new ByteBuffer(data); return new ByteBuffer(data);
} }
public static byte[] toByteArray(BinaryReader inputStream) public static byte[] ToByteArray(BinaryReader inputStream)
{ {
using var baos = new MemoryStream(); using var baos = new MemoryStream();
byte[] buffer = new byte[4096]; byte[] buffer = new byte[4096];
@ -49,13 +49,13 @@ namespace DotRecast.Detour.Io
} }
public static ByteBuffer toByteBuffer(BinaryReader inputStream) public static ByteBuffer ToByteBuffer(BinaryReader inputStream)
{ {
var bytes = toByteArray(inputStream); var bytes = ToByteArray(inputStream);
return new ByteBuffer(bytes); return new ByteBuffer(bytes);
} }
public static int swapEndianness(int i) public static int SwapEndianness(int i)
{ {
var s = (((uint)i >> 24) & 0xFF) | (((uint)i >> 8) & 0xFF00) | (((uint)i << 8) & 0xFF0000) | ((i << 24) & 0xFF000000); var s = (((uint)i >> 24) & 0xFF) | (((uint)i >> 8) & 0xFF00) | (((uint)i << 8) & 0xFF0000) | ((i << 24) & 0xFF000000);
return (int)s; return (int)s;

View File

@ -25,46 +25,46 @@ namespace DotRecast.Detour.Io
{ {
public const int DT_POLY_DETAIL_SIZE = 10; public const int DT_POLY_DETAIL_SIZE = 10;
public MeshData read(BinaryReader stream, int maxVertPerPoly) public MeshData Read(BinaryReader stream, int maxVertPerPoly)
{ {
ByteBuffer buf = IOUtils.toByteBuffer(stream); ByteBuffer buf = IOUtils.ToByteBuffer(stream);
return read(buf, maxVertPerPoly, false); return Read(buf, maxVertPerPoly, false);
} }
public MeshData read(ByteBuffer buf, int maxVertPerPoly) public MeshData Read(ByteBuffer buf, int maxVertPerPoly)
{ {
return read(buf, maxVertPerPoly, false); return Read(buf, maxVertPerPoly, false);
} }
public MeshData read32Bit(BinaryReader stream, int maxVertPerPoly) public MeshData Read32Bit(BinaryReader stream, int maxVertPerPoly)
{ {
ByteBuffer buf = IOUtils.toByteBuffer(stream); ByteBuffer buf = IOUtils.ToByteBuffer(stream);
return read(buf, maxVertPerPoly, true); return Read(buf, maxVertPerPoly, true);
} }
public MeshData read32Bit(ByteBuffer buf, int maxVertPerPoly) public MeshData Read32Bit(ByteBuffer buf, int maxVertPerPoly)
{ {
return read(buf, maxVertPerPoly, true); return Read(buf, maxVertPerPoly, true);
} }
public MeshData read(ByteBuffer buf, int maxVertPerPoly, bool is32Bit) public MeshData Read(ByteBuffer buf, int maxVertPerPoly, bool is32Bit)
{ {
MeshData data = new MeshData(); MeshData data = new MeshData();
MeshHeader header = new MeshHeader(); MeshHeader header = new MeshHeader();
data.header = header; data.header = header;
header.magic = buf.getInt(); header.magic = buf.GetInt();
if (header.magic != MeshHeader.DT_NAVMESH_MAGIC) if (header.magic != MeshHeader.DT_NAVMESH_MAGIC)
{ {
header.magic = IOUtils.swapEndianness(header.magic); header.magic = IOUtils.SwapEndianness(header.magic);
if (header.magic != MeshHeader.DT_NAVMESH_MAGIC) if (header.magic != MeshHeader.DT_NAVMESH_MAGIC)
{ {
throw new IOException("Invalid magic"); throw new IOException("Invalid magic");
} }
buf.order(buf.order() == ByteOrder.BIG_ENDIAN ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); buf.Order(buf.Order() == ByteOrder.BIG_ENDIAN ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
} }
header.version = buf.getInt(); header.version = buf.GetInt();
if (header.version != MeshHeader.DT_NAVMESH_VERSION) if (header.version != MeshHeader.DT_NAVMESH_VERSION)
{ {
if (header.version < MeshHeader.DT_NAVMESH_VERSION_RECAST4J_FIRST if (header.version < MeshHeader.DT_NAVMESH_VERSION_RECAST4J_FIRST
@ -75,67 +75,67 @@ namespace DotRecast.Detour.Io
} }
bool cCompatibility = header.version == MeshHeader.DT_NAVMESH_VERSION; bool cCompatibility = header.version == MeshHeader.DT_NAVMESH_VERSION;
header.x = buf.getInt(); header.x = buf.GetInt();
header.y = buf.getInt(); header.y = buf.GetInt();
header.layer = buf.getInt(); header.layer = buf.GetInt();
header.userId = buf.getInt(); header.userId = buf.GetInt();
header.polyCount = buf.getInt(); header.polyCount = buf.GetInt();
header.vertCount = buf.getInt(); header.vertCount = buf.GetInt();
header.maxLinkCount = buf.getInt(); header.maxLinkCount = buf.GetInt();
header.detailMeshCount = buf.getInt(); header.detailMeshCount = buf.GetInt();
header.detailVertCount = buf.getInt(); header.detailVertCount = buf.GetInt();
header.detailTriCount = buf.getInt(); header.detailTriCount = buf.GetInt();
header.bvNodeCount = buf.getInt(); header.bvNodeCount = buf.GetInt();
header.offMeshConCount = buf.getInt(); header.offMeshConCount = buf.GetInt();
header.offMeshBase = buf.getInt(); header.offMeshBase = buf.GetInt();
header.walkableHeight = buf.getFloat(); header.walkableHeight = buf.GetFloat();
header.walkableRadius = buf.getFloat(); header.walkableRadius = buf.GetFloat();
header.walkableClimb = buf.getFloat(); header.walkableClimb = buf.GetFloat();
header.bmin.x = buf.getFloat(); header.bmin.x = buf.GetFloat();
header.bmin.y = buf.getFloat(); header.bmin.y = buf.GetFloat();
header.bmin.z = buf.getFloat(); header.bmin.z = buf.GetFloat();
header.bmax.x = buf.getFloat(); header.bmax.x = buf.GetFloat();
header.bmax.y = buf.getFloat(); header.bmax.y = buf.GetFloat();
header.bmax.z = buf.getFloat(); header.bmax.z = buf.GetFloat();
header.bvQuantFactor = buf.getFloat(); header.bvQuantFactor = buf.GetFloat();
data.verts = readVerts(buf, header.vertCount); data.verts = ReadVerts(buf, header.vertCount);
data.polys = readPolys(buf, header, maxVertPerPoly); data.polys = ReadPolys(buf, header, maxVertPerPoly);
if (cCompatibility) if (cCompatibility)
{ {
buf.position(buf.position() + header.maxLinkCount * getSizeofLink(is32Bit)); buf.Position(buf.Position() + header.maxLinkCount * GetSizeofLink(is32Bit));
} }
data.detailMeshes = readPolyDetails(buf, header, cCompatibility); data.detailMeshes = ReadPolyDetails(buf, header, cCompatibility);
data.detailVerts = readVerts(buf, header.detailVertCount); data.detailVerts = ReadVerts(buf, header.detailVertCount);
data.detailTris = readDTris(buf, header); data.detailTris = ReadDTris(buf, header);
data.bvTree = readBVTree(buf, header); data.bvTree = ReadBVTree(buf, header);
data.offMeshCons = readOffMeshCons(buf, header); data.offMeshCons = ReadOffMeshCons(buf, header);
return data; return data;
} }
public const int LINK_SIZEOF = 16; public const int LINK_SIZEOF = 16;
public const int LINK_SIZEOF32BIT = 12; public const int LINK_SIZEOF32BIT = 12;
public static int getSizeofLink(bool is32Bit) public static int GetSizeofLink(bool is32Bit)
{ {
return is32Bit ? LINK_SIZEOF32BIT : LINK_SIZEOF; return is32Bit ? LINK_SIZEOF32BIT : LINK_SIZEOF;
} }
private float[] readVerts(ByteBuffer buf, int count) private float[] ReadVerts(ByteBuffer buf, int count)
{ {
float[] verts = new float[count * 3]; float[] verts = new float[count * 3];
for (int i = 0; i < verts.Length; i++) for (int i = 0; i < verts.Length; i++)
{ {
verts[i] = buf.getFloat(); verts[i] = buf.GetFloat();
} }
return verts; return verts;
} }
private Poly[] readPolys(ByteBuffer buf, MeshHeader header, int maxVertPerPoly) private Poly[] ReadPolys(ByteBuffer buf, MeshHeader header, int maxVertPerPoly)
{ {
Poly[] polys = new Poly[header.polyCount]; Poly[] polys = new Poly[header.polyCount];
for (int i = 0; i < polys.Length; i++) for (int i = 0; i < polys.Length; i++)
@ -143,58 +143,58 @@ namespace DotRecast.Detour.Io
polys[i] = new Poly(i, maxVertPerPoly); polys[i] = new Poly(i, maxVertPerPoly);
if (header.version < MeshHeader.DT_NAVMESH_VERSION_RECAST4J_NO_POLY_FIRSTLINK) if (header.version < MeshHeader.DT_NAVMESH_VERSION_RECAST4J_NO_POLY_FIRSTLINK)
{ {
buf.getInt(); // polys[i].firstLink buf.GetInt(); // polys[i].firstLink
} }
for (int j = 0; j < polys[i].verts.Length; j++) for (int j = 0; j < polys[i].verts.Length; j++)
{ {
polys[i].verts[j] = buf.getShort() & 0xFFFF; polys[i].verts[j] = buf.GetShort() & 0xFFFF;
} }
for (int j = 0; j < polys[i].neis.Length; j++) for (int j = 0; j < polys[i].neis.Length; j++)
{ {
polys[i].neis[j] = buf.getShort() & 0xFFFF; polys[i].neis[j] = buf.GetShort() & 0xFFFF;
} }
polys[i].flags = buf.getShort() & 0xFFFF; polys[i].flags = buf.GetShort() & 0xFFFF;
polys[i].vertCount = buf.get() & 0xFF; polys[i].vertCount = buf.Get() & 0xFF;
polys[i].areaAndtype = buf.get() & 0xFF; polys[i].areaAndtype = buf.Get() & 0xFF;
} }
return polys; return polys;
} }
private PolyDetail[] readPolyDetails(ByteBuffer buf, MeshHeader header, bool cCompatibility) private PolyDetail[] ReadPolyDetails(ByteBuffer buf, MeshHeader header, bool cCompatibility)
{ {
PolyDetail[] polys = new PolyDetail[header.detailMeshCount]; PolyDetail[] polys = new PolyDetail[header.detailMeshCount];
for (int i = 0; i < polys.Length; i++) for (int i = 0; i < polys.Length; i++)
{ {
polys[i] = new PolyDetail(); polys[i] = new PolyDetail();
polys[i].vertBase = buf.getInt(); polys[i].vertBase = buf.GetInt();
polys[i].triBase = buf.getInt(); polys[i].triBase = buf.GetInt();
polys[i].vertCount = buf.get() & 0xFF; polys[i].vertCount = buf.Get() & 0xFF;
polys[i].triCount = buf.get() & 0xFF; polys[i].triCount = buf.Get() & 0xFF;
if (cCompatibility) if (cCompatibility)
{ {
buf.getShort(); // C struct padding buf.GetShort(); // C struct padding
} }
} }
return polys; return polys;
} }
private int[] readDTris(ByteBuffer buf, MeshHeader header) private int[] ReadDTris(ByteBuffer buf, MeshHeader header)
{ {
int[] tris = new int[4 * header.detailTriCount]; int[] tris = new int[4 * header.detailTriCount];
for (int i = 0; i < tris.Length; i++) for (int i = 0; i < tris.Length; i++)
{ {
tris[i] = buf.get() & 0xFF; tris[i] = buf.Get() & 0xFF;
} }
return tris; return tris;
} }
private BVNode[] readBVTree(ByteBuffer buf, MeshHeader header) private BVNode[] ReadBVTree(ByteBuffer buf, MeshHeader header)
{ {
BVNode[] nodes = new BVNode[header.bvNodeCount]; BVNode[] nodes = new BVNode[header.bvNodeCount];
for (int i = 0; i < nodes.Length; i++) for (int i = 0; i < nodes.Length; i++)
@ -204,34 +204,34 @@ namespace DotRecast.Detour.Io
{ {
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
nodes[i].bmin[j] = buf.getShort() & 0xFFFF; nodes[i].bmin[j] = buf.GetShort() & 0xFFFF;
} }
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
nodes[i].bmax[j] = buf.getShort() & 0xFFFF; nodes[i].bmax[j] = buf.GetShort() & 0xFFFF;
} }
} }
else else
{ {
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
nodes[i].bmin[j] = buf.getInt(); nodes[i].bmin[j] = buf.GetInt();
} }
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
nodes[i].bmax[j] = buf.getInt(); nodes[i].bmax[j] = buf.GetInt();
} }
} }
nodes[i].i = buf.getInt(); nodes[i].i = buf.GetInt();
} }
return nodes; return nodes;
} }
private OffMeshConnection[] readOffMeshCons(ByteBuffer buf, MeshHeader header) private OffMeshConnection[] ReadOffMeshCons(ByteBuffer buf, MeshHeader header)
{ {
OffMeshConnection[] cons = new OffMeshConnection[header.offMeshConCount]; OffMeshConnection[] cons = new OffMeshConnection[header.offMeshConCount];
for (int i = 0; i < cons.Length; i++) for (int i = 0; i < cons.Length; i++)
@ -239,14 +239,14 @@ namespace DotRecast.Detour.Io
cons[i] = new OffMeshConnection(); cons[i] = new OffMeshConnection();
for (int j = 0; j < 6; j++) for (int j = 0; j < 6; j++)
{ {
cons[i].pos[j] = buf.getFloat(); cons[i].pos[j] = buf.GetFloat();
} }
cons[i].rad = buf.getFloat(); cons[i].rad = buf.GetFloat();
cons[i].poly = buf.getShort() & 0xFFFF; cons[i].poly = buf.GetShort() & 0xFFFF;
cons[i].flags = buf.get() & 0xFF; cons[i].flags = buf.Get() & 0xFF;
cons[i].side = buf.get() & 0xFF; cons[i].side = buf.Get() & 0xFF;
cons[i].userId = buf.getInt(); cons[i].userId = buf.GetInt();
} }
return cons; return cons;

View File

@ -23,106 +23,106 @@ namespace DotRecast.Detour.Io
{ {
public class MeshDataWriter : DetourWriter public class MeshDataWriter : DetourWriter
{ {
public void write(BinaryWriter stream, MeshData data, ByteOrder order, bool cCompatibility) public void Write(BinaryWriter stream, MeshData data, ByteOrder order, bool cCompatibility)
{ {
MeshHeader header = data.header; MeshHeader header = data.header;
write(stream, header.magic, order); Write(stream, header.magic, order);
write(stream, cCompatibility ? MeshHeader.DT_NAVMESH_VERSION : MeshHeader.DT_NAVMESH_VERSION_RECAST4J_LAST, order); Write(stream, cCompatibility ? MeshHeader.DT_NAVMESH_VERSION : MeshHeader.DT_NAVMESH_VERSION_RECAST4J_LAST, order);
write(stream, header.x, order); Write(stream, header.x, order);
write(stream, header.y, order); Write(stream, header.y, order);
write(stream, header.layer, order); Write(stream, header.layer, order);
write(stream, header.userId, order); Write(stream, header.userId, order);
write(stream, header.polyCount, order); Write(stream, header.polyCount, order);
write(stream, header.vertCount, order); Write(stream, header.vertCount, order);
write(stream, header.maxLinkCount, order); Write(stream, header.maxLinkCount, order);
write(stream, header.detailMeshCount, order); Write(stream, header.detailMeshCount, order);
write(stream, header.detailVertCount, order); Write(stream, header.detailVertCount, order);
write(stream, header.detailTriCount, order); Write(stream, header.detailTriCount, order);
write(stream, header.bvNodeCount, order); Write(stream, header.bvNodeCount, order);
write(stream, header.offMeshConCount, order); Write(stream, header.offMeshConCount, order);
write(stream, header.offMeshBase, order); Write(stream, header.offMeshBase, order);
write(stream, header.walkableHeight, order); Write(stream, header.walkableHeight, order);
write(stream, header.walkableRadius, order); Write(stream, header.walkableRadius, order);
write(stream, header.walkableClimb, order); Write(stream, header.walkableClimb, order);
write(stream, header.bmin.x, order); Write(stream, header.bmin.x, order);
write(stream, header.bmin.y, order); Write(stream, header.bmin.y, order);
write(stream, header.bmin.z, order); Write(stream, header.bmin.z, order);
write(stream, header.bmax.x, order); Write(stream, header.bmax.x, order);
write(stream, header.bmax.y, order); Write(stream, header.bmax.y, order);
write(stream, header.bmax.z, order); Write(stream, header.bmax.z, order);
write(stream, header.bvQuantFactor, order); Write(stream, header.bvQuantFactor, order);
writeVerts(stream, data.verts, header.vertCount, order); WriteVerts(stream, data.verts, header.vertCount, order);
writePolys(stream, data, order, cCompatibility); WritePolys(stream, data, order, cCompatibility);
if (cCompatibility) if (cCompatibility)
{ {
byte[] linkPlaceholder = new byte[header.maxLinkCount * MeshDataReader.getSizeofLink(false)]; byte[] linkPlaceholder = new byte[header.maxLinkCount * MeshDataReader.GetSizeofLink(false)];
stream.Write(linkPlaceholder); stream.Write(linkPlaceholder);
} }
writePolyDetails(stream, data, order, cCompatibility); WritePolyDetails(stream, data, order, cCompatibility);
writeVerts(stream, data.detailVerts, header.detailVertCount, order); WriteVerts(stream, data.detailVerts, header.detailVertCount, order);
writeDTris(stream, data); WriteDTris(stream, data);
writeBVTree(stream, data, order, cCompatibility); WriteBVTree(stream, data, order, cCompatibility);
writeOffMeshCons(stream, data, order); WriteOffMeshCons(stream, data, order);
} }
private void writeVerts(BinaryWriter stream, float[] verts, int count, ByteOrder order) private void WriteVerts(BinaryWriter stream, float[] verts, int count, ByteOrder order)
{ {
for (int i = 0; i < count * 3; i++) for (int i = 0; i < count * 3; i++)
{ {
write(stream, verts[i], order); Write(stream, verts[i], order);
} }
} }
private void writePolys(BinaryWriter stream, MeshData data, ByteOrder order, bool cCompatibility) private void WritePolys(BinaryWriter stream, MeshData data, ByteOrder order, bool cCompatibility)
{ {
for (int i = 0; i < data.header.polyCount; i++) for (int i = 0; i < data.header.polyCount; i++)
{ {
if (cCompatibility) if (cCompatibility)
{ {
write(stream, 0xFFFF, order); Write(stream, 0xFFFF, order);
} }
for (int j = 0; j < data.polys[i].verts.Length; j++) for (int j = 0; j < data.polys[i].verts.Length; j++)
{ {
write(stream, (short)data.polys[i].verts[j], order); Write(stream, (short)data.polys[i].verts[j], order);
} }
for (int j = 0; j < data.polys[i].neis.Length; j++) for (int j = 0; j < data.polys[i].neis.Length; j++)
{ {
write(stream, (short)data.polys[i].neis[j], order); Write(stream, (short)data.polys[i].neis[j], order);
} }
write(stream, (short)data.polys[i].flags, order); Write(stream, (short)data.polys[i].flags, order);
write(stream, (byte)data.polys[i].vertCount); Write(stream, (byte)data.polys[i].vertCount);
write(stream, (byte)data.polys[i].areaAndtype); Write(stream, (byte)data.polys[i].areaAndtype);
} }
} }
private void writePolyDetails(BinaryWriter stream, MeshData data, ByteOrder order, bool cCompatibility) private void WritePolyDetails(BinaryWriter stream, MeshData data, ByteOrder order, bool cCompatibility)
{ {
for (int i = 0; i < data.header.detailMeshCount; i++) for (int i = 0; i < data.header.detailMeshCount; i++)
{ {
write(stream, data.detailMeshes[i].vertBase, order); Write(stream, data.detailMeshes[i].vertBase, order);
write(stream, data.detailMeshes[i].triBase, order); Write(stream, data.detailMeshes[i].triBase, order);
write(stream, (byte)data.detailMeshes[i].vertCount); Write(stream, (byte)data.detailMeshes[i].vertCount);
write(stream, (byte)data.detailMeshes[i].triCount); Write(stream, (byte)data.detailMeshes[i].triCount);
if (cCompatibility) if (cCompatibility)
{ {
write(stream, (short)0, order); Write(stream, (short)0, order);
} }
} }
} }
private void writeDTris(BinaryWriter stream, MeshData data) private void WriteDTris(BinaryWriter stream, MeshData data)
{ {
for (int i = 0; i < data.header.detailTriCount * 4; i++) for (int i = 0; i < data.header.detailTriCount * 4; i++)
{ {
write(stream, (byte)data.detailTris[i]); Write(stream, (byte)data.detailTris[i]);
} }
} }
private void writeBVTree(BinaryWriter stream, MeshData data, ByteOrder order, bool cCompatibility) private void WriteBVTree(BinaryWriter stream, MeshData data, ByteOrder order, bool cCompatibility)
{ {
for (int i = 0; i < data.header.bvNodeCount; i++) for (int i = 0; i < data.header.bvNodeCount; i++)
{ {
@ -130,45 +130,45 @@ namespace DotRecast.Detour.Io
{ {
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
write(stream, (short)data.bvTree[i].bmin[j], order); Write(stream, (short)data.bvTree[i].bmin[j], order);
} }
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
write(stream, (short)data.bvTree[i].bmax[j], order); Write(stream, (short)data.bvTree[i].bmax[j], order);
} }
} }
else else
{ {
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
write(stream, data.bvTree[i].bmin[j], order); Write(stream, data.bvTree[i].bmin[j], order);
} }
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
write(stream, data.bvTree[i].bmax[j], order); Write(stream, data.bvTree[i].bmax[j], order);
} }
} }
write(stream, data.bvTree[i].i, order); Write(stream, data.bvTree[i].i, order);
} }
} }
private void writeOffMeshCons(BinaryWriter stream, MeshData data, ByteOrder order) private void WriteOffMeshCons(BinaryWriter stream, MeshData data, ByteOrder order)
{ {
for (int i = 0; i < data.header.offMeshConCount; i++) for (int i = 0; i < data.header.offMeshConCount; i++)
{ {
for (int j = 0; j < 6; j++) for (int j = 0; j < 6; j++)
{ {
write(stream, data.offMeshCons[i].pos[j], order); Write(stream, data.offMeshCons[i].pos[j], order);
} }
write(stream, data.offMeshCons[i].rad, order); Write(stream, data.offMeshCons[i].rad, order);
write(stream, (short)data.offMeshCons[i].poly, order); Write(stream, (short)data.offMeshCons[i].poly, order);
write(stream, (byte)data.offMeshCons[i].flags); Write(stream, (byte)data.offMeshCons[i].flags);
write(stream, (byte)data.offMeshCons[i].side); Write(stream, (byte)data.offMeshCons[i].side);
write(stream, data.offMeshCons[i].userId, order); Write(stream, data.offMeshCons[i].userId, order);
} }
} }
} }

View File

@ -30,39 +30,39 @@ namespace DotRecast.Detour.Io
private readonly MeshDataReader meshReader = new MeshDataReader(); private readonly MeshDataReader meshReader = new MeshDataReader();
private readonly NavMeshParamReader paramReader = new NavMeshParamReader(); private readonly NavMeshParamReader paramReader = new NavMeshParamReader();
public NavMesh read(BinaryReader @is, int maxVertPerPoly) public NavMesh Read(BinaryReader @is, int maxVertPerPoly)
{ {
return read(IOUtils.toByteBuffer(@is), maxVertPerPoly, false); return Read(IOUtils.ToByteBuffer(@is), maxVertPerPoly, false);
} }
public NavMesh read(ByteBuffer bb, int maxVertPerPoly) public NavMesh Read(ByteBuffer bb, int maxVertPerPoly)
{ {
return read(bb, maxVertPerPoly, false); return Read(bb, maxVertPerPoly, false);
} }
public NavMesh read32Bit(BinaryReader @is, int maxVertPerPoly) public NavMesh Read32Bit(BinaryReader @is, int maxVertPerPoly)
{ {
return read(IOUtils.toByteBuffer(@is), maxVertPerPoly, true); return Read(IOUtils.ToByteBuffer(@is), maxVertPerPoly, true);
} }
public NavMesh read32Bit(ByteBuffer bb, int maxVertPerPoly) public NavMesh Read32Bit(ByteBuffer bb, int maxVertPerPoly)
{ {
return read(bb, maxVertPerPoly, true); return Read(bb, maxVertPerPoly, true);
} }
public NavMesh read(BinaryReader @is) public NavMesh Read(BinaryReader @is)
{ {
return read(IOUtils.toByteBuffer(@is)); return Read(IOUtils.ToByteBuffer(@is));
} }
public NavMesh read(ByteBuffer bb) public NavMesh Read(ByteBuffer bb)
{ {
return read(bb, -1, false); return Read(bb, -1, false);
} }
NavMesh read(ByteBuffer bb, int maxVertPerPoly, bool is32Bit) NavMesh Read(ByteBuffer bb, int maxVertPerPoly, bool is32Bit)
{ {
NavMeshSetHeader header = readHeader(bb, maxVertPerPoly); NavMeshSetHeader header = ReadHeader(bb, maxVertPerPoly);
if (header.maxVertsPerPoly <= 0) if (header.maxVertsPerPoly <= 0)
{ {
throw new IOException("Invalid number of verts per poly " + header.maxVertsPerPoly); throw new IOException("Invalid number of verts per poly " + header.maxVertsPerPoly);
@ -70,44 +70,44 @@ namespace DotRecast.Detour.Io
bool cCompatibility = header.version == NavMeshSetHeader.NAVMESHSET_VERSION; bool cCompatibility = header.version == NavMeshSetHeader.NAVMESHSET_VERSION;
NavMesh mesh = new NavMesh(header.option, header.maxVertsPerPoly); NavMesh mesh = new NavMesh(header.option, header.maxVertsPerPoly);
readTiles(bb, is32Bit, header, cCompatibility, mesh); ReadTiles(bb, is32Bit, header, cCompatibility, mesh);
return mesh; return mesh;
} }
private NavMeshSetHeader readHeader(ByteBuffer bb, int maxVertsPerPoly) private NavMeshSetHeader ReadHeader(ByteBuffer bb, int maxVertsPerPoly)
{ {
NavMeshSetHeader header = new NavMeshSetHeader(); NavMeshSetHeader header = new NavMeshSetHeader();
header.magic = bb.getInt(); header.magic = bb.GetInt();
if (header.magic != NavMeshSetHeader.NAVMESHSET_MAGIC) if (header.magic != NavMeshSetHeader.NAVMESHSET_MAGIC)
{ {
header.magic = IOUtils.swapEndianness(header.magic); header.magic = IOUtils.SwapEndianness(header.magic);
if (header.magic != NavMeshSetHeader.NAVMESHSET_MAGIC) if (header.magic != NavMeshSetHeader.NAVMESHSET_MAGIC)
{ {
throw new IOException("Invalid magic " + header.magic); throw new IOException("Invalid magic " + header.magic);
} }
bb.order(bb.order() == ByteOrder.BIG_ENDIAN ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); bb.Order(bb.Order() == ByteOrder.BIG_ENDIAN ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
} }
header.version = bb.getInt(); header.version = bb.GetInt();
if (header.version != NavMeshSetHeader.NAVMESHSET_VERSION && header.version != NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J_1 if (header.version != NavMeshSetHeader.NAVMESHSET_VERSION && header.version != NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J_1
&& header.version != NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J) && header.version != NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J)
{ {
throw new IOException("Invalid version " + header.version); throw new IOException("Invalid version " + header.version);
} }
header.numTiles = bb.getInt(); header.numTiles = bb.GetInt();
header.option = paramReader.read(bb); header.option = paramReader.Read(bb);
header.maxVertsPerPoly = maxVertsPerPoly; header.maxVertsPerPoly = maxVertsPerPoly;
if (header.version == NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J) if (header.version == NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J)
{ {
header.maxVertsPerPoly = bb.getInt(); header.maxVertsPerPoly = bb.GetInt();
} }
return header; return header;
} }
private void readTiles(ByteBuffer bb, bool is32Bit, NavMeshSetHeader header, bool cCompatibility, NavMesh mesh) private void ReadTiles(ByteBuffer bb, bool is32Bit, NavMeshSetHeader header, bool cCompatibility, NavMesh mesh)
{ {
// Read tiles. // Read tiles.
for (int i = 0; i < header.numTiles; ++i) for (int i = 0; i < header.numTiles; ++i)
@ -115,14 +115,14 @@ namespace DotRecast.Detour.Io
NavMeshTileHeader tileHeader = new NavMeshTileHeader(); NavMeshTileHeader tileHeader = new NavMeshTileHeader();
if (is32Bit) if (is32Bit)
{ {
tileHeader.tileRef = convert32BitRef(bb.getInt(), header.option); tileHeader.tileRef = Convert32BitRef(bb.GetInt(), header.option);
} }
else else
{ {
tileHeader.tileRef = bb.getLong(); tileHeader.tileRef = bb.GetLong();
} }
tileHeader.dataSize = bb.getInt(); tileHeader.dataSize = bb.GetInt();
if (tileHeader.tileRef == 0 || tileHeader.dataSize == 0) if (tileHeader.tileRef == 0 || tileHeader.dataSize == 0)
{ {
break; break;
@ -130,18 +130,18 @@ namespace DotRecast.Detour.Io
if (cCompatibility && !is32Bit) if (cCompatibility && !is32Bit)
{ {
bb.getInt(); // C struct padding bb.GetInt(); // C struct padding
} }
MeshData data = meshReader.read(bb, mesh.getMaxVertsPerPoly(), is32Bit); MeshData data = meshReader.Read(bb, mesh.GetMaxVertsPerPoly(), is32Bit);
mesh.addTile(data, i, tileHeader.tileRef); mesh.AddTile(data, i, tileHeader.tileRef);
} }
} }
private long convert32BitRef(int refs, NavMeshParams option) private long Convert32BitRef(int refs, NavMeshParams option)
{ {
int m_tileBits = ilog2(nextPow2(option.maxTiles)); int m_tileBits = Ilog2(NextPow2(option.maxTiles));
int m_polyBits = ilog2(nextPow2(option.maxPolys)); int m_polyBits = Ilog2(NextPow2(option.maxPolys));
// Only allow 31 salt bits, since the salt mask is calculated using 32bit uint and it will overflow. // Only allow 31 salt bits, since the salt mask is calculated using 32bit uint and it will overflow.
int m_saltBits = Math.Min(31, 32 - m_tileBits - m_polyBits); int m_saltBits = Math.Min(31, 32 - m_tileBits - m_polyBits);
int saltMask = (1 << m_saltBits) - 1; int saltMask = (1 << m_saltBits) - 1;
@ -150,7 +150,7 @@ namespace DotRecast.Detour.Io
int salt = ((refs >> (m_polyBits + m_tileBits)) & saltMask); int salt = ((refs >> (m_polyBits + m_tileBits)) & saltMask);
int it = ((refs >> m_polyBits) & tileMask); int it = ((refs >> m_polyBits) & tileMask);
int ip = refs & polyMask; int ip = refs & polyMask;
return NavMesh.encodePolyId(salt, it, ip); return NavMesh.EncodePolyId(salt, it, ip);
} }
} }
} }

View File

@ -26,20 +26,20 @@ namespace DotRecast.Detour.Io
private readonly MeshDataWriter writer = new MeshDataWriter(); private readonly MeshDataWriter writer = new MeshDataWriter();
private readonly NavMeshParamWriter paramWriter = new NavMeshParamWriter(); private readonly NavMeshParamWriter paramWriter = new NavMeshParamWriter();
public void write(BinaryWriter stream, NavMesh mesh, ByteOrder order, bool cCompatibility) public void Write(BinaryWriter stream, NavMesh mesh, ByteOrder order, bool cCompatibility)
{ {
writeHeader(stream, mesh, order, cCompatibility); WriteHeader(stream, mesh, order, cCompatibility);
writeTiles(stream, mesh, order, cCompatibility); WriteTiles(stream, mesh, order, cCompatibility);
} }
private void writeHeader(BinaryWriter stream, NavMesh mesh, ByteOrder order, bool cCompatibility) private void WriteHeader(BinaryWriter stream, NavMesh mesh, ByteOrder order, bool cCompatibility)
{ {
write(stream, NavMeshSetHeader.NAVMESHSET_MAGIC, order); Write(stream, NavMeshSetHeader.NAVMESHSET_MAGIC, order);
write(stream, cCompatibility ? NavMeshSetHeader.NAVMESHSET_VERSION : NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J, order); Write(stream, cCompatibility ? NavMeshSetHeader.NAVMESHSET_VERSION : NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J, order);
int numTiles = 0; int numTiles = 0;
for (int i = 0; i < mesh.getMaxTiles(); ++i) for (int i = 0; i < mesh.GetMaxTiles(); ++i)
{ {
MeshTile tile = mesh.getTile(i); MeshTile tile = mesh.GetTile(i);
if (tile == null || tile.data == null || tile.data.header == null) if (tile == null || tile.data == null || tile.data.header == null)
{ {
continue; continue;
@ -48,39 +48,39 @@ namespace DotRecast.Detour.Io
numTiles++; numTiles++;
} }
write(stream, numTiles, order); Write(stream, numTiles, order);
paramWriter.write(stream, mesh.getParams(), order); paramWriter.Write(stream, mesh.GetParams(), order);
if (!cCompatibility) if (!cCompatibility)
{ {
write(stream, mesh.getMaxVertsPerPoly(), order); Write(stream, mesh.GetMaxVertsPerPoly(), order);
} }
} }
private void writeTiles(BinaryWriter stream, NavMesh mesh, ByteOrder order, bool cCompatibility) private void WriteTiles(BinaryWriter stream, NavMesh mesh, ByteOrder order, bool cCompatibility)
{ {
for (int i = 0; i < mesh.getMaxTiles(); ++i) for (int i = 0; i < mesh.GetMaxTiles(); ++i)
{ {
MeshTile tile = mesh.getTile(i); MeshTile tile = mesh.GetTile(i);
if (tile == null || tile.data == null || tile.data.header == null) if (tile == null || tile.data == null || tile.data.header == null)
{ {
continue; continue;
} }
NavMeshTileHeader tileHeader = new NavMeshTileHeader(); NavMeshTileHeader tileHeader = new NavMeshTileHeader();
tileHeader.tileRef = mesh.getTileRef(tile); tileHeader.tileRef = mesh.GetTileRef(tile);
using MemoryStream bb = new MemoryStream(); using MemoryStream bb = new MemoryStream();
using BinaryWriter baos = new BinaryWriter(bb); using BinaryWriter baos = new BinaryWriter(bb);
writer.write(baos, tile.data, order, cCompatibility); writer.Write(baos, tile.data, order, cCompatibility);
baos.Flush(); baos.Flush();
baos.Close(); baos.Close();
byte[] ba = bb.ToArray(); byte[] ba = bb.ToArray();
tileHeader.dataSize = ba.Length; tileHeader.dataSize = ba.Length;
write(stream, tileHeader.tileRef, order); Write(stream, tileHeader.tileRef, order);
write(stream, tileHeader.dataSize, order); Write(stream, tileHeader.dataSize, order);
if (cCompatibility) if (cCompatibility)
{ {
write(stream, 0, order); // C struct padding Write(stream, 0, order); // C struct padding
} }
stream.Write(ba); stream.Write(ba);

View File

@ -4,16 +4,16 @@ namespace DotRecast.Detour.Io
{ {
public class NavMeshParamReader public class NavMeshParamReader
{ {
public NavMeshParams read(ByteBuffer bb) public NavMeshParams Read(ByteBuffer bb)
{ {
NavMeshParams option = new NavMeshParams(); NavMeshParams option = new NavMeshParams();
option.orig.x = bb.getFloat(); option.orig.x = bb.GetFloat();
option.orig.y = bb.getFloat(); option.orig.y = bb.GetFloat();
option.orig.z = bb.getFloat(); option.orig.z = bb.GetFloat();
option.tileWidth = bb.getFloat(); option.tileWidth = bb.GetFloat();
option.tileHeight = bb.getFloat(); option.tileHeight = bb.GetFloat();
option.maxTiles = bb.getInt(); option.maxTiles = bb.GetInt();
option.maxPolys = bb.getInt(); option.maxPolys = bb.GetInt();
return option; return option;
} }
} }

View File

@ -5,15 +5,15 @@ namespace DotRecast.Detour.Io
{ {
public class NavMeshParamWriter : DetourWriter public class NavMeshParamWriter : DetourWriter
{ {
public void write(BinaryWriter stream, NavMeshParams option, ByteOrder order) public void Write(BinaryWriter stream, NavMeshParams option, ByteOrder order)
{ {
write(stream, option.orig.x, order); Write(stream, option.orig.x, order);
write(stream, option.orig.y, order); Write(stream, option.orig.y, order);
write(stream, option.orig.z, order); Write(stream, option.orig.z, order);
write(stream, option.tileWidth, order); Write(stream, option.tileWidth, order);
write(stream, option.tileHeight, order); Write(stream, option.tileHeight, order);
write(stream, option.maxTiles, order); Write(stream, option.maxTiles, order);
write(stream, option.maxPolys, order); Write(stream, option.maxPolys, order);
} }
} }
} }

View File

@ -34,16 +34,16 @@ namespace DotRecast.Detour
{ {
} }
public override Result<List<long>> findPath(long startRef, long endRef, Vector3f startPos, Vector3f endPos, QueryFilter filter, public override Result<List<long>> FindPath(long startRef, long endRef, Vector3f startPos, Vector3f endPos, QueryFilter filter,
int options, float raycastLimit) int options, float raycastLimit)
{ {
return findPath(startRef, endRef, startPos, endPos, filter); return FindPath(startRef, endRef, startPos, endPos, filter);
} }
public override Result<List<long>> findPath(long startRef, long endRef, Vector3f startPos, Vector3f endPos, QueryFilter filter) public override Result<List<long>> FindPath(long startRef, long endRef, Vector3f startPos, Vector3f endPos, QueryFilter filter)
{ {
// Validate input // Validate input
if (!m_nav.isValidPolyRef(startRef) || !m_nav.isValidPolyRef(endRef) || !vIsFinite(startPos) || !vIsFinite(endPos) || null == filter) if (!m_nav.IsValidPolyRef(startRef) || !m_nav.IsValidPolyRef(endRef) || !VIsFinite(startPos) || !VIsFinite(endPos) || null == filter)
{ {
return Results.InvalidParam<List<long>>(); return Results.InvalidParam<List<long>>();
} }
@ -55,27 +55,27 @@ namespace DotRecast.Detour
return Results.Success(singlePath); return Results.Success(singlePath);
} }
m_nodePool.clear(); m_nodePool.Clear();
m_openList.clear(); m_openList.Clear();
Node startNode = m_nodePool.getNode(startRef); Node startNode = m_nodePool.GetNode(startRef);
startNode.pos = startPos; startNode.pos = startPos;
startNode.pidx = 0; startNode.pidx = 0;
startNode.cost = 0; startNode.cost = 0;
startNode.total = vDist(startPos, endPos) * H_SCALE; startNode.total = VDist(startPos, endPos) * H_SCALE;
startNode.id = startRef; startNode.id = startRef;
startNode.flags = Node.DT_NODE_OPEN; startNode.flags = Node.DT_NODE_OPEN;
m_openList.push(startNode); m_openList.Push(startNode);
Node lastBestNode = startNode; Node lastBestNode = startNode;
float lastBestNodeCost = startNode.total; float lastBestNodeCost = startNode.total;
Status status = Status.SUCCSESS; Status status = Status.SUCCSESS;
while (!m_openList.isEmpty()) while (!m_openList.IsEmpty())
{ {
// Remove node from open list and put it in closed list. // Remove node from open list and put it in closed list.
Node bestNode = m_openList.pop(); Node bestNode = m_openList.Pop();
bestNode.flags &= ~Node.DT_NODE_OPEN; bestNode.flags &= ~Node.DT_NODE_OPEN;
bestNode.flags |= Node.DT_NODE_CLOSED; bestNode.flags |= Node.DT_NODE_CLOSED;
@ -89,7 +89,7 @@ namespace DotRecast.Detour
// Get current poly and tile. // Get current poly and tile.
// The API input has been cheked already, skip checking internal data. // The API input has been cheked already, skip checking internal data.
long bestRef = bestNode.id; long bestRef = bestNode.id;
Tuple<MeshTile, Poly> tileAndPoly = m_nav.getTileAndPolyByRefUnsafe(bestRef); Tuple<MeshTile, Poly> tileAndPoly = m_nav.GetTileAndPolyByRefUnsafe(bestRef);
MeshTile bestTile = tileAndPoly.Item1; MeshTile bestTile = tileAndPoly.Item1;
Poly bestPoly = tileAndPoly.Item2; Poly bestPoly = tileAndPoly.Item2;
@ -99,12 +99,12 @@ namespace DotRecast.Detour
Poly parentPoly = null; Poly parentPoly = null;
if (bestNode.pidx != 0) if (bestNode.pidx != 0)
{ {
parentRef = m_nodePool.getNodeAtIdx(bestNode.pidx).id; parentRef = m_nodePool.GetNodeAtIdx(bestNode.pidx).id;
} }
if (parentRef != 0) if (parentRef != 0)
{ {
tileAndPoly = m_nav.getTileAndPolyByRefUnsafe(parentRef); tileAndPoly = m_nav.GetTileAndPolyByRefUnsafe(parentRef);
parentTile = tileAndPoly.Item1; parentTile = tileAndPoly.Item1;
parentPoly = tileAndPoly.Item2; parentPoly = tileAndPoly.Item2;
} }
@ -121,11 +121,11 @@ namespace DotRecast.Detour
// Get neighbour poly and tile. // Get neighbour poly and tile.
// The API input has been cheked already, skip checking internal data. // The API input has been cheked already, skip checking internal data.
tileAndPoly = m_nav.getTileAndPolyByRefUnsafe(neighbourRef); tileAndPoly = m_nav.GetTileAndPolyByRefUnsafe(neighbourRef);
MeshTile neighbourTile = tileAndPoly.Item1; MeshTile neighbourTile = tileAndPoly.Item1;
Poly neighbourPoly = tileAndPoly.Item2; Poly neighbourPoly = tileAndPoly.Item2;
if (!filter.passFilter(neighbourRef, neighbourTile, neighbourPoly)) if (!filter.PassFilter(neighbourRef, neighbourTile, neighbourPoly))
{ {
continue; continue;
} }
@ -138,12 +138,12 @@ namespace DotRecast.Detour
} }
// get the node // get the node
Node neighbourNode = m_nodePool.getNode(neighbourRef, crossSide); Node neighbourNode = m_nodePool.GetNode(neighbourRef, crossSide);
// If the node is visited the first time, calculate node position. // If the node is visited the first time, calculate node position.
if (neighbourNode.flags == 0) if (neighbourNode.flags == 0)
{ {
var midpod = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, var midpod = GetEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
neighbourTile); neighbourTile);
if (!midpod.Failed()) if (!midpod.Failed())
{ {
@ -159,9 +159,9 @@ namespace DotRecast.Detour
if (neighbourRef == endRef) if (neighbourRef == endRef)
{ {
// Cost // Cost
float curCost = filter.getCost(bestNode.pos, neighbourNode.pos, parentRef, parentTile, parentPoly, float curCost = filter.GetCost(bestNode.pos, neighbourNode.pos, parentRef, parentTile, parentPoly,
bestRef, bestTile, bestPoly, neighbourRef, neighbourTile, neighbourPoly); bestRef, bestTile, bestPoly, neighbourRef, neighbourTile, neighbourPoly);
float endCost = filter.getCost(neighbourNode.pos, endPos, bestRef, bestTile, bestPoly, neighbourRef, float endCost = filter.GetCost(neighbourNode.pos, endPos, bestRef, bestTile, bestPoly, neighbourRef,
neighbourTile, neighbourPoly, 0L, null, null); neighbourTile, neighbourPoly, 0L, null, null);
cost = bestNode.cost + curCost + endCost; cost = bestNode.cost + curCost + endCost;
@ -170,10 +170,10 @@ namespace DotRecast.Detour
else else
{ {
// Cost // Cost
float curCost = filter.getCost(bestNode.pos, neighbourNode.pos, parentRef, parentTile, parentPoly, float curCost = filter.GetCost(bestNode.pos, neighbourNode.pos, parentRef, parentTile, parentPoly,
bestRef, bestTile, bestPoly, neighbourRef, neighbourTile, neighbourPoly); bestRef, bestTile, bestPoly, neighbourRef, neighbourTile, neighbourPoly);
cost = bestNode.cost + curCost; cost = bestNode.cost + curCost;
heuristic = vDist(neighbourNode.pos, endPos) * H_SCALE; heuristic = VDist(neighbourNode.pos, endPos) * H_SCALE;
} }
float total = cost + heuristic; float total = cost + heuristic;
@ -191,7 +191,7 @@ namespace DotRecast.Detour
} }
// Add or update the node. // Add or update the node.
neighbourNode.pidx = m_nodePool.getNodeIdx(bestNode); neighbourNode.pidx = m_nodePool.GetNodeIdx(bestNode);
neighbourNode.id = neighbourRef; neighbourNode.id = neighbourRef;
neighbourNode.flags = (neighbourNode.flags & ~Node.DT_NODE_CLOSED); neighbourNode.flags = (neighbourNode.flags & ~Node.DT_NODE_CLOSED);
neighbourNode.cost = cost; neighbourNode.cost = cost;
@ -200,13 +200,13 @@ namespace DotRecast.Detour
if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0) if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0)
{ {
// Already in open, update node location. // Already in open, update node location.
m_openList.modify(neighbourNode); m_openList.Modify(neighbourNode);
} }
else else
{ {
// Put the node in open list. // Put the node in open list.
neighbourNode.flags |= Node.DT_NODE_OPEN; neighbourNode.flags |= Node.DT_NODE_OPEN;
m_openList.push(neighbourNode); m_openList.Push(neighbourNode);
} }
// Update nearest node to target so far. // Update nearest node to target so far.
@ -218,7 +218,7 @@ namespace DotRecast.Detour
} }
} }
List<long> path = getPathToNode(lastBestNode); List<long> path = GetPathToNode(lastBestNode);
if (lastBestNode.id != endRef) if (lastBestNode.id != endRef)
{ {
@ -235,27 +235,27 @@ namespace DotRecast.Detour
* The maximum number of iterations to perform. * The maximum number of iterations to perform.
* @return The status flags for the query. * @return The status flags for the query.
*/ */
public override Result<int> updateSlicedFindPath(int maxIter) public override Result<int> UpdateSlicedFindPath(int maxIter)
{ {
if (!m_query.status.isInProgress()) if (!m_query.status.IsInProgress())
{ {
return Results.Of(m_query.status, 0); return Results.Of(m_query.status, 0);
} }
// Make sure the request is still valid. // Make sure the request is still valid.
if (!m_nav.isValidPolyRef(m_query.startRef) || !m_nav.isValidPolyRef(m_query.endRef)) if (!m_nav.IsValidPolyRef(m_query.startRef) || !m_nav.IsValidPolyRef(m_query.endRef))
{ {
m_query.status = Status.FAILURE; m_query.status = Status.FAILURE;
return Results.Of(m_query.status, 0); return Results.Of(m_query.status, 0);
} }
int iter = 0; int iter = 0;
while (iter < maxIter && !m_openList.isEmpty()) while (iter < maxIter && !m_openList.IsEmpty())
{ {
iter++; iter++;
// Remove node from open list and put it in closed list. // Remove node from open list and put it in closed list.
Node bestNode = m_openList.pop(); Node bestNode = m_openList.Pop();
bestNode.flags &= ~Node.DT_NODE_OPEN; bestNode.flags &= ~Node.DT_NODE_OPEN;
bestNode.flags |= Node.DT_NODE_CLOSED; bestNode.flags |= Node.DT_NODE_CLOSED;
@ -271,7 +271,7 @@ namespace DotRecast.Detour
// The API input has been cheked already, skip checking internal // The API input has been cheked already, skip checking internal
// data. // data.
long bestRef = bestNode.id; long bestRef = bestNode.id;
Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(bestRef); Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.GetTileAndPolyByRef(bestRef);
if (tileAndPoly.Failed()) if (tileAndPoly.Failed())
{ {
m_query.status = Status.FAILURE; m_query.status = Status.FAILURE;
@ -288,20 +288,20 @@ namespace DotRecast.Detour
Node parentNode = null; Node parentNode = null;
if (bestNode.pidx != 0) if (bestNode.pidx != 0)
{ {
parentNode = m_nodePool.getNodeAtIdx(bestNode.pidx); parentNode = m_nodePool.GetNodeAtIdx(bestNode.pidx);
parentRef = parentNode.id; parentRef = parentNode.id;
if (parentNode.pidx != 0) if (parentNode.pidx != 0)
{ {
grandpaRef = m_nodePool.getNodeAtIdx(parentNode.pidx).id; grandpaRef = m_nodePool.GetNodeAtIdx(parentNode.pidx).id;
} }
} }
if (parentRef != 0) if (parentRef != 0)
{ {
bool invalidParent = false; bool invalidParent = false;
tileAndPoly = m_nav.getTileAndPolyByRef(parentRef); tileAndPoly = m_nav.GetTileAndPolyByRef(parentRef);
invalidParent = tileAndPoly.Failed(); invalidParent = tileAndPoly.Failed();
if (invalidParent || (grandpaRef != 0 && !m_nav.isValidPolyRef(grandpaRef))) if (invalidParent || (grandpaRef != 0 && !m_nav.IsValidPolyRef(grandpaRef)))
{ {
// The polygon has disappeared during the sliced query, // The polygon has disappeared during the sliced query,
// fail. // fail.
@ -317,7 +317,7 @@ namespace DotRecast.Detour
bool tryLOS = false; bool tryLOS = false;
if ((m_query.options & DT_FINDPATH_ANY_ANGLE) != 0) if ((m_query.options & DT_FINDPATH_ANY_ANGLE) != 0)
{ {
if ((parentRef != 0) && (vDistSqr(parentNode.pos, bestNode.pos) < m_query.raycastLimitSqr)) if ((parentRef != 0) && (VDistSqr(parentNode.pos, bestNode.pos) < m_query.raycastLimitSqr))
{ {
tryLOS = true; tryLOS = true;
} }
@ -337,17 +337,17 @@ namespace DotRecast.Detour
// Get neighbour poly and tile. // Get neighbour poly and tile.
// The API input has been cheked already, skip checking internal // The API input has been cheked already, skip checking internal
// data. // data.
Tuple<MeshTile, Poly> tileAndPolyUns = m_nav.getTileAndPolyByRefUnsafe(neighbourRef); Tuple<MeshTile, Poly> tileAndPolyUns = m_nav.GetTileAndPolyByRefUnsafe(neighbourRef);
MeshTile neighbourTile = tileAndPolyUns.Item1; MeshTile neighbourTile = tileAndPolyUns.Item1;
Poly neighbourPoly = tileAndPolyUns.Item2; Poly neighbourPoly = tileAndPolyUns.Item2;
if (!m_query.filter.passFilter(neighbourRef, neighbourTile, neighbourPoly)) if (!m_query.filter.PassFilter(neighbourRef, neighbourTile, neighbourPoly))
{ {
continue; continue;
} }
// get the neighbor node // get the neighbor node
Node neighbourNode = m_nodePool.getNode(neighbourRef, 0); Node neighbourNode = m_nodePool.GetNode(neighbourRef, 0);
// do not expand to nodes that were already visited from the // do not expand to nodes that were already visited from the
// same parent // same parent
@ -360,7 +360,7 @@ namespace DotRecast.Detour
// position. // position.
if (neighbourNode.flags == 0) if (neighbourNode.flags == 0)
{ {
var midpod = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, var midpod = GetEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
neighbourTile); neighbourTile);
if (!midpod.Failed()) if (!midpod.Failed())
{ {
@ -376,7 +376,7 @@ namespace DotRecast.Detour
bool foundShortCut = false; bool foundShortCut = false;
if (tryLOS) if (tryLOS)
{ {
Result<RaycastHit> rayHit = raycast(parentRef, parentNode.pos, neighbourNode.pos, m_query.filter, Result<RaycastHit> rayHit = Raycast(parentRef, parentNode.pos, neighbourNode.pos, m_query.filter,
DT_RAYCAST_USE_COSTS, grandpaRef); DT_RAYCAST_USE_COSTS, grandpaRef);
if (rayHit.Succeeded()) if (rayHit.Succeeded())
{ {
@ -394,7 +394,7 @@ namespace DotRecast.Detour
if (!foundShortCut) if (!foundShortCut)
{ {
// No shortcut found. // No shortcut found.
float curCost = m_query.filter.getCost(bestNode.pos, neighbourNode.pos, parentRef, parentTile, float curCost = m_query.filter.GetCost(bestNode.pos, neighbourNode.pos, parentRef, parentTile,
parentPoly, bestRef, bestTile, bestPoly, neighbourRef, neighbourTile, neighbourPoly); parentPoly, bestRef, bestTile, bestPoly, neighbourRef, neighbourTile, neighbourPoly);
cost = bestNode.cost + curCost; cost = bestNode.cost + curCost;
} }
@ -402,7 +402,7 @@ namespace DotRecast.Detour
// Special case for last node. // Special case for last node.
if (neighbourRef == m_query.endRef) if (neighbourRef == m_query.endRef)
{ {
float endCost = m_query.filter.getCost(neighbourNode.pos, m_query.endPos, bestRef, bestTile, float endCost = m_query.filter.GetCost(neighbourNode.pos, m_query.endPos, bestRef, bestTile,
bestPoly, neighbourRef, neighbourTile, neighbourPoly, 0, null, null); bestPoly, neighbourRef, neighbourTile, neighbourPoly, 0, null, null);
cost = cost + endCost; cost = cost + endCost;
@ -410,7 +410,7 @@ namespace DotRecast.Detour
} }
else else
{ {
heuristic = vDist(neighbourNode.pos, m_query.endPos) * H_SCALE; heuristic = VDist(neighbourNode.pos, m_query.endPos) * H_SCALE;
} }
float total = cost + heuristic; float total = cost + heuristic;
@ -430,7 +430,7 @@ namespace DotRecast.Detour
} }
// Add or update the node. // Add or update the node.
neighbourNode.pidx = foundShortCut ? bestNode.pidx : m_nodePool.getNodeIdx(bestNode); neighbourNode.pidx = foundShortCut ? bestNode.pidx : m_nodePool.GetNodeIdx(bestNode);
neighbourNode.id = neighbourRef; neighbourNode.id = neighbourRef;
neighbourNode.flags = (neighbourNode.flags & ~(Node.DT_NODE_CLOSED | Node.DT_NODE_PARENT_DETACHED)); neighbourNode.flags = (neighbourNode.flags & ~(Node.DT_NODE_CLOSED | Node.DT_NODE_PARENT_DETACHED));
neighbourNode.cost = cost; neighbourNode.cost = cost;
@ -443,13 +443,13 @@ namespace DotRecast.Detour
if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0) if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0)
{ {
// Already in open, update node location. // Already in open, update node location.
m_openList.modify(neighbourNode); m_openList.Modify(neighbourNode);
} }
else else
{ {
// Put the node in open list. // Put the node in open list.
neighbourNode.flags |= Node.DT_NODE_OPEN; neighbourNode.flags |= Node.DT_NODE_OPEN;
m_openList.push(neighbourNode); m_openList.Push(neighbourNode);
} }
// Update nearest node to target so far. // Update nearest node to target so far.
@ -462,7 +462,7 @@ namespace DotRecast.Detour
} }
// Exhausted all nodes, but could not find path. // Exhausted all nodes, but could not find path.
if (m_openList.isEmpty()) if (m_openList.IsEmpty())
{ {
m_query.status = Status.PARTIAL_RESULT; m_query.status = Status.PARTIAL_RESULT;
} }
@ -474,10 +474,10 @@ namespace DotRecast.Detour
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.) /// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
/// [(polyRef) * @p pathCount] /// [(polyRef) * @p pathCount]
/// @returns The status flags for the query. /// @returns The status flags for the query.
public override Result<List<long>> finalizeSlicedFindPath() public override Result<List<long>> FinalizeSlicedFindPath()
{ {
List<long> path = new List<long>(64); List<long> path = new List<long>(64);
if (m_query.status.isFailed()) if (m_query.status.IsFailed())
{ {
// Reset query. // Reset query.
m_query = new QueryData(); m_query = new QueryData();
@ -502,8 +502,8 @@ namespace DotRecast.Detour
int prevRay = 0; int prevRay = 0;
do do
{ {
Node next = m_nodePool.getNodeAtIdx(node.pidx); Node next = m_nodePool.GetNodeAtIdx(node.pidx);
node.pidx = m_nodePool.getNodeIdx(prev); node.pidx = m_nodePool.GetNodeIdx(prev);
prev = node; prev = node;
int nextRay = node.flags & Node.DT_NODE_PARENT_DETACHED; // keep track of whether parent is not adjacent int nextRay = node.flags & Node.DT_NODE_PARENT_DETACHED; // keep track of whether parent is not adjacent
// (i.e. due to raycast shortcut) // (i.e. due to raycast shortcut)
@ -517,10 +517,10 @@ namespace DotRecast.Detour
node = prev; node = prev;
do do
{ {
Node next = m_nodePool.getNodeAtIdx(node.pidx); Node next = m_nodePool.GetNodeAtIdx(node.pidx);
if ((node.flags & Node.DT_NODE_PARENT_DETACHED) != 0) if ((node.flags & Node.DT_NODE_PARENT_DETACHED) != 0)
{ {
Result<RaycastHit> iresult = raycast(node.id, node.pos, next.pos, m_query.filter, 0, 0); Result<RaycastHit> iresult = Raycast(node.id, node.pos, next.pos, m_query.filter, 0, 0);
if (iresult.Succeeded()) if (iresult.Succeeded())
{ {
path.AddRange(iresult.result.path); path.AddRange(iresult.result.path);
@ -555,7 +555,7 @@ namespace DotRecast.Detour
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.) /// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
/// [(polyRef) * @p pathCount] /// [(polyRef) * @p pathCount]
/// @returns The status flags for the query. /// @returns The status flags for the query.
public override Result<List<long>> finalizeSlicedFindPathPartial(List<long> existing) public override Result<List<long>> FinalizeSlicedFindPathPartial(List<long> existing)
{ {
List<long> path = new List<long>(64); List<long> path = new List<long>(64);
if (null == existing || existing.Count <= 0) if (null == existing || existing.Count <= 0)
@ -563,7 +563,7 @@ namespace DotRecast.Detour
return Results.Failure(path); return Results.Failure(path);
} }
if (m_query.status.isFailed()) if (m_query.status.IsFailed())
{ {
// Reset query. // Reset query.
m_query = new QueryData(); m_query = new QueryData();
@ -582,7 +582,7 @@ namespace DotRecast.Detour
Node node = null; Node node = null;
for (int i = existing.Count - 1; i >= 0; --i) for (int i = existing.Count - 1; i >= 0; --i)
{ {
node = m_nodePool.findNode(existing[i]); node = m_nodePool.FindNode(existing[i]);
if (node != null) if (node != null)
{ {
break; break;
@ -599,8 +599,8 @@ namespace DotRecast.Detour
int prevRay = 0; int prevRay = 0;
do do
{ {
Node next = m_nodePool.getNodeAtIdx(node.pidx); Node next = m_nodePool.GetNodeAtIdx(node.pidx);
node.pidx = m_nodePool.getNodeIdx(prev); node.pidx = m_nodePool.GetNodeIdx(prev);
prev = node; prev = node;
int nextRay = node.flags & Node.DT_NODE_PARENT_DETACHED; // keep track of whether parent is not adjacent int nextRay = node.flags & Node.DT_NODE_PARENT_DETACHED; // keep track of whether parent is not adjacent
// (i.e. due to raycast shortcut) // (i.e. due to raycast shortcut)
@ -614,10 +614,10 @@ namespace DotRecast.Detour
node = prev; node = prev;
do do
{ {
Node next = m_nodePool.getNodeAtIdx(node.pidx); Node next = m_nodePool.GetNodeAtIdx(node.pidx);
if ((node.flags & Node.DT_NODE_PARENT_DETACHED) != 0) if ((node.flags & Node.DT_NODE_PARENT_DETACHED) != 0)
{ {
Result<RaycastHit> iresult = raycast(node.id, node.pos, next.pos, m_query.filter, 0, 0); Result<RaycastHit> iresult = Raycast(node.id, node.pos, next.pos, m_query.filter, 0, 0);
if (iresult.Succeeded()) if (iresult.Succeeded())
{ {
path.AddRange(iresult.result.path); path.AddRange(iresult.result.path);
@ -645,41 +645,41 @@ namespace DotRecast.Detour
return Results.Of(status, path); return Results.Of(status, path);
} }
public override Result<FindDistanceToWallResult> findDistanceToWall(long startRef, Vector3f centerPos, float maxRadius, QueryFilter filter) public override Result<FindDistanceToWallResult> FindDistanceToWall(long startRef, Vector3f centerPos, float maxRadius, QueryFilter filter)
{ {
// Validate input // Validate input
if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(centerPos) || maxRadius < 0 if (!m_nav.IsValidPolyRef(startRef) || !VIsFinite(centerPos) || maxRadius < 0
|| !float.IsFinite(maxRadius) || null == filter) || !float.IsFinite(maxRadius) || null == filter)
{ {
return Results.InvalidParam<FindDistanceToWallResult>(); return Results.InvalidParam<FindDistanceToWallResult>();
} }
m_nodePool.clear(); m_nodePool.Clear();
m_openList.clear(); m_openList.Clear();
Node startNode = m_nodePool.getNode(startRef); Node startNode = m_nodePool.GetNode(startRef);
startNode.pos = centerPos; startNode.pos = centerPos;
startNode.pidx = 0; startNode.pidx = 0;
startNode.cost = 0; startNode.cost = 0;
startNode.total = 0; startNode.total = 0;
startNode.id = startRef; startNode.id = startRef;
startNode.flags = Node.DT_NODE_OPEN; startNode.flags = Node.DT_NODE_OPEN;
m_openList.push(startNode); m_openList.Push(startNode);
float radiusSqr = sqr(maxRadius); float radiusSqr = Sqr(maxRadius);
Vector3f hitPos = new Vector3f(); Vector3f hitPos = new Vector3f();
VectorPtr bestvj = null; VectorPtr bestvj = null;
VectorPtr bestvi = null; VectorPtr bestvi = null;
while (!m_openList.isEmpty()) while (!m_openList.IsEmpty())
{ {
Node bestNode = m_openList.pop(); Node bestNode = m_openList.Pop();
bestNode.flags &= ~Node.DT_NODE_OPEN; bestNode.flags &= ~Node.DT_NODE_OPEN;
bestNode.flags |= Node.DT_NODE_CLOSED; bestNode.flags |= Node.DT_NODE_CLOSED;
// Get poly and tile. // Get poly and tile.
// The API input has been cheked already, skip checking internal data. // The API input has been cheked already, skip checking internal data.
long bestRef = bestNode.id; long bestRef = bestNode.id;
Tuple<MeshTile, Poly> tileAndPoly = m_nav.getTileAndPolyByRefUnsafe(bestRef); Tuple<MeshTile, Poly> tileAndPoly = m_nav.GetTileAndPolyByRefUnsafe(bestRef);
MeshTile bestTile = tileAndPoly.Item1; MeshTile bestTile = tileAndPoly.Item1;
Poly bestPoly = tileAndPoly.Item2; Poly bestPoly = tileAndPoly.Item2;
@ -687,7 +687,7 @@ namespace DotRecast.Detour
long parentRef = 0; long parentRef = 0;
if (bestNode.pidx != 0) if (bestNode.pidx != 0)
{ {
parentRef = m_nodePool.getNodeAtIdx(bestNode.pidx).id; parentRef = m_nodePool.GetNodeAtIdx(bestNode.pidx).id;
} }
// Hit test walls. // Hit test walls.
@ -705,10 +705,10 @@ namespace DotRecast.Detour
{ {
if (link.refs != 0) if (link.refs != 0)
{ {
Tuple<MeshTile, Poly> linkTileAndPoly = m_nav.getTileAndPolyByRefUnsafe(link.refs); Tuple<MeshTile, Poly> linkTileAndPoly = m_nav.GetTileAndPolyByRefUnsafe(link.refs);
MeshTile neiTile = linkTileAndPoly.Item1; MeshTile neiTile = linkTileAndPoly.Item1;
Poly neiPoly = linkTileAndPoly.Item2; Poly neiPoly = linkTileAndPoly.Item2;
if (filter.passFilter(link.refs, neiTile, neiPoly)) if (filter.PassFilter(link.refs, neiTile, neiPoly))
{ {
solid = false; solid = false;
} }
@ -727,8 +727,8 @@ namespace DotRecast.Detour
{ {
// Internal edge // Internal edge
int idx = (bestPoly.neis[j] - 1); int idx = (bestPoly.neis[j] - 1);
long refs = m_nav.getPolyRefBase(bestTile) | idx; long refs = m_nav.GetPolyRefBase(bestTile) | idx;
if (filter.passFilter(refs, bestTile, bestTile.data.polys[idx])) if (filter.PassFilter(refs, bestTile, bestTile.data.polys[idx]))
{ {
continue; continue;
} }
@ -737,7 +737,7 @@ namespace DotRecast.Detour
// Calc distance to the edge. // Calc distance to the edge.
int vj = bestPoly.verts[j] * 3; int vj = bestPoly.verts[j] * 3;
int vi = bestPoly.verts[i] * 3; int vi = bestPoly.verts[i] * 3;
Tuple<float, float> distseg = distancePtSegSqr2D(centerPos, bestTile.data.verts, vj, vi); Tuple<float, float> distseg = DistancePtSegSqr2D(centerPos, bestTile.data.verts, vj, vi);
float distSqr = distseg.Item1; float distSqr = distseg.Item1;
float tseg = distseg.Item2; float tseg = distseg.Item2;
@ -770,12 +770,12 @@ namespace DotRecast.Detour
} }
// Expand to neighbour. // Expand to neighbour.
Tuple<MeshTile, Poly> neighbourTileAndPoly = m_nav.getTileAndPolyByRefUnsafe(neighbourRef); Tuple<MeshTile, Poly> neighbourTileAndPoly = m_nav.GetTileAndPolyByRefUnsafe(neighbourRef);
MeshTile neighbourTile = neighbourTileAndPoly.Item1; MeshTile neighbourTile = neighbourTileAndPoly.Item1;
Poly neighbourPoly = neighbourTileAndPoly.Item2; Poly neighbourPoly = neighbourTileAndPoly.Item2;
// Skip off-mesh connections. // Skip off-mesh connections.
if (neighbourPoly.getType() == Poly.DT_POLYTYPE_OFFMESH_CONNECTION) if (neighbourPoly.GetType() == Poly.DT_POLYTYPE_OFFMESH_CONNECTION)
{ {
continue; continue;
} }
@ -783,7 +783,7 @@ namespace DotRecast.Detour
// Calc distance to the edge. // Calc distance to the edge.
int va = bestPoly.verts[link.edge] * 3; int va = bestPoly.verts[link.edge] * 3;
int vb = bestPoly.verts[(link.edge + 1) % bestPoly.vertCount] * 3; int vb = bestPoly.verts[(link.edge + 1) % bestPoly.vertCount] * 3;
Tuple<float, float> distseg = distancePtSegSqr2D(centerPos, bestTile.data.verts, va, vb); Tuple<float, float> distseg = DistancePtSegSqr2D(centerPos, bestTile.data.verts, va, vb);
float distSqr = distseg.Item1; float distSqr = distseg.Item1;
// If the circle is not touching the next polygon, skip it. // If the circle is not touching the next polygon, skip it.
if (distSqr > radiusSqr) if (distSqr > radiusSqr)
@ -791,12 +791,12 @@ namespace DotRecast.Detour
continue; continue;
} }
if (!filter.passFilter(neighbourRef, neighbourTile, neighbourPoly)) if (!filter.PassFilter(neighbourRef, neighbourTile, neighbourPoly))
{ {
continue; continue;
} }
Node neighbourNode = m_nodePool.getNode(neighbourRef); Node neighbourNode = m_nodePool.GetNode(neighbourRef);
if ((neighbourNode.flags & Node.DT_NODE_CLOSED) != 0) if ((neighbourNode.flags & Node.DT_NODE_CLOSED) != 0)
{ {
@ -806,7 +806,7 @@ namespace DotRecast.Detour
// Cost // Cost
if (neighbourNode.flags == 0) if (neighbourNode.flags == 0)
{ {
var midPoint = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, var midPoint = GetEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
neighbourTile); neighbourTile);
if (midPoint.Succeeded()) if (midPoint.Succeeded())
{ {
@ -814,7 +814,7 @@ namespace DotRecast.Detour
} }
} }
float total = bestNode.total + vDist(bestNode.pos, neighbourNode.pos); float total = bestNode.total + VDist(bestNode.pos, neighbourNode.pos);
// The node is already in open list and the new result is worse, skip. // The node is already in open list and the new result is worse, skip.
if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0 && total >= neighbourNode.total) if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0 && total >= neighbourNode.total)
@ -824,17 +824,17 @@ namespace DotRecast.Detour
neighbourNode.id = neighbourRef; neighbourNode.id = neighbourRef;
neighbourNode.flags = (neighbourNode.flags & ~Node.DT_NODE_CLOSED); neighbourNode.flags = (neighbourNode.flags & ~Node.DT_NODE_CLOSED);
neighbourNode.pidx = m_nodePool.getNodeIdx(bestNode); neighbourNode.pidx = m_nodePool.GetNodeIdx(bestNode);
neighbourNode.total = total; neighbourNode.total = total;
if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0) if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0)
{ {
m_openList.modify(neighbourNode); m_openList.Modify(neighbourNode);
} }
else else
{ {
neighbourNode.flags |= Node.DT_NODE_OPEN; neighbourNode.flags |= Node.DT_NODE_OPEN;
m_openList.push(neighbourNode); m_openList.Push(neighbourNode);
} }
} }
} }
@ -843,11 +843,11 @@ namespace DotRecast.Detour
Vector3f hitNormal = new Vector3f(); Vector3f hitNormal = new Vector3f();
if (bestvi != null && bestvj != null) if (bestvi != null && bestvj != null)
{ {
var tangent = vSub(bestvi, bestvj); var tangent = VSub(bestvi, bestvj);
hitNormal.x = tangent.z; hitNormal.x = tangent.z;
hitNormal.y = 0; hitNormal.y = 0;
hitNormal.z = -tangent.x; hitNormal.z = -tangent.x;
vNormalize(ref hitNormal); VNormalize(ref hitNormal);
} }
return Results.Success(new FindDistanceToWallResult((float)Math.Sqrt(radiusSqr), hitPos, hitNormal)); return Results.Success(new FindDistanceToWallResult((float)Math.Sqrt(radiusSqr), hitPos, hitNormal));

File diff suppressed because it is too large Load Diff

View File

@ -61,7 +61,7 @@ namespace DotRecast.Detour
} }
} }
private static int[][] calcExtends(BVItem[] items, int nitems, int imin, int imax) private static int[][] CalcExtends(BVItem[] items, int nitems, int imin, int imax)
{ {
int[] bmin = new int[3]; int[] bmin = new int[3];
int[] bmax = new int[3]; int[] bmax = new int[3];
@ -94,7 +94,7 @@ namespace DotRecast.Detour
return new int[][] { bmin, bmax }; return new int[][] { bmin, bmax };
} }
private static int longestAxis(int x, int y, int z) private static int LongestAxis(int x, int y, int z)
{ {
int axis = 0; int axis = 0;
int maxVal = x; int maxVal = x;
@ -113,7 +113,7 @@ namespace DotRecast.Detour
return axis; return axis;
} }
public static int subdivide(BVItem[] items, int nitems, int imin, int imax, int curNode, BVNode[] nodes) public static int Subdivide(BVItem[] items, int nitems, int imin, int imax, int curNode, BVNode[] nodes)
{ {
int inum = imax - imin; int inum = imax - imin;
int icur = curNode; int icur = curNode;
@ -137,11 +137,11 @@ namespace DotRecast.Detour
else else
{ {
// Split // Split
int[][] minmax = calcExtends(items, nitems, imin, imax); int[][] minmax = CalcExtends(items, nitems, imin, imax);
node.bmin = minmax[0]; node.bmin = minmax[0];
node.bmax = minmax[1]; node.bmax = minmax[1];
int axis = longestAxis(node.bmax[0] - node.bmin[0], node.bmax[1] - node.bmin[1], int axis = LongestAxis(node.bmax[0] - node.bmin[0], node.bmax[1] - node.bmin[1],
node.bmax[2] - node.bmin[2]); node.bmax[2] - node.bmin[2]);
if (axis == 0) if (axis == 0)
@ -163,9 +163,9 @@ namespace DotRecast.Detour
int isplit = imin + inum / 2; int isplit = imin + inum / 2;
// Left // Left
curNode = subdivide(items, nitems, imin, isplit, curNode, nodes); curNode = Subdivide(items, nitems, imin, isplit, curNode, nodes);
// Right // Right
curNode = subdivide(items, nitems, isplit, imax, curNode, nodes); curNode = Subdivide(items, nitems, isplit, imax, curNode, nodes);
int iescape = curNode - icur; int iescape = curNode - icur;
// Negative index means escape. // Negative index means escape.
@ -175,7 +175,7 @@ namespace DotRecast.Detour
return curNode; return curNode;
} }
private static int createBVTree(NavMeshDataCreateParams option, BVNode[] nodes) private static int CreateBVTree(NavMeshDataCreateParams option, BVNode[] nodes)
{ {
// Build tree // Build tree
float quantFactor = 1 / option.cs; float quantFactor = 1 / option.cs;
@ -193,22 +193,22 @@ namespace DotRecast.Detour
Vector3f bmin = new Vector3f(); Vector3f bmin = new Vector3f();
Vector3f bmax = new Vector3f(); Vector3f bmax = new Vector3f();
int dv = vb * 3; int dv = vb * 3;
vCopy(ref bmin, option.detailVerts, dv); VCopy(ref bmin, option.detailVerts, dv);
vCopy(ref bmax, option.detailVerts, dv); VCopy(ref bmax, option.detailVerts, dv);
for (int j = 1; j < ndv; j++) for (int j = 1; j < ndv; j++)
{ {
vMin(ref bmin, option.detailVerts, dv + j * 3); VMin(ref bmin, option.detailVerts, dv + j * 3);
vMax(ref bmax, option.detailVerts, dv + j * 3); VMax(ref bmax, option.detailVerts, dv + j * 3);
} }
// BV-tree uses cs for all dimensions // BV-tree uses cs for all dimensions
it.bmin[0] = clamp((int)((bmin.x - option.bmin.x) * quantFactor), 0, int.MaxValue); it.bmin[0] = Clamp((int)((bmin.x - option.bmin.x) * quantFactor), 0, int.MaxValue);
it.bmin[1] = clamp((int)((bmin.y - option.bmin.y) * quantFactor), 0, int.MaxValue); it.bmin[1] = Clamp((int)((bmin.y - option.bmin.y) * quantFactor), 0, int.MaxValue);
it.bmin[2] = clamp((int)((bmin.z - option.bmin.z) * quantFactor), 0, int.MaxValue); it.bmin[2] = Clamp((int)((bmin.z - option.bmin.z) * quantFactor), 0, int.MaxValue);
it.bmax[0] = clamp((int)((bmax.x - option.bmin.x) * quantFactor), 0, int.MaxValue); it.bmax[0] = Clamp((int)((bmax.x - option.bmin.x) * quantFactor), 0, int.MaxValue);
it.bmax[1] = clamp((int)((bmax.y - option.bmin.y) * quantFactor), 0, int.MaxValue); it.bmax[1] = Clamp((int)((bmax.y - option.bmin.y) * quantFactor), 0, int.MaxValue);
it.bmax[2] = clamp((int)((bmax.z - option.bmin.z) * quantFactor), 0, int.MaxValue); it.bmax[2] = Clamp((int)((bmax.z - option.bmin.z) * quantFactor), 0, int.MaxValue);
} }
else else
{ {
@ -246,7 +246,7 @@ namespace DotRecast.Detour
} }
} }
return subdivide(items, option.polyCount, 0, option.polyCount, 0, nodes); return Subdivide(items, option.polyCount, 0, option.polyCount, 0, nodes);
} }
const int XP = 1 << 0; const int XP = 1 << 0;
@ -254,13 +254,13 @@ namespace DotRecast.Detour
const int XM = 1 << 2; const int XM = 1 << 2;
const int ZM = 1 << 3; const int ZM = 1 << 3;
public static int classifyOffMeshPoint(VectorPtr pt, Vector3f bmin, Vector3f bmax) public static int ClassifyOffMeshPoint(VectorPtr pt, Vector3f bmin, Vector3f bmax)
{ {
int outcode = 0; int outcode = 0;
outcode |= (pt.get(0) >= bmax.x) ? XP : 0; outcode |= (pt.Get(0) >= bmax.x) ? XP : 0;
outcode |= (pt.get(2) >= bmax.z) ? ZP : 0; outcode |= (pt.Get(2) >= bmax.z) ? ZP : 0;
outcode |= (pt.get(0) < bmin.x) ? XM : 0; outcode |= (pt.Get(0) < bmin.x) ? XM : 0;
outcode |= (pt.get(2) < bmin.z) ? ZM : 0; outcode |= (pt.Get(2) < bmin.z) ? ZM : 0;
switch (outcode) switch (outcode)
{ {
@ -293,7 +293,7 @@ namespace DotRecast.Detour
* *
* @return created tile data * @return created tile data
*/ */
public static MeshData createNavMeshData(NavMeshDataCreateParams option) public static MeshData CreateNavMeshData(NavMeshDataCreateParams option)
{ {
if (option.vertCount >= 0xffff) if (option.vertCount >= 0xffff)
return null; return null;
@ -353,14 +353,14 @@ namespace DotRecast.Detour
VectorPtr p0 = new VectorPtr(option.offMeshConVerts, (i * 2 + 0) * 3); VectorPtr p0 = new VectorPtr(option.offMeshConVerts, (i * 2 + 0) * 3);
VectorPtr p1 = new VectorPtr(option.offMeshConVerts, (i * 2 + 1) * 3); VectorPtr p1 = new VectorPtr(option.offMeshConVerts, (i * 2 + 1) * 3);
offMeshConClass[i * 2 + 0] = classifyOffMeshPoint(p0, bmin, bmax); offMeshConClass[i * 2 + 0] = ClassifyOffMeshPoint(p0, bmin, bmax);
offMeshConClass[i * 2 + 1] = classifyOffMeshPoint(p1, bmin, bmax); offMeshConClass[i * 2 + 1] = ClassifyOffMeshPoint(p1, bmin, bmax);
// Zero out off-mesh start positions which are not even // Zero out off-mesh start positions which are not even
// potentially touching the mesh. // potentially touching the mesh.
if (offMeshConClass[i * 2 + 0] == 0xff) if (offMeshConClass[i * 2 + 0] == 0xff)
{ {
if (p0.get(1) < bmin.y || p0.get(1) > bmax.y) if (p0.Get(1) < bmin.y || p0.Get(1) > bmax.y)
offMeshConClass[i * 2 + 0] = 0; offMeshConClass[i * 2 + 0] = 0;
} }
@ -517,8 +517,8 @@ namespace DotRecast.Detour
navPolys[i] = p; navPolys[i] = p;
p.vertCount = 0; p.vertCount = 0;
p.flags = option.polyFlags[i]; p.flags = option.polyFlags[i];
p.setArea(option.polyAreas[i]); p.SetArea(option.polyAreas[i]);
p.setType(Poly.DT_POLYTYPE_GROUND); p.SetType(Poly.DT_POLYTYPE_GROUND);
for (int j = 0; j < nvp; ++j) for (int j = 0; j < nvp; ++j)
{ {
if (option.polys[src + j] == MESH_NULL_IDX) if (option.polys[src + j] == MESH_NULL_IDX)
@ -564,8 +564,8 @@ namespace DotRecast.Detour
p.verts[0] = offMeshVertsBase + n * 2; p.verts[0] = offMeshVertsBase + n * 2;
p.verts[1] = offMeshVertsBase + n * 2 + 1; p.verts[1] = offMeshVertsBase + n * 2 + 1;
p.flags = option.offMeshConFlags[i]; p.flags = option.offMeshConFlags[i];
p.setArea(option.offMeshConAreas[i]); p.SetArea(option.offMeshConAreas[i]);
p.setType(Poly.DT_POLYTYPE_OFFMESH_CONNECTION); p.SetType(Poly.DT_POLYTYPE_OFFMESH_CONNECTION);
n++; n++;
} }
} }
@ -637,7 +637,7 @@ namespace DotRecast.Detour
if (option.buildBvTree) if (option.buildBvTree)
{ {
// Do not set header.bvNodeCount set to make it work look exactly the same as in original Detour // Do not set header.bvNodeCount set to make it work look exactly the same as in original Detour
header.bvNodeCount = createBVTree(option, navBvtree); header.bvNodeCount = CreateBVTree(option, navBvtree);
} }
// Store Off-Mesh connections. // Store Off-Mesh connections.

File diff suppressed because it is too large Load Diff

View File

@ -26,14 +26,14 @@ namespace DotRecast.Detour
*/ */
public static class NavMeshRaycast public static class NavMeshRaycast
{ {
public static float? raycast(NavMesh mesh, Vector3f src, Vector3f dst) public static float? Raycast(NavMesh mesh, Vector3f src, Vector3f dst)
{ {
for (int t = 0; t < mesh.getMaxTiles(); ++t) for (int t = 0; t < mesh.GetMaxTiles(); ++t)
{ {
MeshTile tile = mesh.getTile(t); MeshTile tile = mesh.GetTile(t);
if (tile != null && tile.data != null) if (tile != null && tile.data != null)
{ {
float? intersection = raycast(tile, src, dst); float? intersection = Raycast(tile, src, dst);
if (null != intersection) if (null != intersection)
{ {
return intersection; return intersection;
@ -44,12 +44,12 @@ namespace DotRecast.Detour
return null; return null;
} }
private static float? raycast(MeshTile tile, Vector3f sp, Vector3f sq) private static float? Raycast(MeshTile tile, Vector3f sp, Vector3f sq)
{ {
for (int i = 0; i < tile.data.header.polyCount; ++i) for (int i = 0; i < tile.data.header.polyCount; ++i)
{ {
Poly p = tile.data.polys[i]; Poly p = tile.data.polys[i];
if (p.getType() == Poly.DT_POLYTYPE_OFFMESH_CONNECTION) if (p.GetType() == Poly.DT_POLYTYPE_OFFMESH_CONNECTION)
{ {
continue; continue;
} }
@ -79,7 +79,7 @@ namespace DotRecast.Detour
} }
} }
float? intersection = Intersections.intersectSegmentTriangle(sp, sq, verts[0], verts[1], verts[2]); float? intersection = Intersections.IntersectSegmentTriangle(sp, sq, verts[0], verts[1], verts[2]);
if (null != intersection) if (null != intersection)
{ {
return intersection; return intersection;

View File

@ -24,13 +24,13 @@ namespace DotRecast.Detour
{ {
public static class NavMeshUtils public static class NavMeshUtils
{ {
public static Vector3f[] getNavMeshBounds(NavMesh mesh) public static Vector3f[] GetNavMeshBounds(NavMesh mesh)
{ {
Vector3f bmin = Vector3f.Of(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); Vector3f bmin = Vector3f.Of(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
Vector3f bmax = Vector3f.Of(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); Vector3f bmax = Vector3f.Of(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
for (int t = 0; t < mesh.getMaxTiles(); ++t) for (int t = 0; t < mesh.GetMaxTiles(); ++t)
{ {
MeshTile tile = mesh.getTile(t); MeshTile tile = mesh.GetTile(t);
if (tile != null && tile.data != null) if (tile != null && tile.data != null)
{ {
for (int i = 0; i < tile.data.verts.Length; i += 3) for (int i = 0; i < tile.data.verts.Length; i += 3)

View File

@ -31,13 +31,13 @@ namespace DotRecast.Detour
{ {
} }
public void clear() public void Clear()
{ {
m_nodes.Clear(); m_nodes.Clear();
m_map.Clear(); m_map.Clear();
} }
public List<Node> findNodes(long id) public List<Node> FindNodes(long id)
{ {
var hasNode = m_map.TryGetValue(id, out var nodes); var hasNode = m_map.TryGetValue(id, out var nodes);
; ;
@ -49,7 +49,7 @@ namespace DotRecast.Detour
return nodes; return nodes;
} }
public Node findNode(long id) public Node FindNode(long id)
{ {
var hasNode = m_map.TryGetValue(id, out var nodes); var hasNode = m_map.TryGetValue(id, out var nodes);
; ;
@ -61,7 +61,7 @@ namespace DotRecast.Detour
return null; return null;
} }
public Node getNode(long id, int state) public Node GetNode(long id, int state)
{ {
var hasNode = m_map.TryGetValue(id, out var nodes); var hasNode = m_map.TryGetValue(id, out var nodes);
; ;
@ -76,10 +76,10 @@ namespace DotRecast.Detour
} }
} }
return create(id, state); return Create(id, state);
} }
protected Node create(long id, int state) protected Node Create(long id, int state)
{ {
Node node = new Node(m_nodes.Count + 1); Node node = new Node(m_nodes.Count + 1);
node.id = id; node.id = id;
@ -97,22 +97,22 @@ namespace DotRecast.Detour
return node; return node;
} }
public int getNodeIdx(Node node) public int GetNodeIdx(Node node)
{ {
return node != null ? node.index : 0; return node != null ? node.index : 0;
} }
public Node getNodeAtIdx(int idx) public Node GetNodeAtIdx(int idx)
{ {
return idx != 0 ? m_nodes[idx - 1] : null; return idx != 0 ? m_nodes[idx - 1] : null;
} }
public Node getNode(long refs) public Node GetNode(long refs)
{ {
return getNode(refs, 0); return GetNode(refs, 0);
} }
public Dictionary<long, List<Node>> getNodeMap() public Dictionary<long, List<Node>> GetNodeMap()
{ {
return m_map; return m_map;
} }

View File

@ -28,40 +28,40 @@ namespace DotRecast.Detour
{ {
private readonly SortedQueue<Node> m_heap = new SortedQueue<Node>((n1, n2) => n1.total.CompareTo(n2.total)); private readonly SortedQueue<Node> m_heap = new SortedQueue<Node>((n1, n2) => n1.total.CompareTo(n2.total));
public int count() public int Count()
{ {
return m_heap.Count(); return m_heap.Count();
} }
public void clear() public void Clear()
{ {
m_heap.Clear(); m_heap.Clear();
} }
public Node top() public Node Top()
{ {
return m_heap.Top(); return m_heap.Top();
} }
public Node pop() public Node Pop()
{ {
var node = top(); var node = Top();
m_heap.Remove(node); m_heap.Remove(node);
return node; return node;
} }
public void push(Node node) public void Push(Node node)
{ {
m_heap.Enqueue(node); m_heap.Enqueue(node);
} }
public void modify(Node node) public void Modify(Node node)
{ {
m_heap.Remove(node); m_heap.Remove(node);
push(node); Push(node);
} }
public bool isEmpty() public bool IsEmpty()
{ {
return 0 == m_heap.Count(); return 0 == m_heap.Count();
} }

View File

@ -30,11 +30,11 @@ namespace DotRecast.Detour
private const int MAX_STEER_POINTS = 3; private const int MAX_STEER_POINTS = 3;
public static SteerTarget getSteerTarget(NavMeshQuery navQuery, Vector3f startPos, Vector3f endPos, public static SteerTarget GetSteerTarget(NavMeshQuery navQuery, Vector3f startPos, Vector3f endPos,
float minTargetDist, List<long> path) float minTargetDist, List<long> path)
{ {
// Find steer target. // Find steer target.
Result<List<StraightPathItem>> result = navQuery.findStraightPath(startPos, endPos, path, MAX_STEER_POINTS, 0); Result<List<StraightPathItem>> result = navQuery.FindStraightPath(startPos, endPos, path, MAX_STEER_POINTS, 0);
if (result.Failed()) if (result.Failed())
{ {
return null; return null;
@ -44,9 +44,9 @@ namespace DotRecast.Detour
float[] steerPoints = new float[straightPath.Count * 3]; float[] steerPoints = new float[straightPath.Count * 3];
for (int i = 0; i < straightPath.Count; i++) for (int i = 0; i < straightPath.Count; i++)
{ {
steerPoints[i * 3] = straightPath[i].getPos().x; steerPoints[i * 3] = straightPath[i].GetPos().x;
steerPoints[i * 3 + 1] = straightPath[i].getPos().y; steerPoints[i * 3 + 1] = straightPath[i].GetPos().y;
steerPoints[i * 3 + 2] = straightPath[i].getPos().z; steerPoints[i * 3 + 2] = straightPath[i].GetPos().z;
} }
// Find vertex far enough to steer to. // Find vertex far enough to steer to.
@ -54,8 +54,8 @@ namespace DotRecast.Detour
while (ns < straightPath.Count) while (ns < straightPath.Count)
{ {
// Stop at Off-Mesh link or when point is further than slop away. // Stop at Off-Mesh link or when point is further than slop away.
if (((straightPath[ns].getFlags() & NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0) if (((straightPath[ns].GetFlags() & NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|| !inRange(straightPath[ns].getPos(), startPos, minTargetDist, 1000.0f)) || !InRange(straightPath[ns].GetPos(), startPos, minTargetDist, 1000.0f))
break; break;
ns++; ns++;
} }
@ -65,18 +65,18 @@ namespace DotRecast.Detour
return null; return null;
Vector3f steerPos = Vector3f.Of( Vector3f steerPos = Vector3f.Of(
straightPath[ns].getPos().x, straightPath[ns].GetPos().x,
startPos.y, startPos.y,
straightPath[ns].getPos().z straightPath[ns].GetPos().z
); );
int steerPosFlag = straightPath[ns].getFlags(); int steerPosFlag = straightPath[ns].GetFlags();
long steerPosRef = straightPath[ns].getRef(); long steerPosRef = straightPath[ns].GetRef();
SteerTarget target = new SteerTarget(steerPos, steerPosFlag, steerPosRef, steerPoints); SteerTarget target = new SteerTarget(steerPos, steerPosFlag, steerPosRef, steerPoints);
return target; return target;
} }
public static bool inRange(Vector3f v1, Vector3f v2, float r, float h) public static bool InRange(Vector3f v1, Vector3f v2, float r, float h)
{ {
float dx = v2.x - v1.x; float dx = v2.x - v1.x;
float dy = v2.y - v1.y; float dy = v2.y - v1.y;
@ -84,7 +84,7 @@ namespace DotRecast.Detour
return (dx * dx + dz * dz) < r * r && Math.Abs(dy) < h; return (dx * dx + dz * dz) < r * r && Math.Abs(dy) < h;
} }
public static List<long> fixupCorridor(List<long> path, List<long> visited) public static List<long> FixupCorridor(List<long> path, List<long> visited)
{ {
int furthestPath = -1; int furthestPath = -1;
int furthestVisited = -1; int furthestVisited = -1;
@ -143,7 +143,7 @@ namespace DotRecast.Detour
// +-S-+-T-+ // +-S-+-T-+
// |:::| | <-- the step can end up in here, resulting U-turn path. // |:::| | <-- the step can end up in here, resulting U-turn path.
// +---+---+ // +---+---+
public static List<long> fixupShortcuts(List<long> path, NavMeshQuery navQuery) public static List<long> FixupShortcuts(List<long> path, NavMeshQuery navQuery)
{ {
if (path.Count < 3) if (path.Count < 3)
{ {
@ -153,7 +153,7 @@ namespace DotRecast.Detour
// Get connected polygons // Get connected polygons
List<long> neis = new List<long>(); List<long> neis = new List<long>();
Result<Tuple<MeshTile, Poly>> tileAndPoly = navQuery.getAttachedNavMesh().getTileAndPolyByRef(path[0]); Result<Tuple<MeshTile, Poly>> tileAndPoly = navQuery.GetAttachedNavMesh().GetTileAndPolyByRef(path[0]);
if (tileAndPoly.Failed()) if (tileAndPoly.Failed())
{ {
return path; return path;

View File

@ -58,25 +58,25 @@ namespace DotRecast.Detour
} }
/** Sets the user defined area id. [Limit: &lt; {@link org.recast4j.detour.NavMesh#DT_MAX_AREAS}] */ /** Sets the user defined area id. [Limit: &lt; {@link org.recast4j.detour.NavMesh#DT_MAX_AREAS}] */
public void setArea(int a) public void SetArea(int a)
{ {
areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f); areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f);
} }
/** Sets the polygon type. (See: #dtPolyTypes.) */ /** Sets the polygon type. (See: #dtPolyTypes.) */
public void setType(int t) public void SetType(int t)
{ {
areaAndtype = (areaAndtype & 0x3f) | (t << 6); areaAndtype = (areaAndtype & 0x3f) | (t << 6);
} }
/** Gets the user defined area id. */ /** Gets the user defined area id. */
public int getArea() public int GetArea()
{ {
return areaAndtype & 0x3f; return areaAndtype & 0x3f;
} }
/** Gets the polygon type. (See: #dtPolyTypes) */ /** Gets the polygon type. (See: #dtPolyTypes) */
public int getType() public int GetType()
{ {
return areaAndtype >> 6; return areaAndtype >> 6;
} }

View File

@ -2,6 +2,6 @@ namespace DotRecast.Detour
{ {
public interface PolyQuery public interface PolyQuery
{ {
void process(MeshTile tile, Poly poly, long refs); void Process(MeshTile tile, Poly poly, long refs);
} }
} }

View File

@ -25,21 +25,21 @@ namespace DotRecast.Detour
public interface PolygonByCircleConstraint public interface PolygonByCircleConstraint
{ {
float[] aply(float[] polyVerts, Vector3f circleCenter, float radius); float[] Aply(float[] polyVerts, Vector3f circleCenter, float radius);
public static PolygonByCircleConstraint noop() public static PolygonByCircleConstraint Noop()
{ {
return new NoOpPolygonByCircleConstraint(); return new NoOpPolygonByCircleConstraint();
} }
public static PolygonByCircleConstraint strict() public static PolygonByCircleConstraint Strict()
{ {
return new StrictPolygonByCircleConstraint(); return new StrictPolygonByCircleConstraint();
} }
public class NoOpPolygonByCircleConstraint : PolygonByCircleConstraint public class NoOpPolygonByCircleConstraint : PolygonByCircleConstraint
{ {
public float[] aply(float[] polyVerts, Vector3f circleCenter, float radius) public float[] Aply(float[] polyVerts, Vector3f circleCenter, float radius)
{ {
return polyVerts; return polyVerts;
} }
@ -53,13 +53,13 @@ namespace DotRecast.Detour
private const int CIRCLE_SEGMENTS = 12; private const int CIRCLE_SEGMENTS = 12;
private static float[] unitCircle; private static float[] unitCircle;
public float[] aply(float[] verts, Vector3f center, float radius) public float[] Aply(float[] verts, Vector3f center, float radius)
{ {
float radiusSqr = radius * radius; float radiusSqr = radius * radius;
int outsideVertex = -1; int outsideVertex = -1;
for (int pv = 0; pv < verts.Length; pv += 3) for (int pv = 0; pv < verts.Length; pv += 3)
{ {
if (vDist2DSqr(center, verts, pv) > radiusSqr) if (VDist2DSqr(center, verts, pv) > radiusSqr)
{ {
outsideVertex = pv; outsideVertex = pv;
break; break;
@ -72,9 +72,9 @@ namespace DotRecast.Detour
return verts; return verts;
} }
float[] qCircle = circle(center, radius); float[] qCircle = Circle(center, radius);
float[] intersection = ConvexConvexIntersection.intersect(verts, qCircle); float[] intersection = ConvexConvexIntersection.Intersect(verts, qCircle);
if (intersection == null && pointInPolygon(center, verts, verts.Length / 3)) if (intersection == null && PointInPolygon(center, verts, verts.Length / 3))
{ {
// circle inside polygon // circle inside polygon
return qCircle; return qCircle;
@ -83,7 +83,7 @@ namespace DotRecast.Detour
return intersection; return intersection;
} }
private float[] circle(Vector3f center, float radius) private float[] Circle(Vector3f center, float radius)
{ {
if (unitCircle == null) if (unitCircle == null)
{ {

View File

@ -24,9 +24,9 @@ namespace DotRecast.Detour
{ {
public interface QueryFilter public interface QueryFilter
{ {
bool passFilter(long refs, MeshTile tile, Poly poly); bool PassFilter(long refs, MeshTile tile, Poly poly);
float getCost(Vector3f pa, Vector3f pb, long prevRef, MeshTile prevTile, Poly prevPoly, long curRef, MeshTile curTile, float GetCost(Vector3f pa, Vector3f pb, long prevRef, MeshTile prevTile, Poly prevPoly, long curRef, MeshTile curTile,
Poly curPoly, long nextRef, MeshTile nextTile, Poly nextPoly); Poly curPoly, long nextRef, MeshTile nextTile, Poly nextPoly);
} }
} }

View File

@ -22,6 +22,6 @@ namespace DotRecast.Detour
{ {
public interface QueryHeuristic public interface QueryHeuristic
{ {
float getCost(Vector3f neighbourPos, Vector3f endPos); float GetCost(Vector3f neighbourPos, Vector3f endPos);
} }
} }

View File

@ -34,13 +34,13 @@ namespace DotRecast.Detour.QueryResults
} }
/** Returns true if the position is over the polygon. */ /** Returns true if the position is over the polygon. */
public bool isPosOverPoly() public bool IsPosOverPoly()
{ {
return posOverPoly; return posOverPoly;
} }
/** Returns the closest point on the polygon. [(x, y, z)] */ /** Returns the closest point on the polygon. [(x, y, z)] */
public Vector3f getClosest() public Vector3f GetClosest()
{ {
return closest; return closest;
} }

View File

@ -36,17 +36,17 @@ namespace DotRecast.Detour.QueryResults
this.normal = normal; this.normal = normal;
} }
public float getDistance() public float GetDistance()
{ {
return distance; return distance;
} }
public Vector3f getPosition() public Vector3f GetPosition()
{ {
return position; return position;
} }
public Vector3f getNormal() public Vector3f GetNormal()
{ {
return normal; return normal;
} }

View File

@ -34,12 +34,12 @@ namespace DotRecast.Detour.QueryResults
this.parentRefs = parentRefs; this.parentRefs = parentRefs;
} }
public List<long> getRefs() public List<long> GetRefs()
{ {
return refs; return refs;
} }
public List<long> getParentRefs() public List<long> GetParentRefs()
{ {
return parentRefs; return parentRefs;
} }

View File

@ -36,18 +36,18 @@ namespace DotRecast.Detour.QueryResults
} }
/** Returns the reference id of the nearest polygon. 0 if no polygon is found. */ /** Returns the reference id of the nearest polygon. 0 if no polygon is found. */
public long getNearestRef() public long GetNearestRef()
{ {
return nearestRef; return nearestRef;
} }
/** Returns the nearest point on the polygon. [opt] [(x, y, z)]. Unchanged if no polygon is found. */ /** Returns the nearest point on the polygon. [opt] [(x, y, z)]. Unchanged if no polygon is found. */
public Vector3f getNearestPos() public Vector3f GetNearestPos()
{ {
return nearestPos; return nearestPos;
} }
public bool isOverPoly() public bool IsOverPoly()
{ {
return overPoly; return overPoly;
} }

View File

@ -36,17 +36,17 @@ namespace DotRecast.Detour.QueryResults
this.costs = costs; this.costs = costs;
} }
public List<long> getRefs() public List<long> GetRefs()
{ {
return refs; return refs;
} }
public List<long> getParentRefs() public List<long> GetParentRefs()
{ {
return parentRefs; return parentRefs;
} }
public List<float> getCosts() public List<float> GetCosts()
{ {
return costs; return costs;
} }

View File

@ -35,13 +35,13 @@ namespace DotRecast.Detour.QueryResults
} }
/// @param[out] randomRef The reference id of the random location. /// @param[out] randomRef The reference id of the random location.
public long getRandomRef() public long GetRandomRef()
{ {
return randomRef; return randomRef;
} }
/// @param[out] randomPt The random location. /// @param[out] randomPt The random location.
public Vector3f getRandomPt() public Vector3f GetRandomPt()
{ {
return randomPt; return randomPt;
} }

View File

@ -34,23 +34,23 @@ namespace DotRecast.Detour.QueryResults
_segmentRefs = segmentRefs; _segmentRefs = segmentRefs;
} }
public int countSegmentVerts() public int CountSegmentVerts()
{ {
return _segmentVerts.Count; return _segmentVerts.Count;
} }
public int countSegmentRefs() public int CountSegmentRefs()
{ {
return _segmentRefs.Count; return _segmentRefs.Count;
} }
public SegmentVert getSegmentVert(int idx) public SegmentVert GetSegmentVert(int idx)
{ {
return _segmentVerts[idx]; return _segmentVerts[idx];
} }
public long getSegmentRef(int idx) public long GetSegmentRef(int idx)
{ {
return _segmentRefs[idx]; return _segmentRefs[idx];
} }

View File

@ -37,12 +37,12 @@ namespace DotRecast.Detour.QueryResults
this.visited = visited; this.visited = visited;
} }
public Vector3f getResultPos() public Vector3f GetResultPos()
{ {
return resultPos; return resultPos;
} }
public List<long> getVisited() public List<long> GetVisited()
{ {
return visited; return visited;
} }

View File

@ -84,12 +84,12 @@ namespace DotRecast.Detour.QueryResults
public bool Failed() public bool Failed()
{ {
return status.isFailed(); return status.IsFailed();
} }
public bool Succeeded() public bool Succeeded()
{ {
return status.isSuccess(); return status.IsSuccess();
} }
} }
} }

View File

@ -38,22 +38,22 @@ namespace DotRecast.Detour
public static class StatusEx public static class StatusEx
{ {
public static bool isFailed(this Status @this) public static bool IsFailed(this Status @this)
{ {
return @this == Status.FAILURE || @this == Status.FAILURE_INVALID_PARAM; return @this == Status.FAILURE || @this == Status.FAILURE_INVALID_PARAM;
} }
public static bool isInProgress(this Status @this) public static bool IsInProgress(this Status @this)
{ {
return @this == Status.IN_PROGRESS; return @this == Status.IN_PROGRESS;
} }
public static bool isSuccess(this Status @this) public static bool IsSuccess(this Status @this)
{ {
return @this == Status.SUCCSESS || @this == Status.PARTIAL_RESULT; return @this == Status.SUCCSESS || @this == Status.PARTIAL_RESULT;
} }
public static bool isPartial(this Status @this) public static bool IsPartial(this Status @this)
{ {
return @this == Status.PARTIAL_RESULT; return @this == Status.PARTIAL_RESULT;
} }

View File

@ -38,17 +38,17 @@ namespace DotRecast.Detour
this.refs = refs; this.refs = refs;
} }
public Vector3f getPos() public Vector3f GetPos()
{ {
return pos; return pos;
} }
public int getFlags() public int GetFlags()
{ {
return flags; return flags;
} }
public long getRef() public long GetRef()
{ {
return refs; return refs;
} }

View File

@ -5,12 +5,12 @@ namespace DotRecast.Recast.Demo.Builder;
public abstract class AbstractNavMeshBuilder public abstract class AbstractNavMeshBuilder
{ {
protected NavMeshDataCreateParams getNavMeshCreateParams(DemoInputGeomProvider m_geom, float m_cellSize, protected NavMeshDataCreateParams GetNavMeshCreateParams(DemoInputGeomProvider m_geom, float m_cellSize,
float m_cellHeight, float m_agentHeight, float m_agentRadius, float m_agentMaxClimb, float m_cellHeight, float m_agentHeight, float m_agentRadius, float m_agentMaxClimb,
RecastBuilderResult rcResult) RecastBuilderResult rcResult)
{ {
PolyMesh m_pmesh = rcResult.getMesh(); PolyMesh m_pmesh = rcResult.GetMesh();
PolyMeshDetail m_dmesh = rcResult.getMeshDetail(); PolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
NavMeshDataCreateParams option = new NavMeshDataCreateParams(); NavMeshDataCreateParams option = new NavMeshDataCreateParams();
for (int i = 0; i < m_pmesh.npolys; ++i) for (int i = 0; i < m_pmesh.npolys; ++i)
{ {
@ -42,7 +42,7 @@ public abstract class AbstractNavMeshBuilder
option.ch = m_cellHeight; option.ch = m_cellHeight;
option.buildBvTree = true; option.buildBvTree = true;
option.offMeshConCount = m_geom.getOffMeshConnections().Count; option.offMeshConCount = m_geom.GetOffMeshConnections().Count;
option.offMeshConVerts = new float[option.offMeshConCount * 6]; option.offMeshConVerts = new float[option.offMeshConCount * 6];
option.offMeshConRad = new float[option.offMeshConCount]; option.offMeshConRad = new float[option.offMeshConCount];
option.offMeshConDir = new int[option.offMeshConCount]; option.offMeshConDir = new int[option.offMeshConCount];
@ -51,7 +51,7 @@ public abstract class AbstractNavMeshBuilder
option.offMeshConUserID = new int[option.offMeshConCount]; option.offMeshConUserID = new int[option.offMeshConCount];
for (int i = 0; i < option.offMeshConCount; i++) for (int i = 0; i < option.offMeshConCount; i++)
{ {
DemoOffMeshConnection offMeshCon = m_geom.getOffMeshConnections()[i]; DemoOffMeshConnection offMeshCon = m_geom.GetOffMeshConnections()[i];
for (int j = 0; j < 6; j++) for (int j = 0; j < 6; j++)
{ {
option.offMeshConVerts[6 * i + j] = offMeshCon.verts[j]; option.offMeshConVerts[6 * i + j] = offMeshCon.verts[j];
@ -66,27 +66,27 @@ public abstract class AbstractNavMeshBuilder
return option; return option;
} }
protected MeshData updateAreaAndFlags(MeshData meshData) protected MeshData UpdateAreaAndFlags(MeshData meshData)
{ {
// Update poly flags from areas. // Update poly flags from areas.
for (int i = 0; i < meshData.polys.Length; ++i) for (int i = 0; i < meshData.polys.Length; ++i)
{ {
if (meshData.polys[i].getArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WALKABLE) if (meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WALKABLE)
{ {
meshData.polys[i].setArea(SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND); meshData.polys[i].SetArea(SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND);
} }
if (meshData.polys[i].getArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND if (meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND
|| meshData.polys[i].getArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GRASS || meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GRASS
|| meshData.polys[i].getArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD) || meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD)
{ {
meshData.polys[i].flags = SampleAreaModifications.SAMPLE_POLYFLAGS_WALK; meshData.polys[i].flags = SampleAreaModifications.SAMPLE_POLYFLAGS_WALK;
} }
else if (meshData.polys[i].getArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER) else if (meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER)
{ {
meshData.polys[i].flags = SampleAreaModifications.SAMPLE_POLYFLAGS_SWIM; meshData.polys[i].flags = SampleAreaModifications.SAMPLE_POLYFLAGS_SWIM;
} }
else if (meshData.polys[i].getArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_DOOR) else if (meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_DOOR)
{ {
meshData.polys[i].flags = SampleAreaModifications.SAMPLE_POLYFLAGS_DOOR; meshData.polys[i].flags = SampleAreaModifications.SAMPLE_POLYFLAGS_DOOR;
} }

View File

@ -26,28 +26,28 @@ namespace DotRecast.Recast.Demo.Builder;
public class SoloNavMeshBuilder : AbstractNavMeshBuilder public class SoloNavMeshBuilder : AbstractNavMeshBuilder
{ {
public Tuple<IList<RecastBuilderResult>, NavMesh> build(DemoInputGeomProvider m_geom, PartitionType m_partitionType, public Tuple<IList<RecastBuilderResult>, NavMesh> Build(DemoInputGeomProvider m_geom, PartitionType m_partitionType,
float m_cellSize, float m_cellHeight, float m_agentHeight, float m_agentRadius, float m_agentMaxClimb, float m_cellSize, float m_cellHeight, float m_agentHeight, float m_agentRadius, float m_agentMaxClimb,
float m_agentMaxSlope, int m_regionMinSize, int m_regionMergeSize, float m_edgeMaxLen, float m_edgeMaxError, float m_agentMaxSlope, int m_regionMinSize, int m_regionMergeSize, float m_edgeMaxLen, float m_edgeMaxError,
int m_vertsPerPoly, float m_detailSampleDist, float m_detailSampleMaxError, bool filterLowHangingObstacles, int m_vertsPerPoly, float m_detailSampleDist, float m_detailSampleMaxError, bool filterLowHangingObstacles,
bool filterLedgeSpans, bool filterWalkableLowHeightSpans) bool filterLedgeSpans, bool filterWalkableLowHeightSpans)
{ {
RecastBuilderResult rcResult = buildRecastResult(m_geom, m_partitionType, m_cellSize, m_cellHeight, m_agentHeight, RecastBuilderResult rcResult = BuildRecastResult(m_geom, m_partitionType, m_cellSize, m_cellHeight, m_agentHeight,
m_agentRadius, m_agentMaxClimb, m_agentMaxSlope, m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_agentRadius, m_agentMaxClimb, m_agentMaxSlope, m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError,
m_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError, filterLowHangingObstacles, filterLedgeSpans, m_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError, filterLowHangingObstacles, filterLedgeSpans,
filterWalkableLowHeightSpans); filterWalkableLowHeightSpans);
return Tuple.Create(ImmutableArray.Create(rcResult) as IList<RecastBuilderResult>, return Tuple.Create(ImmutableArray.Create(rcResult) as IList<RecastBuilderResult>,
buildNavMesh( BuildNavMesh(
buildMeshData(m_geom, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, rcResult), BuildMeshData(m_geom, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, rcResult),
m_vertsPerPoly)); m_vertsPerPoly));
} }
private NavMesh buildNavMesh(MeshData meshData, int m_vertsPerPoly) private NavMesh BuildNavMesh(MeshData meshData, int m_vertsPerPoly)
{ {
return new NavMesh(meshData, m_vertsPerPoly, 0); return new NavMesh(meshData, m_vertsPerPoly, 0);
} }
private RecastBuilderResult buildRecastResult(DemoInputGeomProvider m_geom, PartitionType m_partitionType, float m_cellSize, private RecastBuilderResult BuildRecastResult(DemoInputGeomProvider m_geom, PartitionType m_partitionType, float m_cellSize,
float m_cellHeight, float m_agentHeight, float m_agentRadius, float m_agentMaxClimb, float m_agentMaxSlope, float m_cellHeight, float m_agentHeight, float m_agentRadius, float m_agentMaxClimb, float m_agentMaxSlope,
int m_regionMinSize, int m_regionMergeSize, float m_edgeMaxLen, float m_edgeMaxError, int m_vertsPerPoly, int m_regionMinSize, int m_regionMergeSize, float m_edgeMaxLen, float m_edgeMaxError, int m_vertsPerPoly,
float m_detailSampleDist, float m_detailSampleMaxError, bool filterLowHangingObstacles, bool filterLedgeSpans, float m_detailSampleDist, float m_detailSampleMaxError, bool filterLowHangingObstacles, bool filterLedgeSpans,
@ -57,16 +57,16 @@ public class SoloNavMeshBuilder : AbstractNavMeshBuilder
filterLedgeSpans, filterWalkableLowHeightSpans, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_regionMinSize, filterLedgeSpans, filterWalkableLowHeightSpans, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_regionMinSize,
m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError,
SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true); SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, m_geom.getMeshBoundsMin(), m_geom.getMeshBoundsMax()); RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, m_geom.GetMeshBoundsMin(), m_geom.GetMeshBoundsMax());
RecastBuilder rcBuilder = new RecastBuilder(); RecastBuilder rcBuilder = new RecastBuilder();
return rcBuilder.build(m_geom, bcfg); return rcBuilder.Build(m_geom, bcfg);
} }
private MeshData buildMeshData(DemoInputGeomProvider m_geom, float m_cellSize, float m_cellHeight, float m_agentHeight, private MeshData BuildMeshData(DemoInputGeomProvider m_geom, float m_cellSize, float m_cellHeight, float m_agentHeight,
float m_agentRadius, float m_agentMaxClimb, RecastBuilderResult rcResult) float m_agentRadius, float m_agentMaxClimb, RecastBuilderResult rcResult)
{ {
NavMeshDataCreateParams option = getNavMeshCreateParams(m_geom, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, NavMeshDataCreateParams option = GetNavMeshCreateParams(m_geom, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius,
m_agentMaxClimb, rcResult); m_agentMaxClimb, rcResult);
return updateAreaAndFlags(NavMeshBuilder.createNavMeshData(option)); return UpdateAreaAndFlags(NavMeshBuilder.CreateNavMeshData(option));
} }
} }

View File

@ -32,87 +32,87 @@ public class TileNavMeshBuilder : AbstractNavMeshBuilder
{ {
} }
public Tuple<IList<RecastBuilderResult>, NavMesh> build(DemoInputGeomProvider m_geom, PartitionType m_partitionType, public Tuple<IList<RecastBuilderResult>, NavMesh> Build(DemoInputGeomProvider m_geom, PartitionType m_partitionType,
float m_cellSize, float m_cellHeight, float m_agentHeight, float m_agentRadius, float m_agentMaxClimb, float m_cellSize, float m_cellHeight, float m_agentHeight, float m_agentRadius, float m_agentMaxClimb,
float m_agentMaxSlope, int m_regionMinSize, int m_regionMergeSize, float m_edgeMaxLen, float m_edgeMaxError, float m_agentMaxSlope, int m_regionMinSize, int m_regionMergeSize, float m_edgeMaxLen, float m_edgeMaxError,
int m_vertsPerPoly, float m_detailSampleDist, float m_detailSampleMaxError, bool filterLowHangingObstacles, int m_vertsPerPoly, float m_detailSampleDist, float m_detailSampleMaxError, bool filterLowHangingObstacles,
bool filterLedgeSpans, bool filterWalkableLowHeightSpans, int tileSize) bool filterLedgeSpans, bool filterWalkableLowHeightSpans, int tileSize)
{ {
List<RecastBuilderResult> rcResult = buildRecastResult(m_geom, m_partitionType, m_cellSize, m_cellHeight, m_agentHeight, List<RecastBuilderResult> rcResult = BuildRecastResult(m_geom, m_partitionType, m_cellSize, m_cellHeight, m_agentHeight,
m_agentRadius, m_agentMaxClimb, m_agentMaxSlope, m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_agentRadius, m_agentMaxClimb, m_agentMaxSlope, m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError,
m_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError, filterLowHangingObstacles, filterLedgeSpans, m_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError, filterLowHangingObstacles, filterLedgeSpans,
filterWalkableLowHeightSpans, tileSize); filterWalkableLowHeightSpans, tileSize);
return Tuple.Create((IList<RecastBuilderResult>)rcResult, return Tuple.Create((IList<RecastBuilderResult>)rcResult,
buildNavMesh(m_geom, BuildNavMesh(m_geom,
buildMeshData(m_geom, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, rcResult), BuildMeshData(m_geom, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, rcResult),
m_cellSize, tileSize, m_vertsPerPoly)); m_cellSize, tileSize, m_vertsPerPoly));
} }
private List<RecastBuilderResult> buildRecastResult(DemoInputGeomProvider m_geom, PartitionType m_partitionType, private List<RecastBuilderResult> BuildRecastResult(DemoInputGeomProvider m_geom, PartitionType m_partitionType,
float m_cellSize, float m_cellHeight, float m_agentHeight, float m_agentRadius, float m_agentMaxClimb, float m_cellSize, float m_cellHeight, float m_agentHeight, float m_agentRadius, float m_agentMaxClimb,
float m_agentMaxSlope, int m_regionMinSize, int m_regionMergeSize, float m_edgeMaxLen, float m_edgeMaxError, float m_agentMaxSlope, int m_regionMinSize, int m_regionMergeSize, float m_edgeMaxLen, float m_edgeMaxError,
int m_vertsPerPoly, float m_detailSampleDist, float m_detailSampleMaxError, bool filterLowHangingObstacles, int m_vertsPerPoly, float m_detailSampleDist, float m_detailSampleMaxError, bool filterLowHangingObstacles,
bool filterLedgeSpans, bool filterWalkableLowHeightSpans, int tileSize) bool filterLedgeSpans, bool filterWalkableLowHeightSpans, int tileSize)
{ {
RecastConfig cfg = new RecastConfig(true, tileSize, tileSize, RecastConfig.calcBorder(m_agentRadius, m_cellSize), RecastConfig cfg = new RecastConfig(true, tileSize, tileSize, RecastConfig.CalcBorder(m_agentRadius, m_cellSize),
m_partitionType, m_cellSize, m_cellHeight, m_agentMaxSlope, filterLowHangingObstacles, filterLedgeSpans, m_partitionType, m_cellSize, m_cellHeight, m_agentMaxSlope, filterLowHangingObstacles, filterLedgeSpans,
filterWalkableLowHeightSpans, m_agentHeight, m_agentRadius, m_agentMaxClimb, filterWalkableLowHeightSpans, m_agentHeight, m_agentRadius, m_agentMaxClimb,
m_regionMinSize * m_regionMinSize * m_cellSize * m_cellSize, m_regionMinSize * m_regionMinSize * m_cellSize * m_cellSize,
m_regionMergeSize * m_regionMergeSize * m_cellSize * m_cellSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_regionMergeSize * m_regionMergeSize * m_cellSize * m_cellSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly,
true, m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE); true, m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE);
RecastBuilder rcBuilder = new RecastBuilder(); RecastBuilder rcBuilder = new RecastBuilder();
return rcBuilder.buildTiles(m_geom, cfg, Task.Factory); return rcBuilder.BuildTiles(m_geom, cfg, Task.Factory);
} }
private NavMesh buildNavMesh(DemoInputGeomProvider geom, List<MeshData> meshData, float cellSize, int tileSize, private NavMesh BuildNavMesh(DemoInputGeomProvider geom, List<MeshData> meshData, float cellSize, int tileSize,
int vertsPerPoly) int vertsPerPoly)
{ {
NavMeshParams navMeshParams = new NavMeshParams(); NavMeshParams navMeshParams = new NavMeshParams();
navMeshParams.orig.x = geom.getMeshBoundsMin().x; navMeshParams.orig.x = geom.GetMeshBoundsMin().x;
navMeshParams.orig.y = geom.getMeshBoundsMin().y; navMeshParams.orig.y = geom.GetMeshBoundsMin().y;
navMeshParams.orig.z = geom.getMeshBoundsMin().z; navMeshParams.orig.z = geom.GetMeshBoundsMin().z;
navMeshParams.tileWidth = tileSize * cellSize; navMeshParams.tileWidth = tileSize * cellSize;
navMeshParams.tileHeight = tileSize * cellSize; navMeshParams.tileHeight = tileSize * cellSize;
// snprintf(text, 64, "Tiles %d x %d", tw, th); // Snprintf(text, 64, "Tiles %d x %d", tw, th);
navMeshParams.maxTiles = getMaxTiles(geom, cellSize, tileSize); navMeshParams.maxTiles = GetMaxTiles(geom, cellSize, tileSize);
navMeshParams.maxPolys = getMaxPolysPerTile(geom, cellSize, tileSize); navMeshParams.maxPolys = GetMaxPolysPerTile(geom, cellSize, tileSize);
NavMesh navMesh = new NavMesh(navMeshParams, vertsPerPoly); NavMesh navMesh = new NavMesh(navMeshParams, vertsPerPoly);
meshData.forEach(md => navMesh.addTile(md, 0, 0)); meshData.ForEach(md => navMesh.AddTile(md, 0, 0));
return navMesh; return navMesh;
} }
public int getMaxTiles(DemoInputGeomProvider geom, float cellSize, int tileSize) public int GetMaxTiles(DemoInputGeomProvider geom, float cellSize, int tileSize)
{ {
int tileBits = getTileBits(geom, cellSize, tileSize); int tileBits = GetTileBits(geom, cellSize, tileSize);
return 1 << tileBits; return 1 << tileBits;
} }
public int getMaxPolysPerTile(DemoInputGeomProvider geom, float cellSize, int tileSize) public int GetMaxPolysPerTile(DemoInputGeomProvider geom, float cellSize, int tileSize)
{ {
int polyBits = 22 - getTileBits(geom, cellSize, tileSize); int polyBits = 22 - GetTileBits(geom, cellSize, tileSize);
return 1 << polyBits; return 1 << polyBits;
} }
private int getTileBits(DemoInputGeomProvider geom, float cellSize, int tileSize) private int GetTileBits(DemoInputGeomProvider geom, float cellSize, int tileSize)
{ {
int[] wh = Recast.calcGridSize(geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), cellSize); int[] wh = Recast.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize);
int tw = (wh[0] + tileSize - 1) / tileSize; int tw = (wh[0] + tileSize - 1) / tileSize;
int th = (wh[1] + tileSize - 1) / tileSize; int th = (wh[1] + tileSize - 1) / tileSize;
int tileBits = Math.Min(ilog2(nextPow2(tw * th)), 14); int tileBits = Math.Min(Ilog2(NextPow2(tw * th)), 14);
return tileBits; return tileBits;
} }
public int[] getTiles(DemoInputGeomProvider geom, float cellSize, int tileSize) public int[] GetTiles(DemoInputGeomProvider geom, float cellSize, int tileSize)
{ {
int[] wh = Recast.calcGridSize(geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), cellSize); int[] wh = Recast.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize);
int tw = (wh[0] + tileSize - 1) / tileSize; int tw = (wh[0] + tileSize - 1) / tileSize;
int th = (wh[1] + tileSize - 1) / tileSize; int th = (wh[1] + tileSize - 1) / tileSize;
return new int[] { tw, th }; return new int[] { tw, th };
} }
private List<MeshData> buildMeshData(DemoInputGeomProvider m_geom, float m_cellSize, float m_cellHeight, float m_agentHeight, private List<MeshData> BuildMeshData(DemoInputGeomProvider m_geom, float m_cellSize, float m_cellHeight, float m_agentHeight,
float m_agentRadius, float m_agentMaxClimb, List<RecastBuilderResult> rcResult) float m_agentRadius, float m_agentMaxClimb, List<RecastBuilderResult> rcResult)
{ {
// Add tiles to nav mesh // Add tiles to nav mesh
@ -121,14 +121,14 @@ public class TileNavMeshBuilder : AbstractNavMeshBuilder
{ {
int x = result.tileX; int x = result.tileX;
int z = result.tileZ; int z = result.tileZ;
NavMeshDataCreateParams option = getNavMeshCreateParams(m_geom, m_cellSize, m_cellHeight, m_agentHeight, NavMeshDataCreateParams option = GetNavMeshCreateParams(m_geom, m_cellSize, m_cellHeight, m_agentHeight,
m_agentRadius, m_agentMaxClimb, result); m_agentRadius, m_agentMaxClimb, result);
option.tileX = x; option.tileX = x;
option.tileZ = z; option.tileZ = z;
MeshData md = NavMeshBuilder.createNavMeshData(option); MeshData md = NavMeshBuilder.CreateNavMeshData(option);
if (md != null) if (md != null)
{ {
meshData.Add(updateAreaAndFlags(md)); meshData.Add(UpdateAreaAndFlags(md));
} }
} }

View File

@ -48,24 +48,24 @@ public class DebugDraw
} }
public void begin(DebugDrawPrimitives prim) public void Begin(DebugDrawPrimitives prim)
{ {
begin(prim, 1f); Begin(prim, 1f);
} }
public void debugDrawCylinderWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, int col, public void DebugDrawCylinderWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, int col,
float lineWidth) float lineWidth)
{ {
begin(DebugDrawPrimitives.LINES, lineWidth); Begin(DebugDrawPrimitives.LINES, lineWidth);
appendCylinderWire(minx, miny, minz, maxx, maxy, maxz, col); AppendCylinderWire(minx, miny, minz, maxx, maxy, maxz, col);
end(); End();
} }
private const int CYLINDER_NUM_SEG = 16; private const int CYLINDER_NUM_SEG = 16;
private readonly float[] cylinderDir = new float[CYLINDER_NUM_SEG * 2]; private readonly float[] cylinderDir = new float[CYLINDER_NUM_SEG * 2];
private bool cylinderInit = false; private bool cylinderInit = false;
private void initCylinder() private void InitCylinder()
{ {
if (!cylinderInit) if (!cylinderInit)
{ {
@ -79,9 +79,9 @@ public class DebugDraw
} }
} }
void appendCylinderWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, int col) void AppendCylinderWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, int col)
{ {
initCylinder(); InitCylinder();
float cx = (maxx + minx) / 2; float cx = (maxx + minx) / 2;
float cz = (maxz + minz) / 2; float cz = (maxz + minz) / 2;
@ -90,61 +90,61 @@ public class DebugDraw
for (int i = 0, j = CYLINDER_NUM_SEG - 1; i < CYLINDER_NUM_SEG; j = i++) for (int i = 0, j = CYLINDER_NUM_SEG - 1; i < CYLINDER_NUM_SEG; j = i++)
{ {
vertex(cx + cylinderDir[j * 2 + 0] * rx, miny, cz + cylinderDir[j * 2 + 1] * rz, col); Vertex(cx + cylinderDir[j * 2 + 0] * rx, miny, cz + cylinderDir[j * 2 + 1] * rz, col);
vertex(cx + cylinderDir[i * 2 + 0] * rx, miny, cz + cylinderDir[i * 2 + 1] * rz, col); Vertex(cx + cylinderDir[i * 2 + 0] * rx, miny, cz + cylinderDir[i * 2 + 1] * rz, col);
vertex(cx + cylinderDir[j * 2 + 0] * rx, maxy, cz + cylinderDir[j * 2 + 1] * rz, col); Vertex(cx + cylinderDir[j * 2 + 0] * rx, maxy, cz + cylinderDir[j * 2 + 1] * rz, col);
vertex(cx + cylinderDir[i * 2 + 0] * rx, maxy, cz + cylinderDir[i * 2 + 1] * rz, col); Vertex(cx + cylinderDir[i * 2 + 0] * rx, maxy, cz + cylinderDir[i * 2 + 1] * rz, col);
} }
for (int i = 0; i < CYLINDER_NUM_SEG; i += CYLINDER_NUM_SEG / 4) for (int i = 0; i < CYLINDER_NUM_SEG; i += CYLINDER_NUM_SEG / 4)
{ {
vertex(cx + cylinderDir[i * 2 + 0] * rx, miny, cz + cylinderDir[i * 2 + 1] * rz, col); Vertex(cx + cylinderDir[i * 2 + 0] * rx, miny, cz + cylinderDir[i * 2 + 1] * rz, col);
vertex(cx + cylinderDir[i * 2 + 0] * rx, maxy, cz + cylinderDir[i * 2 + 1] * rz, col); Vertex(cx + cylinderDir[i * 2 + 0] * rx, maxy, cz + cylinderDir[i * 2 + 1] * rz, col);
} }
} }
public void debugDrawBoxWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, int col, public void DebugDrawBoxWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, int col,
float lineWidth) float lineWidth)
{ {
begin(DebugDrawPrimitives.LINES, lineWidth); Begin(DebugDrawPrimitives.LINES, lineWidth);
appendBoxWire(minx, miny, minz, maxx, maxy, maxz, col); AppendBoxWire(minx, miny, minz, maxx, maxy, maxz, col);
end(); End();
} }
public void appendBoxWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, int col) public void AppendBoxWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, int col)
{ {
// Top // Top
vertex(minx, miny, minz, col); Vertex(minx, miny, minz, col);
vertex(maxx, miny, minz, col); Vertex(maxx, miny, minz, col);
vertex(maxx, miny, minz, col); Vertex(maxx, miny, minz, col);
vertex(maxx, miny, maxz, col); Vertex(maxx, miny, maxz, col);
vertex(maxx, miny, maxz, col); Vertex(maxx, miny, maxz, col);
vertex(minx, miny, maxz, col); Vertex(minx, miny, maxz, col);
vertex(minx, miny, maxz, col); Vertex(minx, miny, maxz, col);
vertex(minx, miny, minz, col); Vertex(minx, miny, minz, col);
// bottom // bottom
vertex(minx, maxy, minz, col); Vertex(minx, maxy, minz, col);
vertex(maxx, maxy, minz, col); Vertex(maxx, maxy, minz, col);
vertex(maxx, maxy, minz, col); Vertex(maxx, maxy, minz, col);
vertex(maxx, maxy, maxz, col); Vertex(maxx, maxy, maxz, col);
vertex(maxx, maxy, maxz, col); Vertex(maxx, maxy, maxz, col);
vertex(minx, maxy, maxz, col); Vertex(minx, maxy, maxz, col);
vertex(minx, maxy, maxz, col); Vertex(minx, maxy, maxz, col);
vertex(minx, maxy, minz, col); Vertex(minx, maxy, minz, col);
// Sides // Sides
vertex(minx, miny, minz, col); Vertex(minx, miny, minz, col);
vertex(minx, maxy, minz, col); Vertex(minx, maxy, minz, col);
vertex(maxx, miny, minz, col); Vertex(maxx, miny, minz, col);
vertex(maxx, maxy, minz, col); Vertex(maxx, maxy, minz, col);
vertex(maxx, miny, maxz, col); Vertex(maxx, miny, maxz, col);
vertex(maxx, maxy, maxz, col); Vertex(maxx, maxy, maxz, col);
vertex(minx, miny, maxz, col); Vertex(minx, miny, maxz, col);
vertex(minx, maxy, maxz, col); Vertex(minx, maxy, maxz, col);
} }
public void appendBox(float minx, float miny, float minz, float maxx, float maxy, float maxz, int[] fcol) public void AppendBox(float minx, float miny, float minz, float maxx, float maxy, float maxz, int[] fcol)
{ {
float[][] verts = float[][] verts =
{ {
@ -161,66 +161,66 @@ public class DebugDraw
int idx = 0; int idx = 0;
for (int i = 0; i < 6; ++i) for (int i = 0; i < 6; ++i)
{ {
vertex(verts[boxIndices[idx]], fcol[i]); Vertex(verts[boxIndices[idx]], fcol[i]);
idx++; idx++;
vertex(verts[boxIndices[idx]], fcol[i]); Vertex(verts[boxIndices[idx]], fcol[i]);
idx++; idx++;
vertex(verts[boxIndices[idx]], fcol[i]); Vertex(verts[boxIndices[idx]], fcol[i]);
idx++; idx++;
vertex(verts[boxIndices[idx]], fcol[i]); Vertex(verts[boxIndices[idx]], fcol[i]);
idx++; idx++;
} }
} }
public void debugDrawArc(float x0, float y0, float z0, float x1, float y1, float z1, float h, float as0, float as1, int col, public void DebugDrawArc(float x0, float y0, float z0, float x1, float y1, float z1, float h, float as0, float as1, int col,
float lineWidth) float lineWidth)
{ {
begin(DebugDrawPrimitives.LINES, lineWidth); Begin(DebugDrawPrimitives.LINES, lineWidth);
appendArc(x0, y0, z0, x1, y1, z1, h, as0, as1, col); AppendArc(x0, y0, z0, x1, y1, z1, h, as0, as1, col);
end(); End();
} }
public void begin(DebugDrawPrimitives prim, float size) public void Begin(DebugDrawPrimitives prim, float size)
{ {
getOpenGlDraw().begin(prim, size); GetOpenGlDraw().Begin(prim, size);
} }
public void vertex(float[] pos, int color) public void Vertex(float[] pos, int color)
{ {
getOpenGlDraw().vertex(pos, color); GetOpenGlDraw().Vertex(pos, color);
} }
public void vertex(Vector3f pos, int color) public void Vertex(Vector3f pos, int color)
{ {
getOpenGlDraw().vertex(pos, color); GetOpenGlDraw().Vertex(pos, color);
} }
public void vertex(float x, float y, float z, int color) public void Vertex(float x, float y, float z, int color)
{ {
getOpenGlDraw().vertex(x, y, z, color); GetOpenGlDraw().Vertex(x, y, z, color);
} }
public void vertex(Vector3f pos, int color, Vector2f uv) public void Vertex(Vector3f pos, int color, Vector2f uv)
{ {
getOpenGlDraw().vertex(pos, color, uv); GetOpenGlDraw().Vertex(pos, color, uv);
} }
public void vertex(float x, float y, float z, int color, float u, float v) public void Vertex(float x, float y, float z, int color, float u, float v)
{ {
getOpenGlDraw().vertex(x, y, z, color, u, v); GetOpenGlDraw().Vertex(x, y, z, color, u, v);
} }
public void end() public void End()
{ {
getOpenGlDraw().end(); GetOpenGlDraw().End();
} }
public void debugDrawCircle(float x, float y, float z, float r, int col, float lineWidth) public void DebugDrawCircle(float x, float y, float z, float r, int col, float lineWidth)
{ {
begin(DebugDrawPrimitives.LINES, lineWidth); Begin(DebugDrawPrimitives.LINES, lineWidth);
appendCircle(x, y, z, r, col); AppendCircle(x, y, z, r, col);
end(); End();
} }
private bool circleInit = false; private bool circleInit = false;
@ -229,7 +229,7 @@ public class DebugDraw
private float[] _viewMatrix = new float[16]; private float[] _viewMatrix = new float[16];
private readonly float[] _projectionMatrix = new float[16]; private readonly float[] _projectionMatrix = new float[16];
public void appendCircle(float x, float y, float z, float r, int col) public void AppendCircle(float x, float y, float z, float r, int col)
{ {
if (!circleInit) if (!circleInit)
{ {
@ -244,8 +244,8 @@ public class DebugDraw
for (int i = 0, j = CIRCLE_NUM_SEG - 1; i < CIRCLE_NUM_SEG; j = i++) for (int i = 0, j = CIRCLE_NUM_SEG - 1; i < CIRCLE_NUM_SEG; j = i++)
{ {
vertex(x + circeDir[j * 2 + 0] * r, y, z + circeDir[j * 2 + 1] * r, col); Vertex(x + circeDir[j * 2 + 0] * r, y, z + circeDir[j * 2 + 1] * r, col);
vertex(x + circeDir[i * 2 + 0] * r, y, z + circeDir[i * 2 + 1] * r, col); Vertex(x + circeDir[i * 2 + 0] * r, y, z + circeDir[i * 2 + 1] * r, col);
} }
} }
@ -253,21 +253,21 @@ public class DebugDraw
private static readonly float PAD = 0.05f; private static readonly float PAD = 0.05f;
private static readonly float ARC_PTS_SCALE = (1.0f - PAD * 2) / NUM_ARC_PTS; private static readonly float ARC_PTS_SCALE = (1.0f - PAD * 2) / NUM_ARC_PTS;
public void appendArc(float x0, float y0, float z0, float x1, float y1, float z1, float h, float as0, float as1, int col) public void AppendArc(float x0, float y0, float z0, float x1, float y1, float z1, float h, float as0, float as1, int col)
{ {
float dx = x1 - x0; float dx = x1 - x0;
float dy = y1 - y0; float dy = y1 - y0;
float dz = z1 - z0; float dz = z1 - z0;
float len = (float)Math.Sqrt(dx * dx + dy * dy + dz * dz); float len = (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
Vector3f prev = new Vector3f(); Vector3f prev = new Vector3f();
evalArc(x0, y0, z0, dx, dy, dz, len * h, PAD, ref prev); EvalArc(x0, y0, z0, dx, dy, dz, len * h, PAD, ref prev);
for (int i = 1; i <= NUM_ARC_PTS; ++i) for (int i = 1; i <= NUM_ARC_PTS; ++i)
{ {
float u = PAD + i * ARC_PTS_SCALE; float u = PAD + i * ARC_PTS_SCALE;
Vector3f pt = new Vector3f(); Vector3f pt = new Vector3f();
evalArc(x0, y0, z0, dx, dy, dz, len * h, u, ref pt); EvalArc(x0, y0, z0, dx, dy, dz, len * h, u, ref pt);
vertex(prev.x, prev.y, prev.z, col); Vertex(prev.x, prev.y, prev.z, col);
vertex(pt.x, pt.y, pt.z, col); Vertex(pt.x, pt.y, pt.z, col);
prev.x = pt.x; prev.x = pt.x;
prev.y = pt.y; prev.y = pt.y;
prev.z = pt.z; prev.z = pt.z;
@ -278,64 +278,64 @@ public class DebugDraw
{ {
Vector3f p = new Vector3f(); Vector3f p = new Vector3f();
Vector3f q = new Vector3f(); Vector3f q = new Vector3f();
evalArc(x0, y0, z0, dx, dy, dz, len * h, PAD, ref p); EvalArc(x0, y0, z0, dx, dy, dz, len * h, PAD, ref p);
evalArc(x0, y0, z0, dx, dy, dz, len * h, PAD + 0.05f, ref q); EvalArc(x0, y0, z0, dx, dy, dz, len * h, PAD + 0.05f, ref q);
appendArrowHead(p, q, as0, col); AppendArrowHead(p, q, as0, col);
} }
if (as1 > 0.001f) if (as1 > 0.001f)
{ {
Vector3f p = new Vector3f(); Vector3f p = new Vector3f();
Vector3f q = new Vector3f(); Vector3f q = new Vector3f();
evalArc(x0, y0, z0, dx, dy, dz, len * h, 1 - PAD, ref p); EvalArc(x0, y0, z0, dx, dy, dz, len * h, 1 - PAD, ref p);
evalArc(x0, y0, z0, dx, dy, dz, len * h, 1 - (PAD + 0.05f), ref q); EvalArc(x0, y0, z0, dx, dy, dz, len * h, 1 - (PAD + 0.05f), ref q);
appendArrowHead(p, q, as1, col); AppendArrowHead(p, q, as1, col);
} }
} }
private void evalArc(float x0, float y0, float z0, float dx, float dy, float dz, float h, float u, ref Vector3f res) private void EvalArc(float x0, float y0, float z0, float dx, float dy, float dz, float h, float u, ref Vector3f res)
{ {
res.x = x0 + dx * u; res.x = x0 + dx * u;
res.y = y0 + dy * u + h * (1 - (u * 2 - 1) * (u * 2 - 1)); res.y = y0 + dy * u + h * (1 - (u * 2 - 1) * (u * 2 - 1));
res.z = z0 + dz * u; res.z = z0 + dz * u;
} }
public void debugDrawCross(float x, float y, float z, float size, int col, float lineWidth) public void DebugDrawCross(float x, float y, float z, float size, int col, float lineWidth)
{ {
begin(DebugDrawPrimitives.LINES, lineWidth); Begin(DebugDrawPrimitives.LINES, lineWidth);
appendCross(x, y, z, size, col); AppendCross(x, y, z, size, col);
end(); End();
} }
private void appendCross(float x, float y, float z, float s, int col) private void AppendCross(float x, float y, float z, float s, int col)
{ {
vertex(x - s, y, z, col); Vertex(x - s, y, z, col);
vertex(x + s, y, z, col); Vertex(x + s, y, z, col);
vertex(x, y - s, z, col); Vertex(x, y - s, z, col);
vertex(x, y + s, z, col); Vertex(x, y + s, z, col);
vertex(x, y, z - s, col); Vertex(x, y, z - s, col);
vertex(x, y, z + s, col); Vertex(x, y, z + s, col);
} }
public void debugDrawBox(float minx, float miny, float minz, float maxx, float maxy, float maxz, int[] fcol) public void DebugDrawBox(float minx, float miny, float minz, float maxx, float maxy, float maxz, int[] fcol)
{ {
begin(DebugDrawPrimitives.QUADS); Begin(DebugDrawPrimitives.QUADS);
appendBox(minx, miny, minz, maxx, maxy, maxz, fcol); AppendBox(minx, miny, minz, maxx, maxy, maxz, fcol);
end(); End();
} }
public void debugDrawCylinder(float minx, float miny, float minz, float maxx, float maxy, float maxz, int col) public void DebugDrawCylinder(float minx, float miny, float minz, float maxx, float maxy, float maxz, int col)
{ {
begin(DebugDrawPrimitives.TRIS); Begin(DebugDrawPrimitives.TRIS);
appendCylinder(minx, miny, minz, maxx, maxy, maxz, col); AppendCylinder(minx, miny, minz, maxx, maxy, maxz, col);
end(); End();
} }
public void appendCylinder(float minx, float miny, float minz, float maxx, float maxy, float maxz, int col) public void AppendCylinder(float minx, float miny, float minz, float maxx, float maxy, float maxz, int col)
{ {
initCylinder(); InitCylinder();
int col2 = duMultCol(col, 160); int col2 = DuMultCol(col, 160);
float cx = (maxx + minx) / 2; float cx = (maxx + minx) / 2;
float cz = (maxz + minz) / 2; float cz = (maxz + minz) / 2;
@ -345,57 +345,57 @@ public class DebugDraw
for (int i = 2; i < CYLINDER_NUM_SEG; ++i) for (int i = 2; i < CYLINDER_NUM_SEG; ++i)
{ {
int a = 0, b = i - 1, c = i; int a = 0, b = i - 1, c = i;
vertex(cx + cylinderDir[a * 2 + 0] * rx, miny, cz + cylinderDir[a * 2 + 1] * rz, col2); Vertex(cx + cylinderDir[a * 2 + 0] * rx, miny, cz + cylinderDir[a * 2 + 1] * rz, col2);
vertex(cx + cylinderDir[b * 2 + 0] * rx, miny, cz + cylinderDir[b * 2 + 1] * rz, col2); Vertex(cx + cylinderDir[b * 2 + 0] * rx, miny, cz + cylinderDir[b * 2 + 1] * rz, col2);
vertex(cx + cylinderDir[c * 2 + 0] * rx, miny, cz + cylinderDir[c * 2 + 1] * rz, col2); Vertex(cx + cylinderDir[c * 2 + 0] * rx, miny, cz + cylinderDir[c * 2 + 1] * rz, col2);
} }
for (int i = 2; i < CYLINDER_NUM_SEG; ++i) for (int i = 2; i < CYLINDER_NUM_SEG; ++i)
{ {
int a = 0, b = i, c = i - 1; int a = 0, b = i, c = i - 1;
vertex(cx + cylinderDir[a * 2 + 0] * rx, maxy, cz + cylinderDir[a * 2 + 1] * rz, col); Vertex(cx + cylinderDir[a * 2 + 0] * rx, maxy, cz + cylinderDir[a * 2 + 1] * rz, col);
vertex(cx + cylinderDir[b * 2 + 0] * rx, maxy, cz + cylinderDir[b * 2 + 1] * rz, col); Vertex(cx + cylinderDir[b * 2 + 0] * rx, maxy, cz + cylinderDir[b * 2 + 1] * rz, col);
vertex(cx + cylinderDir[c * 2 + 0] * rx, maxy, cz + cylinderDir[c * 2 + 1] * rz, col); Vertex(cx + cylinderDir[c * 2 + 0] * rx, maxy, cz + cylinderDir[c * 2 + 1] * rz, col);
} }
for (int i = 0, j = CYLINDER_NUM_SEG - 1; i < CYLINDER_NUM_SEG; j = i++) for (int i = 0, j = CYLINDER_NUM_SEG - 1; i < CYLINDER_NUM_SEG; j = i++)
{ {
vertex(cx + cylinderDir[i * 2 + 0] * rx, miny, cz + cylinderDir[i * 2 + 1] * rz, col2); Vertex(cx + cylinderDir[i * 2 + 0] * rx, miny, cz + cylinderDir[i * 2 + 1] * rz, col2);
vertex(cx + cylinderDir[j * 2 + 0] * rx, miny, cz + cylinderDir[j * 2 + 1] * rz, col2); Vertex(cx + cylinderDir[j * 2 + 0] * rx, miny, cz + cylinderDir[j * 2 + 1] * rz, col2);
vertex(cx + cylinderDir[j * 2 + 0] * rx, maxy, cz + cylinderDir[j * 2 + 1] * rz, col); Vertex(cx + cylinderDir[j * 2 + 0] * rx, maxy, cz + cylinderDir[j * 2 + 1] * rz, col);
vertex(cx + cylinderDir[i * 2 + 0] * rx, miny, cz + cylinderDir[i * 2 + 1] * rz, col2); Vertex(cx + cylinderDir[i * 2 + 0] * rx, miny, cz + cylinderDir[i * 2 + 1] * rz, col2);
vertex(cx + cylinderDir[j * 2 + 0] * rx, maxy, cz + cylinderDir[j * 2 + 1] * rz, col); Vertex(cx + cylinderDir[j * 2 + 0] * rx, maxy, cz + cylinderDir[j * 2 + 1] * rz, col);
vertex(cx + cylinderDir[i * 2 + 0] * rx, maxy, cz + cylinderDir[i * 2 + 1] * rz, col); Vertex(cx + cylinderDir[i * 2 + 0] * rx, maxy, cz + cylinderDir[i * 2 + 1] * rz, col);
} }
} }
public void debugDrawArrow(float x0, float y0, float z0, float x1, float y1, float z1, float as0, float as1, int col, public void DebugDrawArrow(float x0, float y0, float z0, float x1, float y1, float z1, float as0, float as1, int col,
float lineWidth) float lineWidth)
{ {
begin(DebugDrawPrimitives.LINES, lineWidth); Begin(DebugDrawPrimitives.LINES, lineWidth);
appendArrow(x0, y0, z0, x1, y1, z1, as0, as1, col); AppendArrow(x0, y0, z0, x1, y1, z1, as0, as1, col);
end(); End();
} }
public void appendArrow(float x0, float y0, float z0, float x1, float y1, float z1, float as0, float as1, int col) public void AppendArrow(float x0, float y0, float z0, float x1, float y1, float z1, float as0, float as1, int col)
{ {
vertex(x0, y0, z0, col); Vertex(x0, y0, z0, col);
vertex(x1, y1, z1, col); Vertex(x1, y1, z1, col);
// End arrows // End arrows
Vector3f p = Vector3f.Of(x0, y0, z0); Vector3f p = Vector3f.Of(x0, y0, z0);
Vector3f q = Vector3f.Of(x1, y1, z1); Vector3f q = Vector3f.Of(x1, y1, z1);
if (as0 > 0.001f) if (as0 > 0.001f)
appendArrowHead(p, q, as0, col); AppendArrowHead(p, q, as0, col);
if (as1 > 0.001f) if (as1 > 0.001f)
appendArrowHead(q, p, as1, col); AppendArrowHead(q, p, as1, col);
} }
void appendArrowHead(Vector3f p, Vector3f q, float s, int col) void AppendArrowHead(Vector3f p, Vector3f q, float s, int col)
{ {
float eps = 0.001f; float eps = 0.001f;
if (vdistSqr(p, q) < eps * eps) if (VdistSqr(p, q) < eps * eps)
{ {
return; return;
} }
@ -403,29 +403,29 @@ public class DebugDraw
Vector3f ax = new Vector3f(); Vector3f ax = new Vector3f();
Vector3f ay = Vector3f.Of(0, 1, 0); Vector3f ay = Vector3f.Of(0, 1, 0);
Vector3f az = new Vector3f(); Vector3f az = new Vector3f();
vsub(ref az, q, p); Vsub(ref az, q, p);
vnormalize(ref az); Vnormalize(ref az);
vcross(ref ax, ay, az); Vcross(ref ax, ay, az);
vcross(ref ay, az, ax); Vcross(ref ay, az, ax);
vnormalize(ref ay); Vnormalize(ref ay);
vertex(p, col); Vertex(p, col);
// vertex(p.x+az.x*s+ay.x*s/2, p.y+az.y*s+ay.y*s/2, p.z+az.z*s+ay.z*s/2, col); // Vertex(p.x+az.x*s+ay.x*s/2, p.y+az.y*s+ay.y*s/2, p.z+az.z*s+ay.z*s/2, col);
vertex(p.x + az.x * s + ax.x * s / 3, p.y + az.y * s + ax.y * s / 3, p.z + az.z * s + ax.z * s / 3, col); Vertex(p.x + az.x * s + ax.x * s / 3, p.y + az.y * s + ax.y * s / 3, p.z + az.z * s + ax.z * s / 3, col);
vertex(p, col); Vertex(p, col);
// vertex(p.x+az.x*s-ay.x*s/2, p.y+az.y*s-ay.y*s/2, p.z+az.z*s-ay.z*s/2, col); // Vertex(p.x+az.x*s-ay.x*s/2, p.y+az.y*s-ay.y*s/2, p.z+az.z*s-ay.z*s/2, col);
vertex(p.x + az.x * s - ax.x * s / 3, p.y + az.y * s - ax.y * s / 3, p.z + az.z * s - ax.z * s / 3, col); Vertex(p.x + az.x * s - ax.x * s / 3, p.y + az.y * s - ax.y * s / 3, p.z + az.z * s - ax.z * s / 3, col);
} }
public void vcross(ref Vector3f dest, Vector3f v1, Vector3f v2) public void Vcross(ref Vector3f dest, Vector3f v1, Vector3f v2)
{ {
dest.x = v1.y * v2.z - v1.z * v2.y; dest.x = v1.y * v2.z - v1.z * v2.y;
dest.y = v1.z * v2.x - v1.x * v2.z; dest.y = v1.z * v2.x - v1.x * v2.z;
dest.z = v1.x * v2.y - v1.y * v2.x; dest.z = v1.x * v2.y - v1.y * v2.x;
} }
public void vnormalize(ref Vector3f v) public void Vnormalize(ref Vector3f v)
{ {
float d = (float)(1.0f / Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z)); float d = (float)(1.0f / Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z));
v.x *= d; v.x *= d;
@ -433,14 +433,14 @@ public class DebugDraw
v.z *= d; v.z *= d;
} }
public void vsub(ref Vector3f dest, Vector3f v1, Vector3f v2) public void Vsub(ref Vector3f dest, Vector3f v1, Vector3f v2)
{ {
dest.x = v1.x - v2.x; dest.x = v1.x - v2.x;
dest.y = v1.y - v2.y; dest.y = v1.y - v2.y;
dest.z = v1.z - v2.z; dest.z = v1.z - v2.z;
} }
public float vdistSqr(Vector3f v1, Vector3f v2) public float VdistSqr(Vector3f v1, Vector3f v2)
{ {
float x = v1.x - v2.x; float x = v1.x - v2.x;
float y = v1.y - v2.y; float y = v1.y - v2.y;
@ -448,49 +448,49 @@ public class DebugDraw
return x * x + y * y + z * z; return x * x + y * y + z * z;
} }
// public static int areaToCol(int area) { // public static int AreaToCol(int area) {
// if (area == 0) { // if (area == 0) {
// return duRGBA(0, 192, 255, 255); // return DuRGBA(0, 192, 255, 255);
// } else { // } else {
// return duIntToCol(area, 255); // return DuIntToCol(area, 255);
// } // }
// } // }
public static int areaToCol(int area) public static int AreaToCol(int area)
{ {
switch (area) switch (area)
{ {
// Ground (0) : light blue // Ground (0) : light blue
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WALKABLE: case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WALKABLE:
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND: case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND:
return duRGBA(0, 192, 255, 255); return DuRGBA(0, 192, 255, 255);
// Water : blue // Water : blue
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER: case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER:
return duRGBA(0, 0, 255, 255); return DuRGBA(0, 0, 255, 255);
// Road : brown // Road : brown
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD: case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD:
return duRGBA(50, 20, 12, 255); return DuRGBA(50, 20, 12, 255);
// Door : cyan // Door : cyan
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_DOOR: case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_DOOR:
return duRGBA(0, 255, 255, 255); return DuRGBA(0, 255, 255, 255);
// Grass : green // Grass : green
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GRASS: case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GRASS:
return duRGBA(0, 255, 0, 255); return DuRGBA(0, 255, 0, 255);
// Jump : yellow // Jump : yellow
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_JUMP: case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_JUMP:
return duRGBA(255, 255, 0, 255); return DuRGBA(255, 255, 0, 255);
// Unexpected : red // Unexpected : red
default: default:
return duRGBA(255, 0, 0, 255); return DuRGBA(255, 0, 0, 255);
} }
} }
public static int duRGBA(int r, int g, int b, int a) public static int DuRGBA(int r, int g, int b, int a)
{ {
return (r) | (g << 8) | (b << 16) | (a << 24); return (r) | (g << 8) | (b << 16) | (a << 24);
} }
public static int duLerpCol(int ca, int cb, int u) public static int DuLerpCol(int ca, int cb, int u)
{ {
int ra = ca & 0xff; int ra = ca & 0xff;
int ga = (ca >> 8) & 0xff; int ga = (ca >> 8) & 0xff;
@ -505,134 +505,134 @@ public class DebugDraw
int g = (ga * (255 - u) + gb * u) / 255; int g = (ga * (255 - u) + gb * u) / 255;
int b = (ba * (255 - u) + bb * u) / 255; int b = (ba * (255 - u) + bb * u) / 255;
int a = (aa * (255 - u) + ab * u) / 255; int a = (aa * (255 - u) + ab * u) / 255;
return duRGBA(r, g, b, a); return DuRGBA(r, g, b, a);
} }
public static int bit(int a, int b) public static int Bit(int a, int b)
{ {
return (a & (1 << b)) >>> b; return (a & (1 << b)) >>> b;
} }
public static int duIntToCol(int i, int a) public static int DuIntToCol(int i, int a)
{ {
int r = bit(i, 1) + bit(i, 3) * 2 + 1; int r = Bit(i, 1) + Bit(i, 3) * 2 + 1;
int g = bit(i, 2) + bit(i, 4) * 2 + 1; int g = Bit(i, 2) + Bit(i, 4) * 2 + 1;
int b = bit(i, 0) + bit(i, 5) * 2 + 1; int b = Bit(i, 0) + Bit(i, 5) * 2 + 1;
return duRGBA(r * 63, g * 63, b * 63, a); return DuRGBA(r * 63, g * 63, b * 63, a);
} }
public static void duCalcBoxColors(int[] colors, int colTop, int colSide) public static void DuCalcBoxColors(int[] colors, int colTop, int colSide)
{ {
colors[0] = duMultCol(colTop, 250); colors[0] = DuMultCol(colTop, 250);
colors[1] = duMultCol(colSide, 140); colors[1] = DuMultCol(colSide, 140);
colors[2] = duMultCol(colSide, 165); colors[2] = DuMultCol(colSide, 165);
colors[3] = duMultCol(colSide, 165); colors[3] = DuMultCol(colSide, 165);
colors[4] = duMultCol(colSide, 217); colors[4] = DuMultCol(colSide, 217);
colors[5] = duMultCol(colSide, 217); colors[5] = DuMultCol(colSide, 217);
} }
public static int duMultCol(int col, int d) public static int DuMultCol(int col, int d)
{ {
int r = col & 0xff; int r = col & 0xff;
int g = (col >> 8) & 0xff; int g = (col >> 8) & 0xff;
int b = (col >> 16) & 0xff; int b = (col >> 16) & 0xff;
int a = (col >> 24) & 0xff; int a = (col >> 24) & 0xff;
return duRGBA((r * d) >> 8, (g * d) >> 8, (b * d) >> 8, a); return DuRGBA((r * d) >> 8, (g * d) >> 8, (b * d) >> 8, a);
} }
public static int duTransCol(int c, int a) public static int DuTransCol(int c, int a)
{ {
return (a << 24) | (c & 0x00ffffff); return (a << 24) | (c & 0x00ffffff);
} }
public static int duDarkenCol(int col) public static int DuDarkenCol(int col)
{ {
return (int)(((col >> 1) & 0x007f7f7f) | (col & 0xff000000)); return (int)(((col >> 1) & 0x007f7f7f) | (col & 0xff000000));
} }
public void fog(float start, float end) public void Fog(float start, float end)
{ {
getOpenGlDraw().fog(start, end); GetOpenGlDraw().Fog(start, end);
} }
public void fog(bool state) public void Fog(bool state)
{ {
getOpenGlDraw().fog(state); GetOpenGlDraw().Fog(state);
} }
public void depthMask(bool state) public void DepthMask(bool state)
{ {
getOpenGlDraw().depthMask(state); GetOpenGlDraw().DepthMask(state);
} }
public void texture(bool state) public void Texture(bool state)
{ {
getOpenGlDraw().texture(g_tex, state); GetOpenGlDraw().Texture(g_tex, state);
} }
public void init(float fogDistance) public void Init(float fogDistance)
{ {
getOpenGlDraw().init(); GetOpenGlDraw().Init();
} }
public void clear() public void Clear()
{ {
getOpenGlDraw().clear(); GetOpenGlDraw().Clear();
} }
public float[] projectionMatrix(float fovy, float aspect, float near, float far) public float[] ProjectionMatrix(float fovy, float aspect, float near, float far)
{ {
GLU.glhPerspectivef2(_projectionMatrix, fovy, aspect, near, far); GLU.GlhPerspectivef2(_projectionMatrix, fovy, aspect, near, far);
getOpenGlDraw().projectionMatrix(_projectionMatrix); GetOpenGlDraw().ProjectionMatrix(_projectionMatrix);
updateFrustum(); UpdateFrustum();
return _projectionMatrix; return _projectionMatrix;
} }
public float[] viewMatrix(Vector3f cameraPos, float[] cameraEulers) public float[] ViewMatrix(Vector3f cameraPos, float[] cameraEulers)
{ {
float[] rx = GLU.build_4x4_rotation_matrix(cameraEulers[0], 1, 0, 0); float[] rx = GLU.Build_4x4_rotation_matrix(cameraEulers[0], 1, 0, 0);
float[] ry = GLU.build_4x4_rotation_matrix(cameraEulers[1], 0, 1, 0); float[] ry = GLU.Build_4x4_rotation_matrix(cameraEulers[1], 0, 1, 0);
float[] r = GLU.mul(rx, ry); float[] r = GLU.Mul(rx, ry);
float[] t = new float[16]; float[] t = new float[16];
t[0] = t[5] = t[10] = t[15] = 1; t[0] = t[5] = t[10] = t[15] = 1;
t[12] = -cameraPos.x; t[12] = -cameraPos.x;
t[13] = -cameraPos.y; t[13] = -cameraPos.y;
t[14] = -cameraPos.z; t[14] = -cameraPos.z;
_viewMatrix = GLU.mul(r, t); _viewMatrix = GLU.Mul(r, t);
getOpenGlDraw().viewMatrix(_viewMatrix); GetOpenGlDraw().ViewMatrix(_viewMatrix);
updateFrustum(); UpdateFrustum();
return _viewMatrix; return _viewMatrix;
} }
private OpenGLDraw getOpenGlDraw() private OpenGLDraw GetOpenGlDraw()
{ {
return openGlDraw; return openGlDraw;
} }
private void updateFrustum() private void UpdateFrustum()
{ {
float[] vpm = GLU.mul(_projectionMatrix, _viewMatrix); float[] vpm = GLU.Mul(_projectionMatrix, _viewMatrix);
// left // left
frustumPlanes[0] = normalizePlane(vpm[0 + 3] + vpm[0 + 0], vpm[4 + 3] + vpm[4 + 0], vpm[8 + 3] + vpm[8 + 0], frustumPlanes[0] = NormalizePlane(vpm[0 + 3] + vpm[0 + 0], vpm[4 + 3] + vpm[4 + 0], vpm[8 + 3] + vpm[8 + 0],
vpm[12 + 3] + vpm[12 + 0]); vpm[12 + 3] + vpm[12 + 0]);
// right // right
frustumPlanes[1] = normalizePlane(vpm[0 + 3] - vpm[0 + 0], vpm[4 + 3] - vpm[4 + 0], vpm[8 + 3] - vpm[8 + 0], frustumPlanes[1] = NormalizePlane(vpm[0 + 3] - vpm[0 + 0], vpm[4 + 3] - vpm[4 + 0], vpm[8 + 3] - vpm[8 + 0],
vpm[12 + 3] - vpm[12 + 0]); vpm[12 + 3] - vpm[12 + 0]);
// top // top
frustumPlanes[2] = normalizePlane(vpm[0 + 3] - vpm[0 + 1], vpm[4 + 3] - vpm[4 + 1], vpm[8 + 3] - vpm[8 + 1], frustumPlanes[2] = NormalizePlane(vpm[0 + 3] - vpm[0 + 1], vpm[4 + 3] - vpm[4 + 1], vpm[8 + 3] - vpm[8 + 1],
vpm[12 + 3] - vpm[12 + 1]); vpm[12 + 3] - vpm[12 + 1]);
// bottom // bottom
frustumPlanes[3] = normalizePlane(vpm[0 + 3] + vpm[0 + 1], vpm[4 + 3] + vpm[4 + 1], vpm[8 + 3] + vpm[8 + 1], frustumPlanes[3] = NormalizePlane(vpm[0 + 3] + vpm[0 + 1], vpm[4 + 3] + vpm[4 + 1], vpm[8 + 3] + vpm[8 + 1],
vpm[12 + 3] + vpm[12 + 1]); vpm[12 + 3] + vpm[12 + 1]);
// near // near
frustumPlanes[4] = normalizePlane(vpm[0 + 3] + vpm[0 + 2], vpm[4 + 3] + vpm[4 + 2], vpm[8 + 3] + vpm[8 + 2], frustumPlanes[4] = NormalizePlane(vpm[0 + 3] + vpm[0 + 2], vpm[4 + 3] + vpm[4 + 2], vpm[8 + 3] + vpm[8 + 2],
vpm[12 + 3] + vpm[12 + 2]); vpm[12 + 3] + vpm[12 + 2]);
// far // far
frustumPlanes[5] = normalizePlane(vpm[0 + 3] - vpm[0 + 2], vpm[4 + 3] - vpm[4 + 2], vpm[8 + 3] - vpm[8 + 2], frustumPlanes[5] = NormalizePlane(vpm[0 + 3] - vpm[0 + 2], vpm[4 + 3] - vpm[4 + 2], vpm[8 + 3] - vpm[8 + 2],
vpm[12 + 3] - vpm[12 + 2]); vpm[12 + 3] - vpm[12 + 2]);
} }
private float[] normalizePlane(float px, float py, float pz, float pw) private float[] NormalizePlane(float px, float py, float pz, float pw)
{ {
float length = (float)Math.Sqrt(px * px + py * py + pz * pz); float length = (float)Math.Sqrt(px * px + py * py + pz * pz);
if (length != 0) if (length != 0)
@ -647,7 +647,7 @@ public class DebugDraw
return new float[] { px, py, pz, pw }; return new float[] { px, py, pz, pw };
} }
public bool frustumTest(float[] bounds) public bool FrustumTest(float[] bounds)
{ {
foreach (float[] plane in frustumPlanes) foreach (float[] plane in frustumPlanes)
{ {
@ -699,8 +699,8 @@ public class DebugDraw
return true; return true;
} }
public bool frustumTest(Vector3f bmin, Vector3f bmax) public bool FrustumTest(Vector3f bmin, Vector3f bmax)
{ {
return frustumTest(new float[] { bmin.x, bmin.y, bmin.z, bmax.x, bmax.y, bmax.z }); return FrustumTest(new float[] { bmin.x, bmin.y, bmin.z, bmax.x, bmax.y, bmax.z });
} }
} }

View File

@ -32,7 +32,7 @@ public class GLCheckerTexture
_gl = gl; _gl = gl;
} }
public void release() public void Release()
{ {
if (m_texId != 0) if (m_texId != 0)
{ {
@ -40,13 +40,13 @@ public class GLCheckerTexture
} }
} }
public void bind() public void Bind()
{ {
if (m_texId == 0) if (m_texId == 0)
{ {
// Create checker pattern. // Create checker pattern.
int col0 = DebugDraw.duRGBA(215, 215, 215, 255); int col0 = DebugDraw.DuRGBA(215, 215, 215, 255);
int col1 = DebugDraw.duRGBA(255, 255, 255, 255); int col1 = DebugDraw.DuRGBA(255, 255, 255, 255);
uint TSIZE = 64; uint TSIZE = 64;
int[] data = new int[TSIZE * TSIZE]; int[] data = new int[TSIZE * TSIZE];

View File

@ -24,24 +24,24 @@ namespace DotRecast.Recast.Demo.Draw;
public class GLU public class GLU
{ {
public static float[] gluPerspective(float fovy, float aspect, float near, float far) public static float[] GluPerspective(float fovy, float aspect, float near, float far)
{ {
float[] projectionMatrix = new float[16]; float[] projectionMatrix = new float[16];
glhPerspectivef2(projectionMatrix, fovy, aspect, near, far); GlhPerspectivef2(projectionMatrix, fovy, aspect, near, far);
//glLoadMatrixf(projectionMatrix); //GlLoadMatrixf(projectionMatrix);
return projectionMatrix; return projectionMatrix;
} }
public static void glhPerspectivef2(float[] matrix, float fovyInDegrees, float aspectRatio, float znear, public static void GlhPerspectivef2(float[] matrix, float fovyInDegrees, float aspectRatio, float znear,
float zfar) float zfar)
{ {
float ymax, xmax; float ymax, xmax;
ymax = (float)(znear * Math.Tan(fovyInDegrees * Math.PI / 360.0)); ymax = (float)(znear * Math.Tan(fovyInDegrees * Math.PI / 360.0));
xmax = ymax * aspectRatio; xmax = ymax * aspectRatio;
glhFrustumf2(matrix, -xmax, xmax, -ymax, ymax, znear, zfar); GlhFrustumf2(matrix, -xmax, xmax, -ymax, ymax, znear, zfar);
} }
private static void glhFrustumf2(float[] matrix, float left, float right, float bottom, float top, float znear, private static void GlhFrustumf2(float[] matrix, float left, float right, float bottom, float top, float znear,
float zfar) float zfar)
{ {
float temp, temp2, temp3, temp4; float temp, temp2, temp3, temp4;
@ -67,7 +67,7 @@ public class GLU
matrix[15] = 0.0f; matrix[15] = 0.0f;
} }
public static int glhUnProjectf(float winx, float winy, float winz, float[] modelview, float[] projection, int[] viewport, ref Vector3f objectCoordinate) public static int GlhUnProjectf(float winx, float winy, float winz, float[] modelview, float[] projection, int[] viewport, ref Vector3f objectCoordinate)
{ {
// Transformation matrices // Transformation matrices
float[] m = new float[16], A = new float[16]; float[] m = new float[16], A = new float[16];
@ -76,7 +76,7 @@ public class GLU
// and store in A[16] // and store in A[16]
MultiplyMatrices4by4OpenGL_FLOAT(A, projection, modelview); MultiplyMatrices4by4OpenGL_FLOAT(A, projection, modelview);
// Now compute the inverse of matrix A // Now compute the inverse of matrix A
if (glhInvertMatrixf2(A, m) == 0) if (GlhInvertMatrixf2(A, m) == 0)
return 0; return 0;
// Transformation of normalized coordinates between -1 and 1 // Transformation of normalized coordinates between -1 and 1
@in[0] = (winx - viewport[0]) / viewport[2] * 2.0f - 1.0f; @in[0] = (winx - viewport[0]) / viewport[2] * 2.0f - 1.0f;
@ -126,7 +126,7 @@ public class GLU
} }
// This code comes directly from GLU except that it is for float // This code comes directly from GLU except that it is for float
static int glhInvertMatrixf2(float[] m, float[] @out) static int GlhInvertMatrixf2(float[] m, float[] @out)
{ {
float[][] wtmp = ArrayUtils.Of<float>(4, 8); float[][] wtmp = ArrayUtils.Of<float>(4, 8);
float m0, m1, m2, m3, s; float m0, m1, m2, m3, s;
@ -370,7 +370,7 @@ public class GLU
m[(c) * 4 + (r)] = v; m[(c) * 4 + (r)] = v;
} }
public static float[] build_4x4_rotation_matrix(float a, float x, float y, float z) public static float[] Build_4x4_rotation_matrix(float a, float x, float y, float z)
{ {
float[] matrix = new float[16]; float[] matrix = new float[16];
a = (float)(a * Math.PI / 180.0); // convert to radians a = (float)(a * Math.PI / 180.0); // convert to radians
@ -408,7 +408,7 @@ public class GLU
return matrix; return matrix;
} }
public static float[] mul(float[] left, float[] right) public static float[] Mul(float[] left, float[] right)
{ {
float m00 = left[0] * right[0] + left[4] * right[1] + left[8] * right[2] + left[12] * right[3]; float m00 = left[0] * right[0] + left[4] * right[1] + left[8] * right[2] + left[12] * right[3];
float m01 = left[1] * right[0] + left[5] * right[1] + left[9] * right[2] + left[13] * right[3]; float m01 = left[1] * right[0] + left[5] * right[1] + left[9] * right[2] + left[13] * right[3];

View File

@ -35,7 +35,7 @@ public class ModernOpenGLDraw : OpenGLDraw
_gl = gl; _gl = gl;
} }
public unsafe void init() public unsafe void Init()
{ {
string SHADER_VERSION = "#version 400\n"; string SHADER_VERSION = "#version 400\n";
string vertex_shader = SHADER_VERSION + "uniform mat4 ProjMtx;\n" // string vertex_shader = SHADER_VERSION + "uniform mat4 ProjMtx;\n" //
@ -153,7 +153,7 @@ public class ModernOpenGLDraw : OpenGLDraw
_gl.BindBuffer(GLEnum.ElementArrayBuffer, 0); _gl.BindBuffer(GLEnum.ElementArrayBuffer, 0);
} }
public void clear() public void Clear()
{ {
_gl.ClearColor(0.3f, 0.3f, 0.32f, 1.0f); _gl.ClearColor(0.3f, 0.3f, 0.32f, 1.0f);
_gl.Clear((uint)GLEnum.ColorBufferBit | (uint)GLEnum.DepthBufferBit); _gl.Clear((uint)GLEnum.ColorBufferBit | (uint)GLEnum.DepthBufferBit);
@ -164,7 +164,7 @@ public class ModernOpenGLDraw : OpenGLDraw
_gl.Enable(GLEnum.CullFace); _gl.Enable(GLEnum.CullFace);
} }
public void begin(DebugDrawPrimitives prim, float size) public void Begin(DebugDrawPrimitives prim, float size)
{ {
currentPrim = prim; currentPrim = prim;
vertices.Clear(); vertices.Clear();
@ -172,7 +172,7 @@ public class ModernOpenGLDraw : OpenGLDraw
_gl.PointSize(size); _gl.PointSize(size);
} }
public unsafe void end() public unsafe void End()
{ {
if (0 >= vertices.Count) if (0 >= vertices.Count)
{ {
@ -189,8 +189,8 @@ public class ModernOpenGLDraw : OpenGLDraw
_gl.BindVertexArray(vao); _gl.BindVertexArray(vao);
_gl.BindBuffer(GLEnum.ArrayBuffer, vbo); _gl.BindBuffer(GLEnum.ArrayBuffer, vbo);
_gl.BindBuffer(GLEnum.ElementArrayBuffer, ebo); _gl.BindBuffer(GLEnum.ElementArrayBuffer, ebo);
// glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_BUFFER, GL_STREAM_DRAW); // GlBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_BUFFER, GL_STREAM_DRAW);
// glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_BUFFER, GL_STREAM_DRAW); // GlBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_BUFFER, GL_STREAM_DRAW);
uint vboSize = (uint)vertices.Count * 24; uint vboSize = (uint)vertices.Count * 24;
uint eboSize = currentPrim == DebugDrawPrimitives.QUADS ? (uint)vertices.Count * 6 : (uint)vertices.Count * 4; uint eboSize = currentPrim == DebugDrawPrimitives.QUADS ? (uint)vertices.Count * 6 : (uint)vertices.Count * 4;
@ -203,7 +203,7 @@ public class ModernOpenGLDraw : OpenGLDraw
byte* pVerts = (byte*)_gl.MapBuffer(GLEnum.ArrayBuffer, GLEnum.WriteOnly); byte* pVerts = (byte*)_gl.MapBuffer(GLEnum.ArrayBuffer, GLEnum.WriteOnly);
byte* pElems = (byte*)_gl.MapBuffer(GLEnum.ElementArrayBuffer, GLEnum.WriteOnly); byte* pElems = (byte*)_gl.MapBuffer(GLEnum.ElementArrayBuffer, GLEnum.WriteOnly);
//vertices.forEach(v => v.store(verts)); //vertices.ForEach(v => v.Store(verts));
fixed (void* v = vertices.AsArray()) fixed (void* v = vertices.AsArray())
{ {
System.Buffer.MemoryCopy(v, pVerts, vboSize, vboSize); System.Buffer.MemoryCopy(v, pVerts, vboSize, vboSize);
@ -241,7 +241,7 @@ public class ModernOpenGLDraw : OpenGLDraw
} }
if (_texture != null) if (_texture != null)
{ {
_texture.bind(); _texture.Bind();
_gl.Uniform1(uniformUseTexture, 1.0f); _gl.Uniform1(uniformUseTexture, 1.0f);
} }
else else
@ -276,63 +276,63 @@ public class ModernOpenGLDraw : OpenGLDraw
_gl.PointSize(1.0f); _gl.PointSize(1.0f);
} }
public void vertex(float x, float y, float z, int color) public void Vertex(float x, float y, float z, int color)
{ {
vertices.Add(new OpenGLVertex(x, y, z, color)); vertices.Add(new OpenGLVertex(x, y, z, color));
} }
public void vertex(float[] pos, int color) public void Vertex(float[] pos, int color)
{ {
vertices.Add(new OpenGLVertex(pos, color)); vertices.Add(new OpenGLVertex(pos, color));
} }
public void vertex(Vector3f pos, int color) public void Vertex(Vector3f pos, int color)
{ {
vertices.Add(new OpenGLVertex(pos, color)); vertices.Add(new OpenGLVertex(pos, color));
} }
public void vertex(Vector3f pos, int color, Vector2f uv) public void Vertex(Vector3f pos, int color, Vector2f uv)
{ {
vertices.Add(new OpenGLVertex(pos, uv, color)); vertices.Add(new OpenGLVertex(pos, uv, color));
} }
public void vertex(float x, float y, float z, int color, float u, float v) public void Vertex(float x, float y, float z, int color, float u, float v)
{ {
vertices.Add(new OpenGLVertex(x, y, z, u, v, color)); vertices.Add(new OpenGLVertex(x, y, z, u, v, color));
} }
public void depthMask(bool state) public void DepthMask(bool state)
{ {
_gl.DepthMask(state); _gl.DepthMask(state);
} }
public void texture(GLCheckerTexture g_tex, bool state) public void Texture(GLCheckerTexture g_tex, bool state)
{ {
_texture = state ? g_tex : null; _texture = state ? g_tex : null;
if (_texture != null) if (_texture != null)
{ {
_texture.bind(); _texture.Bind();
} }
} }
public void projectionMatrix(float[] projectionMatrix) public void ProjectionMatrix(float[] projectionMatrix)
{ {
this._projectionMatrix = projectionMatrix; this._projectionMatrix = projectionMatrix;
} }
public void viewMatrix(float[] viewMatrix) public void ViewMatrix(float[] viewMatrix)
{ {
this._viewMatrix = viewMatrix; this._viewMatrix = viewMatrix;
} }
public void fog(float start, float end) public void Fog(float start, float end)
{ {
fogStart = start; fogStart = start;
fogEnd = end; fogEnd = end;
} }
public void fog(bool state) public void Fog(bool state)
{ {
fogEnabled = state; fogEnabled = state;
} }

View File

@ -39,45 +39,45 @@ public class NavMeshRenderer
this.debugDraw = debugDraw; this.debugDraw = debugDraw;
} }
public RecastDebugDraw getDebugDraw() public RecastDebugDraw GetDebugDraw()
{ {
return debugDraw; return debugDraw;
} }
public void render(Sample sample) public void Render(Sample sample)
{ {
if (sample == null) if (sample == null)
{ {
return; return;
} }
NavMeshQuery navQuery = sample.getNavMeshQuery(); NavMeshQuery navQuery = sample.GetNavMeshQuery();
DemoInputGeomProvider geom = sample.getInputGeom(); DemoInputGeomProvider geom = sample.GetInputGeom();
IList<RecastBuilderResult> rcBuilderResults = sample.getRecastResults(); IList<RecastBuilderResult> rcBuilderResults = sample.GetRecastResults();
NavMesh navMesh = sample.getNavMesh(); NavMesh navMesh = sample.GetNavMesh();
RcSettingsView rcSettingsView = sample.getSettingsUI(); RcSettingsView rcSettingsView = sample.GetSettingsUI();
debugDraw.fog(true); debugDraw.Fog(true);
debugDraw.depthMask(true); debugDraw.DepthMask(true);
var drawMode = rcSettingsView.getDrawMode(); var drawMode = rcSettingsView.GetDrawMode();
float texScale = 1.0f / (rcSettingsView.getCellSize() * 10.0f); float texScale = 1.0f / (rcSettingsView.GetCellSize() * 10.0f);
float m_agentMaxSlope = rcSettingsView.getAgentMaxSlope(); float m_agentMaxSlope = rcSettingsView.GetAgentMaxSlope();
if (drawMode != DrawMode.DRAWMODE_NAVMESH_TRANS) if (drawMode != DrawMode.DRAWMODE_NAVMESH_TRANS)
{ {
// Draw mesh // Draw mesh
if (geom != null) if (geom != null)
{ {
debugDraw.debugDrawTriMeshSlope(geom.vertices, geom.faces, geom.normals, m_agentMaxSlope, texScale); debugDraw.DebugDrawTriMeshSlope(geom.vertices, geom.faces, geom.normals, m_agentMaxSlope, texScale);
drawOffMeshConnections(geom, false); DrawOffMeshConnections(geom, false);
} }
} }
debugDraw.fog(false); debugDraw.Fog(false);
debugDraw.depthMask(false); debugDraw.DepthMask(false);
if (geom != null) if (geom != null)
{ {
drawGeomBounds(geom); DrawGeomBounds(geom);
} }
if (navMesh != null && navQuery != null if (navMesh != null && navQuery != null
@ -88,221 +88,221 @@ public class NavMeshRenderer
{ {
if (drawMode != DrawMode.DRAWMODE_NAVMESH_INVIS) if (drawMode != DrawMode.DRAWMODE_NAVMESH_INVIS)
{ {
debugDraw.debugDrawNavMeshWithClosedList(navMesh, navQuery, navMeshDrawFlags); debugDraw.DebugDrawNavMeshWithClosedList(navMesh, navQuery, navMeshDrawFlags);
} }
if (drawMode == DrawMode.DRAWMODE_NAVMESH_BVTREE) if (drawMode == DrawMode.DRAWMODE_NAVMESH_BVTREE)
{ {
debugDraw.debugDrawNavMeshBVTree(navMesh); debugDraw.DebugDrawNavMeshBVTree(navMesh);
} }
if (drawMode == DrawMode.DRAWMODE_NAVMESH_PORTALS) if (drawMode == DrawMode.DRAWMODE_NAVMESH_PORTALS)
{ {
debugDraw.debugDrawNavMeshPortals(navMesh); debugDraw.DebugDrawNavMeshPortals(navMesh);
} }
if (drawMode == DrawMode.DRAWMODE_NAVMESH_NODES) if (drawMode == DrawMode.DRAWMODE_NAVMESH_NODES)
{ {
debugDraw.debugDrawNavMeshNodes(navQuery); debugDraw.DebugDrawNavMeshNodes(navQuery);
debugDraw.debugDrawNavMeshPolysWithFlags(navMesh, SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED, debugDraw.DebugDrawNavMeshPolysWithFlags(navMesh, SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED,
DebugDraw.duRGBA(0, 0, 0, 128)); DebugDraw.DuRGBA(0, 0, 0, 128));
} }
} }
debugDraw.depthMask(true); debugDraw.DepthMask(true);
foreach (RecastBuilderResult rcBuilderResult in rcBuilderResults) foreach (RecastBuilderResult rcBuilderResult in rcBuilderResults)
{ {
if (rcBuilderResult.getCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT) if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT)
{ {
debugDraw.debugDrawCompactHeightfieldSolid(rcBuilderResult.getCompactHeightfield()); debugDraw.DebugDrawCompactHeightfieldSolid(rcBuilderResult.GetCompactHeightfield());
} }
if (rcBuilderResult.getCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT_DISTANCE) if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT_DISTANCE)
{ {
debugDraw.debugDrawCompactHeightfieldDistance(rcBuilderResult.getCompactHeightfield()); debugDraw.DebugDrawCompactHeightfieldDistance(rcBuilderResult.GetCompactHeightfield());
} }
if (rcBuilderResult.getCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT_REGIONS) if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT_REGIONS)
{ {
debugDraw.debugDrawCompactHeightfieldRegions(rcBuilderResult.getCompactHeightfield()); debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.GetCompactHeightfield());
} }
if (rcBuilderResult.getSolidHeightfield() != null && drawMode == DrawMode.DRAWMODE_VOXELS) if (rcBuilderResult.GetSolidHeightfield() != null && drawMode == DrawMode.DRAWMODE_VOXELS)
{ {
debugDraw.fog(true); debugDraw.Fog(true);
debugDraw.debugDrawHeightfieldSolid(rcBuilderResult.getSolidHeightfield()); debugDraw.DebugDrawHeightfieldSolid(rcBuilderResult.GetSolidHeightfield());
debugDraw.fog(false); debugDraw.Fog(false);
} }
if (rcBuilderResult.getSolidHeightfield() != null && drawMode == DrawMode.DRAWMODE_VOXELS_WALKABLE) if (rcBuilderResult.GetSolidHeightfield() != null && drawMode == DrawMode.DRAWMODE_VOXELS_WALKABLE)
{ {
debugDraw.fog(true); debugDraw.Fog(true);
debugDraw.debugDrawHeightfieldWalkable(rcBuilderResult.getSolidHeightfield()); debugDraw.DebugDrawHeightfieldWalkable(rcBuilderResult.GetSolidHeightfield());
debugDraw.fog(false); debugDraw.Fog(false);
} }
if (rcBuilderResult.getContourSet() != null && drawMode == DrawMode.DRAWMODE_RAW_CONTOURS) if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_RAW_CONTOURS)
{ {
debugDraw.depthMask(false); debugDraw.DepthMask(false);
debugDraw.debugDrawRawContours(rcBuilderResult.getContourSet(), 1f); debugDraw.DebugDrawRawContours(rcBuilderResult.GetContourSet(), 1f);
debugDraw.depthMask(true); debugDraw.DepthMask(true);
} }
if (rcBuilderResult.getContourSet() != null && drawMode == DrawMode.DRAWMODE_BOTH_CONTOURS) if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_BOTH_CONTOURS)
{ {
debugDraw.depthMask(false); debugDraw.DepthMask(false);
debugDraw.debugDrawRawContours(rcBuilderResult.getContourSet(), 0.5f); debugDraw.DebugDrawRawContours(rcBuilderResult.GetContourSet(), 0.5f);
debugDraw.debugDrawContours(rcBuilderResult.getContourSet()); debugDraw.DebugDrawContours(rcBuilderResult.GetContourSet());
debugDraw.depthMask(true); debugDraw.DepthMask(true);
} }
if (rcBuilderResult.getContourSet() != null && drawMode == DrawMode.DRAWMODE_CONTOURS) if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_CONTOURS)
{ {
debugDraw.depthMask(false); debugDraw.DepthMask(false);
debugDraw.debugDrawContours(rcBuilderResult.getContourSet()); debugDraw.DebugDrawContours(rcBuilderResult.GetContourSet());
debugDraw.depthMask(true); debugDraw.DepthMask(true);
} }
if (rcBuilderResult.getCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_REGION_CONNECTIONS) if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_REGION_CONNECTIONS)
{ {
debugDraw.debugDrawCompactHeightfieldRegions(rcBuilderResult.getCompactHeightfield()); debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.GetCompactHeightfield());
debugDraw.depthMask(false); debugDraw.DepthMask(false);
if (rcBuilderResult.getContourSet() != null) if (rcBuilderResult.GetContourSet() != null)
{ {
debugDraw.debugDrawRegionConnections(rcBuilderResult.getContourSet()); debugDraw.DebugDrawRegionConnections(rcBuilderResult.GetContourSet());
} }
debugDraw.depthMask(true); debugDraw.DepthMask(true);
} }
if (rcBuilderResult.getMesh() != null && drawMode == DrawMode.DRAWMODE_POLYMESH) if (rcBuilderResult.GetMesh() != null && drawMode == DrawMode.DRAWMODE_POLYMESH)
{ {
debugDraw.depthMask(false); debugDraw.DepthMask(false);
debugDraw.debugDrawPolyMesh(rcBuilderResult.getMesh()); debugDraw.DebugDrawPolyMesh(rcBuilderResult.GetMesh());
debugDraw.depthMask(true); debugDraw.DepthMask(true);
} }
if (rcBuilderResult.getMeshDetail() != null && drawMode == DrawMode.DRAWMODE_POLYMESH_DETAIL) if (rcBuilderResult.GetMeshDetail() != null && drawMode == DrawMode.DRAWMODE_POLYMESH_DETAIL)
{ {
debugDraw.depthMask(false); debugDraw.DepthMask(false);
debugDraw.debugDrawPolyMeshDetail(rcBuilderResult.getMeshDetail()); debugDraw.DebugDrawPolyMeshDetail(rcBuilderResult.GetMeshDetail());
debugDraw.depthMask(true); debugDraw.DepthMask(true);
} }
} }
if (geom != null) if (geom != null)
{ {
drawConvexVolumes(geom); DrawConvexVolumes(geom);
} }
} }
private void drawGeomBounds(DemoInputGeomProvider geom) private void DrawGeomBounds(DemoInputGeomProvider geom)
{ {
// Draw bounds // Draw bounds
Vector3f bmin = geom.getMeshBoundsMin(); Vector3f bmin = geom.GetMeshBoundsMin();
Vector3f bmax = geom.getMeshBoundsMax(); Vector3f bmax = geom.GetMeshBoundsMax();
debugDraw.debugDrawBoxWire(bmin.x, bmin.y, bmin.z, bmax.x, bmax.y, bmax.z, debugDraw.DebugDrawBoxWire(bmin.x, bmin.y, bmin.z, bmax.x, bmax.y, bmax.z,
DebugDraw.duRGBA(255, 255, 255, 128), 1.0f); DebugDraw.DuRGBA(255, 255, 255, 128), 1.0f);
debugDraw.begin(DebugDrawPrimitives.POINTS, 5.0f); debugDraw.Begin(DebugDrawPrimitives.POINTS, 5.0f);
debugDraw.vertex(bmin.x, bmin.y, bmin.z, DebugDraw.duRGBA(255, 255, 255, 128)); debugDraw.Vertex(bmin.x, bmin.y, bmin.z, DebugDraw.DuRGBA(255, 255, 255, 128));
debugDraw.end(); debugDraw.End();
} }
public void drawOffMeshConnections(DemoInputGeomProvider geom, bool hilight) public void DrawOffMeshConnections(DemoInputGeomProvider geom, bool hilight)
{ {
int conColor = DebugDraw.duRGBA(192, 0, 128, 192); int conColor = DebugDraw.DuRGBA(192, 0, 128, 192);
int baseColor = DebugDraw.duRGBA(0, 0, 0, 64); int baseColor = DebugDraw.DuRGBA(0, 0, 0, 64);
debugDraw.depthMask(false); debugDraw.DepthMask(false);
debugDraw.begin(DebugDrawPrimitives.LINES, 2.0f); debugDraw.Begin(DebugDrawPrimitives.LINES, 2.0f);
foreach (DemoOffMeshConnection con in geom.getOffMeshConnections()) foreach (DemoOffMeshConnection con in geom.GetOffMeshConnections())
{ {
float[] v = con.verts; float[] v = con.verts;
debugDraw.vertex(v[0], v[1], v[2], baseColor); debugDraw.Vertex(v[0], v[1], v[2], baseColor);
debugDraw.vertex(v[0], v[1] + 0.2f, v[2], baseColor); debugDraw.Vertex(v[0], v[1] + 0.2f, v[2], baseColor);
debugDraw.vertex(v[3], v[4], v[5], baseColor); debugDraw.Vertex(v[3], v[4], v[5], baseColor);
debugDraw.vertex(v[3], v[4] + 0.2f, v[5], baseColor); debugDraw.Vertex(v[3], v[4] + 0.2f, v[5], baseColor);
debugDraw.appendCircle(v[0], v[1] + 0.1f, v[2], con.radius, baseColor); debugDraw.AppendCircle(v[0], v[1] + 0.1f, v[2], con.radius, baseColor);
debugDraw.appendCircle(v[3], v[4] + 0.1f, v[5], con.radius, baseColor); debugDraw.AppendCircle(v[3], v[4] + 0.1f, v[5], con.radius, baseColor);
if (hilight) if (hilight)
{ {
debugDraw.appendArc(v[0], v[1], v[2], v[3], v[4], v[5], 0.25f, con.bidir ? 0.6f : 0.0f, 0.6f, conColor); debugDraw.AppendArc(v[0], v[1], v[2], v[3], v[4], v[5], 0.25f, con.bidir ? 0.6f : 0.0f, 0.6f, conColor);
} }
} }
debugDraw.end(); debugDraw.End();
debugDraw.depthMask(true); debugDraw.DepthMask(true);
} }
void drawConvexVolumes(DemoInputGeomProvider geom) void DrawConvexVolumes(DemoInputGeomProvider geom)
{ {
debugDraw.depthMask(false); debugDraw.DepthMask(false);
debugDraw.begin(DebugDrawPrimitives.TRIS); debugDraw.Begin(DebugDrawPrimitives.TRIS);
foreach (ConvexVolume vol in geom.convexVolumes()) foreach (ConvexVolume vol in geom.ConvexVolumes())
{ {
int col = DebugDraw.duTransCol(DebugDraw.areaToCol(vol.areaMod.getMaskedValue()), 32); int col = DebugDraw.DuTransCol(DebugDraw.AreaToCol(vol.areaMod.GetMaskedValue()), 32);
for (int j = 0, k = vol.verts.Length - 3; j < vol.verts.Length; k = j, j += 3) for (int j = 0, k = vol.verts.Length - 3; j < vol.verts.Length; k = j, j += 3)
{ {
var va = Vector3f.Of(vol.verts[k], vol.verts[k + 1], vol.verts[k + 2]); var va = Vector3f.Of(vol.verts[k], vol.verts[k + 1], vol.verts[k + 2]);
var vb = Vector3f.Of(vol.verts[j], vol.verts[j + 1], vol.verts[j + 2]); var vb = Vector3f.Of(vol.verts[j], vol.verts[j + 1], vol.verts[j + 2]);
debugDraw.vertex(vol.verts[0], vol.hmax, vol.verts[2], col); debugDraw.Vertex(vol.verts[0], vol.hmax, vol.verts[2], col);
debugDraw.vertex(vb.x, vol.hmax, vb.z, col); debugDraw.Vertex(vb.x, vol.hmax, vb.z, col);
debugDraw.vertex(va.x, vol.hmax, va.z, col); debugDraw.Vertex(va.x, vol.hmax, va.z, col);
debugDraw.vertex(va.x, vol.hmin, va.z, DebugDraw.duDarkenCol(col)); debugDraw.Vertex(va.x, vol.hmin, va.z, DebugDraw.DuDarkenCol(col));
debugDraw.vertex(va.x, vol.hmax, va.z, col); debugDraw.Vertex(va.x, vol.hmax, va.z, col);
debugDraw.vertex(vb.x, vol.hmax, vb.z, col); debugDraw.Vertex(vb.x, vol.hmax, vb.z, col);
debugDraw.vertex(va.x, vol.hmin, va.z, DebugDraw.duDarkenCol(col)); debugDraw.Vertex(va.x, vol.hmin, va.z, DebugDraw.DuDarkenCol(col));
debugDraw.vertex(vb.x, vol.hmax, vb.z, col); debugDraw.Vertex(vb.x, vol.hmax, vb.z, col);
debugDraw.vertex(vb.x, vol.hmin, vb.z, DebugDraw.duDarkenCol(col)); debugDraw.Vertex(vb.x, vol.hmin, vb.z, DebugDraw.DuDarkenCol(col));
} }
} }
debugDraw.end(); debugDraw.End();
debugDraw.begin(DebugDrawPrimitives.LINES, 2.0f); debugDraw.Begin(DebugDrawPrimitives.LINES, 2.0f);
foreach (ConvexVolume vol in geom.convexVolumes()) foreach (ConvexVolume vol in geom.ConvexVolumes())
{ {
int col = DebugDraw.duTransCol(DebugDraw.areaToCol(vol.areaMod.getMaskedValue()), 220); int col = DebugDraw.DuTransCol(DebugDraw.AreaToCol(vol.areaMod.GetMaskedValue()), 220);
for (int j = 0, k = vol.verts.Length - 3; j < vol.verts.Length; k = j, j += 3) for (int j = 0, k = vol.verts.Length - 3; j < vol.verts.Length; k = j, j += 3)
{ {
var va = Vector3f.Of(vol.verts[k], vol.verts[k + 1], vol.verts[k + 2]); var va = Vector3f.Of(vol.verts[k], vol.verts[k + 1], vol.verts[k + 2]);
var vb = Vector3f.Of(vol.verts[j], vol.verts[j + 1], vol.verts[j + 2]); var vb = Vector3f.Of(vol.verts[j], vol.verts[j + 1], vol.verts[j + 2]);
debugDraw.vertex(va.x, vol.hmin, va.z, DebugDraw.duDarkenCol(col)); debugDraw.Vertex(va.x, vol.hmin, va.z, DebugDraw.DuDarkenCol(col));
debugDraw.vertex(vb.x, vol.hmin, vb.z, DebugDraw.duDarkenCol(col)); debugDraw.Vertex(vb.x, vol.hmin, vb.z, DebugDraw.DuDarkenCol(col));
debugDraw.vertex(va.x, vol.hmax, va.z, col); debugDraw.Vertex(va.x, vol.hmax, va.z, col);
debugDraw.vertex(vb.x, vol.hmax, vb.z, col); debugDraw.Vertex(vb.x, vol.hmax, vb.z, col);
debugDraw.vertex(va.x, vol.hmin, va.z, DebugDraw.duDarkenCol(col)); debugDraw.Vertex(va.x, vol.hmin, va.z, DebugDraw.DuDarkenCol(col));
debugDraw.vertex(va.x, vol.hmax, va.z, col); debugDraw.Vertex(va.x, vol.hmax, va.z, col);
} }
} }
debugDraw.end(); debugDraw.End();
debugDraw.begin(DebugDrawPrimitives.POINTS, 3.0f); debugDraw.Begin(DebugDrawPrimitives.POINTS, 3.0f);
foreach (ConvexVolume vol in geom.convexVolumes()) foreach (ConvexVolume vol in geom.ConvexVolumes())
{ {
int col = DebugDraw int col = DebugDraw
.duDarkenCol(DebugDraw.duTransCol(DebugDraw.areaToCol(vol.areaMod.getMaskedValue()), 220)); .DuDarkenCol(DebugDraw.DuTransCol(DebugDraw.AreaToCol(vol.areaMod.GetMaskedValue()), 220));
for (int j = 0; j < vol.verts.Length; j += 3) for (int j = 0; j < vol.verts.Length; j += 3)
{ {
debugDraw.vertex(vol.verts[j + 0], vol.verts[j + 1] + 0.1f, vol.verts[j + 2], col); debugDraw.Vertex(vol.verts[j + 0], vol.verts[j + 1] + 0.1f, vol.verts[j + 2], col);
debugDraw.vertex(vol.verts[j + 0], vol.hmin, vol.verts[j + 2], col); debugDraw.Vertex(vol.verts[j + 0], vol.hmin, vol.verts[j + 2], col);
debugDraw.vertex(vol.verts[j + 0], vol.hmax, vol.verts[j + 2], col); debugDraw.Vertex(vol.verts[j + 0], vol.hmax, vol.verts[j + 2], col);
} }
} }
debugDraw.end(); debugDraw.End();
debugDraw.depthMask(true); debugDraw.DepthMask(true);
} }
} }

View File

@ -5,32 +5,32 @@ namespace DotRecast.Recast.Demo.Draw;
public interface OpenGLDraw public interface OpenGLDraw
{ {
void init(); void Init();
void clear(); void Clear();
void begin(DebugDrawPrimitives prim, float size); void Begin(DebugDrawPrimitives prim, float size);
void end(); void End();
void vertex(float x, float y, float z, int color); void Vertex(float x, float y, float z, int color);
void vertex(float[] pos, int color); void Vertex(float[] pos, int color);
void vertex(Vector3f pos, int color); void Vertex(Vector3f pos, int color);
void vertex(Vector3f pos, int color, Vector2f uv); void Vertex(Vector3f pos, int color, Vector2f uv);
void vertex(float x, float y, float z, int color, float u, float v); void Vertex(float x, float y, float z, int color, float u, float v);
void fog(bool state); void Fog(bool state);
void depthMask(bool state); void DepthMask(bool state);
void texture(GLCheckerTexture g_tex, bool state); void Texture(GLCheckerTexture g_tex, bool state);
void projectionMatrix(float[] projectionMatrix); void ProjectionMatrix(float[] projectionMatrix);
void viewMatrix(float[] viewMatrix); void ViewMatrix(float[] viewMatrix);
void fog(float start, float end); void Fog(float start, float end);
} }

View File

@ -46,7 +46,7 @@ public struct OpenGLVertex
this.color = color; this.color = color;
} }
public void store(BinaryWriter writer) public void Store(BinaryWriter writer)
{ {
// writer.Write(BitConverter.GetBytes(x)); // writer.Write(BitConverter.GetBytes(x));
// writer.Write(BitConverter.GetBytes(y)); // writer.Write(BitConverter.GetBytes(y));

File diff suppressed because it is too large Load Diff

View File

@ -39,11 +39,11 @@ public class DemoInputGeomProvider : InputGeomProvider
private readonly TriMesh _mesh; private readonly TriMesh _mesh;
public DemoInputGeomProvider(List<float> vertexPositions, List<int> meshFaces) : public DemoInputGeomProvider(List<float> vertexPositions, List<int> meshFaces) :
this(mapVertices(vertexPositions), mapFaces(meshFaces)) this(MapVertices(vertexPositions), MapFaces(meshFaces))
{ {
} }
private static int[] mapFaces(List<int> meshFaces) private static int[] MapFaces(List<int> meshFaces)
{ {
int[] faces = new int[meshFaces.Count]; int[] faces = new int[meshFaces.Count];
for (int i = 0; i < faces.Length; i++) for (int i = 0; i < faces.Length; i++)
@ -54,7 +54,7 @@ public class DemoInputGeomProvider : InputGeomProvider
return faces; return faces;
} }
private static float[] mapVertices(List<float> vertexPositions) private static float[] MapVertices(List<float> vertexPositions)
{ {
float[] vertices = new float[vertexPositions.Count]; float[] vertices = new float[vertexPositions.Count];
for (int i = 0; i < vertices.Length; i++) for (int i = 0; i < vertices.Length; i++)
@ -70,31 +70,31 @@ public class DemoInputGeomProvider : InputGeomProvider
this.vertices = vertices; this.vertices = vertices;
this.faces = faces; this.faces = faces;
normals = new float[faces.Length]; normals = new float[faces.Length];
calculateNormals(); CalculateNormals();
bmin = Vector3f.Zero; bmin = Vector3f.Zero;
bmax = Vector3f.Zero; bmax = Vector3f.Zero;
RecastVectors.copy(ref bmin, vertices, 0); RecastVectors.Copy(ref bmin, vertices, 0);
RecastVectors.copy(ref bmax, vertices, 0); RecastVectors.Copy(ref bmax, vertices, 0);
for (int i = 1; i < vertices.Length / 3; i++) for (int i = 1; i < vertices.Length / 3; i++)
{ {
RecastVectors.min(ref bmin, vertices, i * 3); RecastVectors.Min(ref bmin, vertices, i * 3);
RecastVectors.max(ref bmax, vertices, i * 3); RecastVectors.Max(ref bmax, vertices, i * 3);
} }
_mesh = new TriMesh(vertices, faces); _mesh = new TriMesh(vertices, faces);
} }
public Vector3f getMeshBoundsMin() public Vector3f GetMeshBoundsMin()
{ {
return bmin; return bmin;
} }
public Vector3f getMeshBoundsMax() public Vector3f GetMeshBoundsMax()
{ {
return bmax; return bmax;
} }
public void calculateNormals() public void CalculateNormals()
{ {
for (int i = 0; i < faces.Length; i += 3) for (int i = 0; i < faces.Length; i += 3)
{ {
@ -123,36 +123,36 @@ public class DemoInputGeomProvider : InputGeomProvider
} }
} }
public IList<ConvexVolume> convexVolumes() public IList<ConvexVolume> ConvexVolumes()
{ {
return _convexVolumes; return _convexVolumes;
} }
public IEnumerable<TriMesh> meshes() public IEnumerable<TriMesh> Meshes()
{ {
return ImmutableArray.Create(_mesh); return ImmutableArray.Create(_mesh);
} }
public List<DemoOffMeshConnection> getOffMeshConnections() public List<DemoOffMeshConnection> GetOffMeshConnections()
{ {
return offMeshConnections; return offMeshConnections;
} }
public void addOffMeshConnection(Vector3f start, Vector3f end, float radius, bool bidir, int area, int flags) public void AddOffMeshConnection(Vector3f start, Vector3f end, float radius, bool bidir, int area, int flags)
{ {
offMeshConnections.Add(new DemoOffMeshConnection(start, end, radius, bidir, area, flags)); offMeshConnections.Add(new DemoOffMeshConnection(start, end, radius, bidir, area, flags));
} }
public void removeOffMeshConnections(Predicate<DemoOffMeshConnection> filter) public void RemoveOffMeshConnections(Predicate<DemoOffMeshConnection> filter)
{ {
//offMeshConnections.retainAll(offMeshConnections.stream().filter(c -> !filter.test(c)).collect(toList())); //offMeshConnections.RetainAll(offMeshConnections.Stream().Filter(c -> !filter.Test(c)).Collect(ToList()));
offMeshConnections.RemoveAll(filter); // TODO : 확인 필요 offMeshConnections.RemoveAll(filter); // TODO : 확인 필요
} }
public float? raycastMesh(Vector3f src, Vector3f dst) public float? RaycastMesh(Vector3f src, Vector3f dst)
{ {
// Prune hit ray. // Prune hit ray.
float[] btminmax = Intersections.intersectSegmentAABB(src, dst, bmin, bmax); float[] btminmax = Intersections.IntersectSegmentAABB(src, dst, bmin, bmax);
if (null == btminmax) if (null == btminmax)
{ {
return null; return null;
@ -166,7 +166,7 @@ public class DemoInputGeomProvider : InputGeomProvider
q[0] = src.x + (dst.x - src.x) * btmax; q[0] = src.x + (dst.x - src.x) * btmax;
q[1] = src.z + (dst.z - src.z) * btmax; q[1] = src.z + (dst.z - src.z) * btmax;
List<ChunkyTriMeshNode> chunks = _mesh.chunkyTriMesh.getChunksOverlappingSegment(p, q); List<ChunkyTriMeshNode> chunks = _mesh.chunkyTriMesh.GetChunksOverlappingSegment(p, q);
if (0 == chunks.Count) if (0 == chunks.Count)
{ {
return null; return null;
@ -194,7 +194,7 @@ public class DemoInputGeomProvider : InputGeomProvider
vertices[tris[j + 2] * 3 + 1], vertices[tris[j + 2] * 3 + 1],
vertices[tris[j + 2] * 3 + 2] vertices[tris[j + 2] * 3 + 2]
); );
float? t = Intersections.intersectSegmentTriangle(src, dst, v1, v2, v3); float? t = Intersections.IntersectSegmentTriangle(src, dst, v1, v2, v3);
if (null != t) if (null != t)
{ {
if (t.Value < tmin) if (t.Value < tmin)
@ -211,7 +211,7 @@ public class DemoInputGeomProvider : InputGeomProvider
} }
public void addConvexVolume(float[] verts, float minh, float maxh, AreaModification areaMod) public void AddConvexVolume(float[] verts, float minh, float maxh, AreaModification areaMod)
{ {
ConvexVolume volume = new ConvexVolume(); ConvexVolume volume = new ConvexVolume();
volume.verts = verts; volume.verts = verts;
@ -221,7 +221,7 @@ public class DemoInputGeomProvider : InputGeomProvider
_convexVolumes.Add(volume); _convexVolumes.Add(volume);
} }
public void clearConvexVolumes() public void ClearConvexVolumes()
{ {
_convexVolumes.Clear(); _convexVolumes.Clear();
} }

View File

@ -143,7 +143,7 @@ public class RecastDemo
} }
} }
float[] modelviewMatrix = dd.viewMatrix(cameraPos, cameraEulers); float[] modelviewMatrix = dd.ViewMatrix(cameraPos, cameraEulers);
cameraPos.x += scrollZoom * 2.0f * modelviewMatrix[2]; cameraPos.x += scrollZoom * 2.0f * modelviewMatrix[2];
cameraPos.y += scrollZoom * 2.0f * modelviewMatrix[6]; cameraPos.y += scrollZoom * 2.0f * modelviewMatrix[6];
cameraPos.z += scrollZoom * 2.0f * modelviewMatrix[10]; cameraPos.z += scrollZoom * 2.0f * modelviewMatrix[10];
@ -168,7 +168,7 @@ public class RecastDemo
if (pan) if (pan)
{ {
float[] modelviewMatrix = dd.viewMatrix(cameraPos, cameraEulers); float[] modelviewMatrix = dd.ViewMatrix(cameraPos, cameraEulers);
cameraPos.x = origCameraPos.x; cameraPos.x = origCameraPos.x;
cameraPos.y = origCameraPos.y; cameraPos.y = origCameraPos.y;
cameraPos.z = origCameraPos.z; cameraPos.z = origCameraPos.z;
@ -286,7 +286,7 @@ public class RecastDemo
// // -- move somewhere else: // // -- move somewhere else:
// glfw.SetWindowPos(window, (mode->Width - width) / 2, (mode->Height - height) / 2); // glfw.SetWindowPos(window, (mode->Width - width) / 2, (mode->Height - height) / 2);
// // glfwSetWindowMonitor(window.getWindow(), monitor, 0, 0, mode.width(), mode.height(), mode.refreshRate()); // // GlfwSetWindowMonitor(window.GetWindow(), monitor, 0, 0, mode.Width(), mode.Height(), mode.RefreshRate());
// glfw.ShowWindow(window); // glfw.ShowWindow(window);
// glfw.MakeContextCurrent(window); // glfw.MakeContextCurrent(window);
//} //}
@ -296,35 +296,35 @@ public class RecastDemo
return window; return window;
} }
private DemoInputGeomProvider loadInputMesh(byte[] stream) private DemoInputGeomProvider LoadInputMesh(byte[] stream)
{ {
DemoInputGeomProvider geom = DemoObjImporter.load(stream); DemoInputGeomProvider geom = DemoObjImporter.Load(stream);
sample = new Sample(geom, ImmutableArray<RecastBuilderResult>.Empty, null, settingsUI, dd); sample = new Sample(geom, ImmutableArray<RecastBuilderResult>.Empty, null, settingsUI, dd);
toolsUI.setEnabled(true); toolsUI.SetEnabled(true);
return geom; return geom;
} }
private void loadNavMesh(FileStream file, string filename) private void LoadNavMesh(FileStream file, string filename)
{ {
NavMesh mesh = null; NavMesh mesh = null;
if (filename.EndsWith(".zip") || filename.EndsWith(".bytes")) if (filename.EndsWith(".zip") || filename.EndsWith(".bytes"))
{ {
UnityAStarPathfindingImporter importer = new UnityAStarPathfindingImporter(); UnityAStarPathfindingImporter importer = new UnityAStarPathfindingImporter();
mesh = importer.load(file)[0]; mesh = importer.Load(file)[0];
} }
else if (filename.EndsWith(".bin") || filename.EndsWith(".navmesh")) else if (filename.EndsWith(".bin") || filename.EndsWith(".navmesh"))
{ {
MeshSetReader reader = new MeshSetReader(); MeshSetReader reader = new MeshSetReader();
using (var fis = new BinaryReader(file)) using (var fis = new BinaryReader(file))
{ {
mesh = reader.read(fis, 6); mesh = reader.Read(fis, 6);
} }
} }
if (mesh != null) if (mesh != null)
{ {
//sample = new Sample(null, ImmutableArray<RecastBuilderResult>.Empty, mesh, settingsUI, dd); //sample = new Sample(null, ImmutableArray<RecastBuilderResult>.Empty, mesh, settingsUI, dd);
toolsUI.setEnabled(true); toolsUI.SetEnabled(true);
} }
} }
@ -363,7 +363,7 @@ public class RecastDemo
dd = new RecastDebugDraw(_gl); dd = new RecastDebugDraw(_gl);
renderer = new NavMeshRenderer(dd); renderer = new NavMeshRenderer(dd);
dd.init(camr); dd.Init(camr);
_imgui = new ImGuiController(_gl, window, _input); _imgui = new ImGuiController(_gl, window, _input);
@ -391,7 +391,7 @@ public class RecastDemo
Logger.Debug(glslString); Logger.Debug(glslString);
DemoInputGeomProvider geom = loadInputMesh(Loader.ToBytes("nav_test.obj")); DemoInputGeomProvider geom = LoadInputMesh(Loader.ToBytes("nav_test.obj"));
sample = new Sample(geom, ImmutableArray<RecastBuilderResult>.Empty, null, settingsUI, dd); sample = new Sample(geom, ImmutableArray<RecastBuilderResult>.Empty, null, settingsUI, dd);
} }
@ -409,31 +409,31 @@ public class RecastDemo
var tempMoveAccel = keyboard.IsKeyPressed(Key.ShiftLeft) || keyboard.IsKeyPressed(Key.ShiftRight) ? 1.0f : -1f; var tempMoveAccel = keyboard.IsKeyPressed(Key.ShiftLeft) || keyboard.IsKeyPressed(Key.ShiftRight) ? 1.0f : -1f;
modState = keyboard.IsKeyPressed(Key.ControlLeft) || keyboard.IsKeyPressed(Key.ShiftRight) ? 1 : 0; modState = keyboard.IsKeyPressed(Key.ControlLeft) || keyboard.IsKeyPressed(Key.ShiftRight) ? 1 : 0;
_moveFront = clamp(_moveFront + tempMoveFront * dt * 4.0f, 0, 2.0f); _moveFront = Clamp(_moveFront + tempMoveFront * dt * 4.0f, 0, 2.0f);
_moveLeft = clamp(_moveLeft + tempMoveLeft * dt * 4.0f, 0, 2.0f); _moveLeft = Clamp(_moveLeft + tempMoveLeft * dt * 4.0f, 0, 2.0f);
_moveBack = clamp(_moveBack + tempMoveBack * dt * 4.0f, 0, 2.0f); _moveBack = Clamp(_moveBack + tempMoveBack * dt * 4.0f, 0, 2.0f);
_moveRight = clamp(_moveRight + tempMoveRight * dt * 4.0f, 0, 2.0f); _moveRight = Clamp(_moveRight + tempMoveRight * dt * 4.0f, 0, 2.0f);
_moveUp = clamp(_moveUp + tempMoveUp * dt * 4.0f, 0, 2.0f); _moveUp = Clamp(_moveUp + tempMoveUp * dt * 4.0f, 0, 2.0f);
_moveDown = clamp(_moveDown + tempMoveDown * dt * 4.0f, 0, 2.0f); _moveDown = Clamp(_moveDown + tempMoveDown * dt * 4.0f, 0, 2.0f);
_moveAccel = clamp(_moveAccel + tempMoveAccel * dt * 4.0f, 0, 2.0f); _moveAccel = Clamp(_moveAccel + tempMoveAccel * dt * 4.0f, 0, 2.0f);
} }
} }
private void OnWindowUpdate(double dt) private void OnWindowUpdate(double dt)
{ {
/* /*
* try (MemoryStack stack = stackPush()) { int[] w = stack.mallocInt(1); int[] h = * try (MemoryStack stack = StackPush()) { int[] w = stack.MallocInt(1); int[] h =
* stack.mallocInt(1); glfwGetWindowSize(win, w, h); width = w.x; height = h.x; } * stack.MallocInt(1); GlfwGetWindowSize(win, w, h); width = w.x; height = h.x; }
*/ */
if (sample.getInputGeom() != null) if (sample.GetInputGeom() != null)
{ {
Vector3f bmin = sample.getInputGeom().getMeshBoundsMin(); Vector3f bmin = sample.GetInputGeom().GetMeshBoundsMin();
Vector3f bmax = sample.getInputGeom().getMeshBoundsMax(); Vector3f bmax = sample.GetInputGeom().GetMeshBoundsMax();
int[] voxels = Recast.calcGridSize(bmin, bmax, settingsUI.getCellSize()); int[] voxels = Recast.CalcGridSize(bmin, bmax, settingsUI.GetCellSize());
settingsUI.setVoxels(voxels); settingsUI.SetVoxels(voxels);
settingsUI.setTiles(tileNavMeshBuilder.getTiles(sample.getInputGeom(), settingsUI.getCellSize(), settingsUI.getTileSize())); settingsUI.SetTiles(tileNavMeshBuilder.GetTiles(sample.GetInputGeom(), settingsUI.GetCellSize(), settingsUI.GetTileSize()));
settingsUI.setMaxTiles(tileNavMeshBuilder.getMaxTiles(sample.getInputGeom(), settingsUI.getCellSize(), settingsUI.getTileSize())); settingsUI.SetMaxTiles(tileNavMeshBuilder.GetMaxTiles(sample.GetInputGeom(), settingsUI.GetCellSize(), settingsUI.GetTileSize()));
settingsUI.setMaxPolys(tileNavMeshBuilder.getMaxPolysPerTile(sample.getInputGeom(), settingsUI.getCellSize(), settingsUI.getTileSize())); settingsUI.SetMaxPolys(tileNavMeshBuilder.GetMaxPolysPerTile(sample.GetInputGeom(), settingsUI.GetCellSize(), settingsUI.GetTileSize()));
} }
UpdateKeyboard((float)dt); UpdateKeyboard((float)dt);
@ -465,40 +465,40 @@ public class RecastDemo
// Update sample simulation. // Update sample simulation.
float SIM_RATE = 20; float SIM_RATE = 20;
float DELTA_TIME = 1.0f / SIM_RATE; float DELTA_TIME = 1.0f / SIM_RATE;
timeAcc = clamp((float)(timeAcc + dt), -1.0f, 1.0f); timeAcc = Clamp((float)(timeAcc + dt), -1.0f, 1.0f);
int simIter = 0; int simIter = 0;
while (timeAcc > DELTA_TIME) while (timeAcc > DELTA_TIME)
{ {
timeAcc -= DELTA_TIME; timeAcc -= DELTA_TIME;
if (simIter < 5 && sample != null) if (simIter < 5 && sample != null)
{ {
toolsUI.handleUpdate(DELTA_TIME); toolsUI.HandleUpdate(DELTA_TIME);
} }
simIter++; simIter++;
} }
if (settingsUI.isMeshInputTrigerred()) if (settingsUI.IsMeshInputTrigerred())
{ {
var bytes = Loader.ToBytes(settingsUI.GetMeshInputFilePath()); var bytes = Loader.ToBytes(settingsUI.GetMeshInputFilePath());
sample.update(loadInputMesh(bytes), null, null); sample.Update(LoadInputMesh(bytes), null, null);
} }
else if (settingsUI.isNavMeshInputTrigerred()) else if (settingsUI.IsNavMeshInputTrigerred())
{ {
// try (MemoryStack stack = stackPush()) { // try (MemoryStack stack = StackPush()) {
// PointerBuffer aFilterPatterns = stack.mallocPointer(4); // PointerBuffer aFilterPatterns = stack.MallocPointer(4);
// aFilterPatterns.put(stack.UTF8("*.bin")); // aFilterPatterns.Put(stack.UTF8("*.bin"));
// aFilterPatterns.put(stack.UTF8("*.zip")); // aFilterPatterns.Put(stack.UTF8("*.zip"));
// aFilterPatterns.put(stack.UTF8("*.bytes")); // aFilterPatterns.Put(stack.UTF8("*.bytes"));
// aFilterPatterns.put(stack.UTF8("*.navmesh")); // aFilterPatterns.Put(stack.UTF8("*.navmesh"));
// aFilterPatterns.flip(); // aFilterPatterns.Flip();
// string filename = TinyFileDialogs.tinyfd_openFileDialog("Open Nav Mesh File", "", aFilterPatterns, // string filename = TinyFileDialogs.Tinyfd_openFileDialog("Open Nav Mesh File", "", aFilterPatterns,
// "Nav Mesh File", false); // "Nav Mesh File", false);
// if (filename != null) { // if (filename != null) {
// File file = new File(filename); // File file = new File(filename);
// if (file.exists()) { // if (file.Exists()) {
// try { // try {
// loadNavMesh(file, filename); // LoadNavMesh(file, filename);
// geom = null; // geom = null;
// } catch (Exception e) { // } catch (Exception e) {
// Console.WriteLine(e); // Console.WriteLine(e);
@ -507,56 +507,56 @@ public class RecastDemo
// } // }
// } // }
} }
if (settingsUI.isBuildTriggered() && sample.getInputGeom() != null) if (settingsUI.IsBuildTriggered() && sample.GetInputGeom() != null)
{ {
if (!building) if (!building)
{ {
float m_cellSize = settingsUI.getCellSize(); float m_cellSize = settingsUI.GetCellSize();
float m_cellHeight = settingsUI.getCellHeight(); float m_cellHeight = settingsUI.GetCellHeight();
float m_agentHeight = settingsUI.getAgentHeight(); float m_agentHeight = settingsUI.GetAgentHeight();
float m_agentRadius = settingsUI.getAgentRadius(); float m_agentRadius = settingsUI.GetAgentRadius();
float m_agentMaxClimb = settingsUI.getAgentMaxClimb(); float m_agentMaxClimb = settingsUI.GetAgentMaxClimb();
float m_agentMaxSlope = settingsUI.getAgentMaxSlope(); float m_agentMaxSlope = settingsUI.GetAgentMaxSlope();
int m_regionMinSize = settingsUI.getMinRegionSize(); int m_regionMinSize = settingsUI.GetMinRegionSize();
int m_regionMergeSize = settingsUI.getMergedRegionSize(); int m_regionMergeSize = settingsUI.GetMergedRegionSize();
float m_edgeMaxLen = settingsUI.getEdgeMaxLen(); float m_edgeMaxLen = settingsUI.GetEdgeMaxLen();
float m_edgeMaxError = settingsUI.getEdgeMaxError(); float m_edgeMaxError = settingsUI.GetEdgeMaxError();
int m_vertsPerPoly = settingsUI.getVertsPerPoly(); int m_vertsPerPoly = settingsUI.GetVertsPerPoly();
float m_detailSampleDist = settingsUI.getDetailSampleDist(); float m_detailSampleDist = settingsUI.GetDetailSampleDist();
float m_detailSampleMaxError = settingsUI.getDetailSampleMaxError(); float m_detailSampleMaxError = settingsUI.GetDetailSampleMaxError();
int m_tileSize = settingsUI.getTileSize(); int m_tileSize = settingsUI.GetTileSize();
long t = FrequencyWatch.Ticks; long t = FrequencyWatch.Ticks;
Logger.Information($"build"); Logger.Information($"build");
Tuple<IList<RecastBuilderResult>, NavMesh> buildResult; Tuple<IList<RecastBuilderResult>, NavMesh> buildResult;
if (settingsUI.isTiled()) if (settingsUI.IsTiled())
{ {
buildResult = tileNavMeshBuilder.build(sample.getInputGeom(), settingsUI.getPartitioning(), m_cellSize, buildResult = tileNavMeshBuilder.Build(sample.GetInputGeom(), settingsUI.GetPartitioning(), m_cellSize,
m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_agentMaxSlope, m_regionMinSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_agentMaxSlope, m_regionMinSize,
m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist,
m_detailSampleMaxError, settingsUI.isFilterLowHangingObstacles(), settingsUI.isFilterLedgeSpans(), m_detailSampleMaxError, settingsUI.IsFilterLowHangingObstacles(), settingsUI.IsFilterLedgeSpans(),
settingsUI.isFilterWalkableLowHeightSpans(), m_tileSize); settingsUI.IsFilterWalkableLowHeightSpans(), m_tileSize);
} }
else else
{ {
buildResult = soloNavMeshBuilder.build(sample.getInputGeom(), settingsUI.getPartitioning(), m_cellSize, buildResult = soloNavMeshBuilder.Build(sample.GetInputGeom(), settingsUI.GetPartitioning(), m_cellSize,
m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_agentMaxSlope, m_regionMinSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_agentMaxSlope, m_regionMinSize,
m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist,
m_detailSampleMaxError, settingsUI.isFilterLowHangingObstacles(), settingsUI.isFilterLedgeSpans(), m_detailSampleMaxError, settingsUI.IsFilterLowHangingObstacles(), settingsUI.IsFilterLedgeSpans(),
settingsUI.isFilterWalkableLowHeightSpans()); settingsUI.IsFilterWalkableLowHeightSpans());
} }
sample.update(sample.getInputGeom(), buildResult.Item1, buildResult.Item2); sample.Update(sample.GetInputGeom(), buildResult.Item1, buildResult.Item2);
sample.setChanged(false); sample.SetChanged(false);
settingsUI.setBuildTime((FrequencyWatch.Ticks - t) / TimeSpan.TicksPerMillisecond); settingsUI.SetBuildTime((FrequencyWatch.Ticks - t) / TimeSpan.TicksPerMillisecond);
//settingsUI.setBuildTelemetry(buildResult.Item1.Select(x => x.getTelemetry()).ToList()); //settingsUI.SetBuildTelemetry(buildResult.Item1.Select(x => x.GetTelemetry()).ToList());
toolsUI.setSample(sample); toolsUI.SetSample(sample);
Logger.Information($"build times"); Logger.Information($"build times");
Logger.Information($"-----------------------------------------"); Logger.Information($"-----------------------------------------");
var telemetries = buildResult.Item1 var telemetries = buildResult.Item1
.Select(x => x.getTelemetry()) .Select(x => x.GetTelemetry())
.SelectMany(x => x.ToList()) .SelectMany(x => x.ToList())
.GroupBy(x => x.Item1) .GroupBy(x => x.Item1)
.ToImmutableSortedDictionary(x => x.Key, x => x.Sum(y => y.Item2)); .ToImmutableSortedDictionary(x => x.Key, x => x.Sum(y => y.Item2));
@ -574,35 +574,35 @@ public class RecastDemo
if (!_mouseOverMenu) if (!_mouseOverMenu)
{ {
GLU.glhUnProjectf(mousePos[0], viewport[3] - 1 - mousePos[1], 0.0f, modelviewMatrix, projectionMatrix, viewport, ref rayStart); GLU.GlhUnProjectf(mousePos[0], viewport[3] - 1 - mousePos[1], 0.0f, modelviewMatrix, projectionMatrix, viewport, ref rayStart);
GLU.glhUnProjectf(mousePos[0], viewport[3] - 1 - mousePos[1], 1.0f, modelviewMatrix, projectionMatrix, viewport, ref rayEnd); GLU.GlhUnProjectf(mousePos[0], viewport[3] - 1 - mousePos[1], 1.0f, modelviewMatrix, projectionMatrix, viewport, ref rayEnd);
// Hit test mesh. // Hit test mesh.
DemoInputGeomProvider inputGeom = sample.getInputGeom(); DemoInputGeomProvider inputGeom = sample.GetInputGeom();
if (processHitTest && sample != null) if (processHitTest && sample != null)
{ {
float? hit = null; float? hit = null;
if (inputGeom != null) if (inputGeom != null)
{ {
hit = inputGeom.raycastMesh(rayStart, rayEnd); hit = inputGeom.RaycastMesh(rayStart, rayEnd);
} }
if (!hit.HasValue && sample.getNavMesh() != null) if (!hit.HasValue && sample.GetNavMesh() != null)
{ {
hit = NavMeshRaycast.raycast(sample.getNavMesh(), rayStart, rayEnd); hit = NavMeshRaycast.Raycast(sample.GetNavMesh(), rayStart, rayEnd);
} }
if (!hit.HasValue && sample.getRecastResults() != null) if (!hit.HasValue && sample.GetRecastResults() != null)
{ {
hit = PolyMeshRaycast.raycast(sample.getRecastResults(), rayStart, rayEnd); hit = PolyMeshRaycast.Raycast(sample.GetRecastResults(), rayStart, rayEnd);
} }
float[] rayDir = new float[] { rayEnd.x - rayStart.x, rayEnd.y - rayStart.y, rayEnd.z - rayStart.z }; float[] rayDir = new float[] { rayEnd.x - rayStart.x, rayEnd.y - rayStart.y, rayEnd.z - rayStart.z };
Tool rayTool = toolsUI.getTool(); Tool rayTool = toolsUI.GetTool();
vNormalize(rayDir); VNormalize(rayDir);
if (rayTool != null) if (rayTool != null)
{ {
rayTool.handleClickRay(rayStart, rayDir, processHitTestShift); rayTool.HandleClickRay(rayStart, rayDir, processHitTestShift);
} }
if (hit.HasValue) if (hit.HasValue)
@ -624,7 +624,7 @@ public class RecastDemo
pos.z = rayStart.z + (rayEnd.z - rayStart.z) * hitTime; pos.z = rayStart.z + (rayEnd.z - rayStart.z) * hitTime;
if (rayTool != null) if (rayTool != null)
{ {
rayTool.handleClick(rayStart, pos, processHitTestShift); rayTool.HandleClick(rayStart, pos, processHitTestShift);
} }
} }
} }
@ -641,26 +641,26 @@ public class RecastDemo
processHitTest = false; processHitTest = false;
} }
if (sample.isChanged()) if (sample.IsChanged())
{ {
Vector3f? bminN = null; Vector3f? bminN = null;
Vector3f? bmaxN = null; Vector3f? bmaxN = null;
if (sample.getInputGeom() != null) if (sample.GetInputGeom() != null)
{ {
bminN = sample.getInputGeom().getMeshBoundsMin(); bminN = sample.GetInputGeom().GetMeshBoundsMin();
bmaxN = sample.getInputGeom().getMeshBoundsMax(); bmaxN = sample.GetInputGeom().GetMeshBoundsMax();
} }
else if (sample.getNavMesh() != null) else if (sample.GetNavMesh() != null)
{ {
Vector3f[] bounds = NavMeshUtils.getNavMeshBounds(sample.getNavMesh()); Vector3f[] bounds = NavMeshUtils.GetNavMeshBounds(sample.GetNavMesh());
bminN = bounds[0]; bminN = bounds[0];
bmaxN = bounds[1]; bmaxN = bounds[1];
} }
else if (0 < sample.getRecastResults().Count) else if (0 < sample.GetRecastResults().Count)
{ {
foreach (RecastBuilderResult result in sample.getRecastResults()) foreach (RecastBuilderResult result in sample.GetRecastResults())
{ {
if (result.getSolidHeightfield() != null) if (result.GetSolidHeightfield() != null)
{ {
if (bminN == null) if (bminN == null)
{ {
@ -669,15 +669,15 @@ public class RecastDemo
} }
bminN = Vector3f.Of( bminN = Vector3f.Of(
Math.Min(bminN.Value.x, result.getSolidHeightfield().bmin.x), Math.Min(bminN.Value.x, result.GetSolidHeightfield().bmin.x),
Math.Min(bminN.Value.y, result.getSolidHeightfield().bmin.y), Math.Min(bminN.Value.y, result.GetSolidHeightfield().bmin.y),
Math.Min(bminN.Value.z, result.getSolidHeightfield().bmin.z) Math.Min(bminN.Value.z, result.GetSolidHeightfield().bmin.z)
); );
bmaxN = Vector3f.Of( bmaxN = Vector3f.Of(
Math.Max(bmaxN.Value.x, result.getSolidHeightfield().bmax.x), Math.Max(bmaxN.Value.x, result.GetSolidHeightfield().bmax.x),
Math.Max(bmaxN.Value.y, result.getSolidHeightfield().bmax.y), Math.Max(bmaxN.Value.y, result.GetSolidHeightfield().bmax.y),
Math.Max(bmaxN.Value.z, result.getSolidHeightfield().bmax.z) Math.Max(bmaxN.Value.z, result.GetSolidHeightfield().bmax.z)
); );
} }
} }
@ -689,7 +689,7 @@ public class RecastDemo
Vector3f bmax = bmaxN.Value; Vector3f bmax = bmaxN.Value;
camr = (float)(Math.Sqrt( camr = (float)(Math.Sqrt(
sqr(bmax.x - bmin.x) + sqr(bmax.y - bmin.y) + sqr(bmax.z - bmin.z)) Sqr(bmax.x - bmin.x) + Sqr(bmax.y - bmin.y) + Sqr(bmax.z - bmin.z))
/ 2); / 2);
cameraPos.x = (bmax.x + bmin.x) / 2 + camr; cameraPos.x = (bmax.x + bmin.x) / 2 + camr;
cameraPos.y = (bmax.y + bmin.y) / 2 + camr; cameraPos.y = (bmax.y + bmin.y) / 2 + camr;
@ -699,8 +699,8 @@ public class RecastDemo
cameraEulers[1] = -45; cameraEulers[1] = -45;
} }
sample.setChanged(false); sample.SetChanged(false);
toolsUI.setSample(sample); toolsUI.SetSample(sample);
} }
@ -717,19 +717,19 @@ public class RecastDemo
private void OnWindowRender(double dt) private void OnWindowRender(double dt)
{ {
// Clear the screen // Clear the screen
dd.clear(); dd.Clear();
projectionMatrix = dd.projectionMatrix(50f, (float)width / (float)height, 1.0f, camr); projectionMatrix = dd.ProjectionMatrix(50f, (float)width / (float)height, 1.0f, camr);
modelviewMatrix = dd.viewMatrix(cameraPos, cameraEulers); modelviewMatrix = dd.ViewMatrix(cameraPos, cameraEulers);
dd.fog(camr * 0.1f, camr * 1.25f); dd.Fog(camr * 0.1f, camr * 1.25f);
renderer.render(sample); renderer.Render(sample);
Tool tool = toolsUI.getTool(); Tool tool = toolsUI.GetTool();
if (tool != null) if (tool != null)
{ {
tool.handleRender(renderer); tool.HandleRender(renderer);
} }
dd.fog(false); dd.Fog(false);
_canvas.Draw(dt); _canvas.Draw(dt);
_mouseOverMenu = _canvas.IsMouseOverUI(); _mouseOverMenu = _canvas.IsMouseOverUI();

View File

@ -43,56 +43,56 @@ public class Sample
this.recastResults = recastResults; this.recastResults = recastResults;
this.navMesh = navMesh; this.navMesh = navMesh;
_settingsView = settingsView; _settingsView = settingsView;
setQuery(navMesh); SetQuery(navMesh);
changed = true; changed = true;
} }
private void setQuery(NavMesh navMesh) private void SetQuery(NavMesh navMesh)
{ {
navMeshQuery = navMesh != null ? new NavMeshQuery(navMesh) : null; navMeshQuery = navMesh != null ? new NavMeshQuery(navMesh) : null;
} }
public DemoInputGeomProvider getInputGeom() public DemoInputGeomProvider GetInputGeom()
{ {
return inputGeom; return inputGeom;
} }
public IList<RecastBuilderResult> getRecastResults() public IList<RecastBuilderResult> GetRecastResults()
{ {
return recastResults; return recastResults;
} }
public NavMesh getNavMesh() public NavMesh GetNavMesh()
{ {
return navMesh; return navMesh;
} }
public RcSettingsView getSettingsUI() public RcSettingsView GetSettingsUI()
{ {
return _settingsView; return _settingsView;
} }
public NavMeshQuery getNavMeshQuery() public NavMeshQuery GetNavMeshQuery()
{ {
return navMeshQuery; return navMeshQuery;
} }
public bool isChanged() public bool IsChanged()
{ {
return changed; return changed;
} }
public void setChanged(bool changed) public void SetChanged(bool changed)
{ {
this.changed = changed; this.changed = changed;
} }
public void update(DemoInputGeomProvider geom, IList<RecastBuilderResult> recastResults, NavMesh navMesh) public void Update(DemoInputGeomProvider geom, IList<RecastBuilderResult> recastResults, NavMesh navMesh)
{ {
inputGeom = geom; inputGeom = geom;
this.recastResults = recastResults; this.recastResults = recastResults;
this.navMesh = navMesh; this.navMesh = navMesh;
setQuery(navMesh); SetQuery(navMesh);
changed = true; changed = true;
} }
} }

View File

@ -16,7 +16,7 @@ public class ConsoleTextWriterHook : TextWriter
public override void Write(char[] buffer, int index, int count) public override void Write(char[] buffer, int index, int count)
{ {
var s = new string(new Span<char>(buffer, index, count)); var s = new String(new Span<char>(buffer, index, count));
_event?.Invoke(s); _event?.Invoke(s);
} }
} }

View File

@ -42,14 +42,14 @@ public class ConvexVolumeTool : Tool
private readonly List<float> pts = new(); private readonly List<float> pts = new();
private readonly List<int> hull = new(); private readonly List<int> hull = new();
public override void setSample(Sample m_sample) public override void SetSample(Sample m_sample)
{ {
sample = m_sample; sample = m_sample;
} }
public override void handleClick(Vector3f s, Vector3f p, bool shift) public override void HandleClick(Vector3f s, Vector3f p, bool shift)
{ {
DemoInputGeomProvider geom = sample.getInputGeom(); DemoInputGeomProvider geom = sample.GetInputGeom();
if (geom == null) if (geom == null)
{ {
return; return;
@ -59,10 +59,10 @@ public class ConvexVolumeTool : Tool
{ {
// Delete // Delete
int nearestIndex = -1; int nearestIndex = -1;
IList<ConvexVolume> vols = geom.convexVolumes(); IList<ConvexVolume> vols = geom.ConvexVolumes();
for (int i = 0; i < vols.Count; ++i) for (int i = 0; i < vols.Count; ++i)
{ {
if (PolyUtils.pointInPoly(vols[i].verts, p) && p.y >= vols[i].hmin if (PolyUtils.PointInPoly(vols[i].verts, p) && p.y >= vols[i].hmin
&& p.y <= vols[i].hmax) && p.y <= vols[i].hmax)
{ {
nearestIndex = i; nearestIndex = i;
@ -72,7 +72,7 @@ public class ConvexVolumeTool : Tool
// If end point close enough, delete it. // If end point close enough, delete it.
if (nearestIndex != -1) if (nearestIndex != -1)
{ {
geom.convexVolumes().RemoveAt(nearestIndex); geom.ConvexVolumes().RemoveAt(nearestIndex);
} }
} }
else else
@ -80,7 +80,7 @@ public class ConvexVolumeTool : Tool
// Create // Create
// If clicked on that last pt, create the shape. // If clicked on that last pt, create the shape.
if (pts.Count > 0 && RecastMath.vDistSqr(p, Vector3f.Of(pts[pts.Count - 3], pts[pts.Count - 2], pts[pts.Count - 1])) < 0.2f * 0.2f) if (pts.Count > 0 && RecastMath.VDistSqr(p, Vector3f.Of(pts[pts.Count - 3], pts[pts.Count - 2], pts[pts.Count - 1])) < 0.2f * 0.2f)
{ {
if (hull.Count > 2) if (hull.Count > 2)
{ {
@ -105,15 +105,15 @@ public class ConvexVolumeTool : Tool
if (polyOffset > 0.01f) if (polyOffset > 0.01f)
{ {
float[] offset = new float[verts.Length * 2]; float[] offset = new float[verts.Length * 2];
int noffset = PolyUtils.offsetPoly(verts, hull.Count, polyOffset, offset, offset.Length); int noffset = PolyUtils.OffsetPoly(verts, hull.Count, polyOffset, offset, offset.Length);
if (noffset > 0) if (noffset > 0)
{ {
geom.addConvexVolume(ArrayUtils.CopyOf(offset, 0, noffset * 3), minh, maxh, areaType); geom.AddConvexVolume(ArrayUtils.CopyOf(offset, 0, noffset * 3), minh, maxh, areaType);
} }
} }
else else
{ {
geom.addConvexVolume(verts, minh, maxh, areaType); geom.AddConvexVolume(verts, minh, maxh, areaType);
} }
} }
@ -130,7 +130,7 @@ public class ConvexVolumeTool : Tool
if (pts.Count > 3) if (pts.Count > 3)
{ {
hull.Clear(); hull.Clear();
hull.AddRange(ConvexUtils.convexhull(pts)); hull.AddRange(ConvexUtils.Convexhull(pts));
} }
else else
{ {
@ -140,9 +140,9 @@ public class ConvexVolumeTool : Tool
} }
} }
public override void handleRender(NavMeshRenderer renderer) public override void HandleRender(NavMeshRenderer renderer)
{ {
RecastDebugDraw dd = renderer.getDebugDraw(); RecastDebugDraw dd = renderer.GetDebugDraw();
// Find height extent of the shape. // Find height extent of the shape.
float minh = float.MaxValue, maxh = 0; float minh = float.MaxValue, maxh = 0;
for (int i = 0; i < pts.Count; i += 3) for (int i = 0; i < pts.Count; i += 3)
@ -153,37 +153,37 @@ public class ConvexVolumeTool : Tool
minh -= boxDescent; minh -= boxDescent;
maxh = minh + boxHeight; maxh = minh + boxHeight;
dd.begin(POINTS, 4.0f); dd.Begin(POINTS, 4.0f);
for (int i = 0; i < pts.Count; i += 3) for (int i = 0; i < pts.Count; i += 3)
{ {
int col = duRGBA(255, 255, 255, 255); int col = DuRGBA(255, 255, 255, 255);
if (i == pts.Count - 3) if (i == pts.Count - 3)
{ {
col = duRGBA(240, 32, 16, 255); col = DuRGBA(240, 32, 16, 255);
} }
dd.vertex(pts[i + 0], pts[i + 1] + 0.1f, pts[i + 2], col); dd.Vertex(pts[i + 0], pts[i + 1] + 0.1f, pts[i + 2], col);
} }
dd.end(); dd.End();
dd.begin(LINES, 2.0f); dd.Begin(LINES, 2.0f);
for (int i = 0, j = hull.Count - 1; i < hull.Count; j = i++) for (int i = 0, j = hull.Count - 1; i < hull.Count; j = i++)
{ {
int vi = hull[j] * 3; int vi = hull[j] * 3;
int vj = hull[i] * 3; int vj = hull[i] * 3;
dd.vertex(pts[vj + 0], minh, pts[vj + 2], duRGBA(255, 255, 255, 64)); dd.Vertex(pts[vj + 0], minh, pts[vj + 2], DuRGBA(255, 255, 255, 64));
dd.vertex(pts[vi + 0], minh, pts[vi + 2], duRGBA(255, 255, 255, 64)); dd.Vertex(pts[vi + 0], minh, pts[vi + 2], DuRGBA(255, 255, 255, 64));
dd.vertex(pts[vj + 0], maxh, pts[vj + 2], duRGBA(255, 255, 255, 64)); dd.Vertex(pts[vj + 0], maxh, pts[vj + 2], DuRGBA(255, 255, 255, 64));
dd.vertex(pts[vi + 0], maxh, pts[vi + 2], duRGBA(255, 255, 255, 64)); dd.Vertex(pts[vi + 0], maxh, pts[vi + 2], DuRGBA(255, 255, 255, 64));
dd.vertex(pts[vj + 0], minh, pts[vj + 2], duRGBA(255, 255, 255, 64)); dd.Vertex(pts[vj + 0], minh, pts[vj + 2], DuRGBA(255, 255, 255, 64));
dd.vertex(pts[vj + 0], maxh, pts[vj + 2], duRGBA(255, 255, 255, 64)); dd.Vertex(pts[vj + 0], maxh, pts[vj + 2], DuRGBA(255, 255, 255, 64));
} }
dd.end(); dd.End();
} }
public override void layout() public override void Layout()
{ {
ImGui.SliderFloat("Shape Height", ref boxHeight, 0.1f, 20f, "%.1f"); ImGui.SliderFloat("Shape Height", ref boxHeight, 0.1f, 20f, "%.1f");
ImGui.SliderFloat("Shape Descent", ref boxDescent, 0.1f, 20f, "%.1f"); ImGui.SliderFloat("Shape Descent", ref boxDescent, 0.1f, 20f, "%.1f");
@ -217,20 +217,20 @@ public class ConvexVolumeTool : Tool
hull.Clear(); hull.Clear();
pts.Clear(); pts.Clear();
DemoInputGeomProvider geom = sample.getInputGeom(); DemoInputGeomProvider geom = sample.GetInputGeom();
if (geom != null) if (geom != null)
{ {
geom.clearConvexVolumes(); geom.ClearConvexVolumes();
} }
} }
} }
public override string getName() public override string GetName()
{ {
return "Create Convex Volumes"; return "Create Convex Volumes";
} }
public override void handleUpdate(float dt) public override void HandleUpdate(float dt)
{ {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }

View File

@ -57,7 +57,7 @@ public class CrowdProfilingTool
this.agentParamsSupplier = agentParamsSupplier; this.agentParamsSupplier = agentParamsSupplier;
} }
public void layout() public void Layout()
{ {
ImGui.Text("Simulation Options"); ImGui.Text("Simulation Options");
ImGui.Separator(); ImGui.Separator();
@ -80,18 +80,18 @@ public class CrowdProfilingTool
if (navMesh != null) if (navMesh != null)
{ {
rnd = new FRand(randomSeed); rnd = new FRand(randomSeed);
createCrowd(); CreateCrowd();
createZones(); CreateZones();
NavMeshQuery navquery = new NavMeshQuery(navMesh); NavMeshQuery navquery = new NavMeshQuery(navMesh);
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < agents; i++) for (int i = 0; i < agents; i++)
{ {
float tr = rnd.frand(); float tr = rnd.Frand();
AgentType type = AgentType.MOB; AgentType type = AgentType.MOB;
float mobsPcnt = percentMobs / 100f; float mobsPcnt = percentMobs / 100f;
if (tr > mobsPcnt) if (tr > mobsPcnt)
{ {
tr = rnd.frand(); tr = rnd.Frand();
float travellerPcnt = percentTravellers / 100f; float travellerPcnt = percentTravellers / 100f;
if (tr > travellerPcnt) if (tr > travellerPcnt)
{ {
@ -107,19 +107,19 @@ public class CrowdProfilingTool
switch (type) switch (type)
{ {
case AgentType.MOB: case AgentType.MOB:
pos = getMobPosition(navquery, filter); pos = GetMobPosition(navquery, filter);
break; break;
case AgentType.VILLAGER: case AgentType.VILLAGER:
pos = getVillagerPosition(navquery, filter); pos = GetVillagerPosition(navquery, filter);
break; break;
case AgentType.TRAVELLER: case AgentType.TRAVELLER:
pos = getVillagerPosition(navquery, filter); pos = GetVillagerPosition(navquery, filter);
break; break;
} }
if (pos != null) if (pos != null)
{ {
addAgent(pos.Value, type); AddAgent(pos.Value, type);
} }
} }
} }
@ -129,10 +129,10 @@ public class CrowdProfilingTool
ImGui.Separator(); ImGui.Separator();
if (crowd != null) if (crowd != null)
{ {
ImGui.Text($"Max time to enqueue request: {crowd.telemetry().maxTimeToEnqueueRequest()} s"); ImGui.Text($"Max time to enqueue request: {crowd.Telemetry().MaxTimeToEnqueueRequest()} s");
ImGui.Text($"Max time to find path: {crowd.telemetry().maxTimeToFindPath()} s"); ImGui.Text($"Max time to find path: {crowd.Telemetry().MaxTimeToFindPath()} s");
List<Tuple<string, long>> timings = crowd.telemetry() List<Tuple<string, long>> timings = crowd.Telemetry()
.executionTimings() .ExecutionTimings()
.Select(e => Tuple.Create(e.Key, e.Value)) .Select(e => Tuple.Create(e.Key, e.Value))
.OrderBy(x => x.Item2) .OrderBy(x => x.Item2)
.ToList(); .ToList();
@ -146,34 +146,34 @@ public class CrowdProfilingTool
} }
} }
private Vector3f? getMobPosition(NavMeshQuery navquery, QueryFilter filter) private Vector3f? GetMobPosition(NavMeshQuery navquery, QueryFilter filter)
{ {
Result<FindRandomPointResult> result = navquery.findRandomPoint(filter, rnd); Result<FindRandomPointResult> result = navquery.FindRandomPoint(filter, rnd);
if (result.Succeeded()) if (result.Succeeded())
{ {
return result.result.getRandomPt(); return result.result.GetRandomPt();
} }
return null; return null;
} }
private Vector3f? getVillagerPosition(NavMeshQuery navquery, QueryFilter filter) private Vector3f? GetVillagerPosition(NavMeshQuery navquery, QueryFilter filter)
{ {
if (0 < zones.Count) if (0 < zones.Count)
{ {
int zone = (int)(rnd.frand() * zones.Count); int zone = (int)(rnd.Frand() * zones.Count);
Result<FindRandomPointResult> result = navquery.findRandomPointWithinCircle(zones[zone].getRandomRef(), Result<FindRandomPointResult> result = navquery.FindRandomPointWithinCircle(zones[zone].GetRandomRef(),
zones[zone].getRandomPt(), zoneRadius, filter, rnd); zones[zone].GetRandomPt(), zoneRadius, filter, rnd);
if (result.Succeeded()) if (result.Succeeded())
{ {
return result.result.getRandomPt(); return result.result.GetRandomPt();
} }
} }
return null; return null;
} }
private void createZones() private void CreateZones()
{ {
zones.Clear(); zones.Clear();
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
@ -183,13 +183,13 @@ public class CrowdProfilingTool
float zoneSeparation = zoneRadius * zoneRadius * 16; float zoneSeparation = zoneRadius * zoneRadius * 16;
for (int k = 0; k < 100; k++) for (int k = 0; k < 100; k++)
{ {
Result<FindRandomPointResult> result = navquery.findRandomPoint(filter, rnd); Result<FindRandomPointResult> result = navquery.FindRandomPoint(filter, rnd);
if (result.Succeeded()) if (result.Succeeded())
{ {
bool valid = true; bool valid = true;
foreach (FindRandomPointResult zone in zones) foreach (FindRandomPointResult zone in zones)
{ {
if (RecastMath.vDistSqr(zone.getRandomPt(), result.result.getRandomPt()) < zoneSeparation) if (RecastMath.VDistSqr(zone.GetRandomPt(), result.result.GetRandomPt()) < zoneSeparation)
{ {
valid = false; valid = false;
break; break;
@ -206,46 +206,46 @@ public class CrowdProfilingTool
} }
} }
private void createCrowd() private void CreateCrowd()
{ {
crowd = new Crowd(config, navMesh, __ => new DefaultQueryFilter(SampleAreaModifications.SAMPLE_POLYFLAGS_ALL, crowd = new Crowd(config, navMesh, __ => new DefaultQueryFilter(SampleAreaModifications.SAMPLE_POLYFLAGS_ALL,
SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED, new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f })); SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED, new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f }));
ObstacleAvoidanceParams option = new ObstacleAvoidanceParams(crowd.getObstacleAvoidanceParams(0)); ObstacleAvoidanceParams option = new ObstacleAvoidanceParams(crowd.GetObstacleAvoidanceParams(0));
// Low (11) // Low (11)
option.velBias = 0.5f; option.velBias = 0.5f;
option.adaptiveDivs = 5; option.adaptiveDivs = 5;
option.adaptiveRings = 2; option.adaptiveRings = 2;
option.adaptiveDepth = 1; option.adaptiveDepth = 1;
crowd.setObstacleAvoidanceParams(0, option); crowd.SetObstacleAvoidanceParams(0, option);
// Medium (22) // Medium (22)
option.velBias = 0.5f; option.velBias = 0.5f;
option.adaptiveDivs = 5; option.adaptiveDivs = 5;
option.adaptiveRings = 2; option.adaptiveRings = 2;
option.adaptiveDepth = 2; option.adaptiveDepth = 2;
crowd.setObstacleAvoidanceParams(1, option); crowd.SetObstacleAvoidanceParams(1, option);
// Good (45) // Good (45)
option.velBias = 0.5f; option.velBias = 0.5f;
option.adaptiveDivs = 7; option.adaptiveDivs = 7;
option.adaptiveRings = 2; option.adaptiveRings = 2;
option.adaptiveDepth = 3; option.adaptiveDepth = 3;
crowd.setObstacleAvoidanceParams(2, option); crowd.SetObstacleAvoidanceParams(2, option);
// High (66) // High (66)
option.velBias = 0.5f; option.velBias = 0.5f;
option.adaptiveDivs = 7; option.adaptiveDivs = 7;
option.adaptiveRings = 3; option.adaptiveRings = 3;
option.adaptiveDepth = 3; option.adaptiveDepth = 3;
crowd.setObstacleAvoidanceParams(3, option); crowd.SetObstacleAvoidanceParams(3, option);
} }
public void update(float dt) public void Update(float dt)
{ {
long startTime = FrequencyWatch.Ticks; long startTime = FrequencyWatch.Ticks;
if (crowd != null) if (crowd != null)
{ {
crowd.config().pathQueueSize = pathQueueSize; crowd.Config().pathQueueSize = pathQueueSize;
crowd.config().maxFindPathIterations = maxIterations; crowd.Config().maxFindPathIterations = maxIterations;
crowd.update(dt, null); crowd.Update(dt, null);
} }
long endTime = FrequencyWatch.Ticks; long endTime = FrequencyWatch.Ticks;
@ -253,21 +253,21 @@ public class CrowdProfilingTool
{ {
NavMeshQuery navquery = new NavMeshQuery(navMesh); NavMeshQuery navquery = new NavMeshQuery(navMesh);
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
if (needsNewTarget(ag)) if (NeedsNewTarget(ag))
{ {
AgentData agentData = (AgentData)ag.option.userData; AgentData agentData = (AgentData)ag.option.userData;
switch (agentData.type) switch (agentData.type)
{ {
case AgentType.MOB: case AgentType.MOB:
moveMob(navquery, filter, ag, agentData); MoveMob(navquery, filter, ag, agentData);
break; break;
case AgentType.VILLAGER: case AgentType.VILLAGER:
moveVillager(navquery, filter, ag, agentData); MoveVillager(navquery, filter, ag, agentData);
break; break;
case AgentType.TRAVELLER: case AgentType.TRAVELLER:
moveTraveller(navquery, filter, ag, agentData); MoveTraveller(navquery, filter, ag, agentData);
break; break;
} }
} }
@ -277,43 +277,43 @@ public class CrowdProfilingTool
crowdUpdateTime = (endTime - startTime) / TimeSpan.TicksPerMillisecond; crowdUpdateTime = (endTime - startTime) / TimeSpan.TicksPerMillisecond;
} }
private void moveMob(NavMeshQuery navquery, QueryFilter filter, CrowdAgent ag, AgentData agentData) private void MoveMob(NavMeshQuery navquery, QueryFilter filter, CrowdAgent ag, AgentData agentData)
{ {
// Move somewhere // Move somewhere
Result<FindNearestPolyResult> nearestPoly = navquery.findNearestPoly(ag.npos, crowd.getQueryExtents(), filter); Result<FindNearestPolyResult> nearestPoly = navquery.FindNearestPoly(ag.npos, crowd.GetQueryExtents(), filter);
if (nearestPoly.Succeeded()) if (nearestPoly.Succeeded())
{ {
Result<FindRandomPointResult> result = navquery.findRandomPointAroundCircle(nearestPoly.result.getNearestRef(), Result<FindRandomPointResult> result = navquery.FindRandomPointAroundCircle(nearestPoly.result.GetNearestRef(),
agentData.home, zoneRadius * 2f, filter, rnd); agentData.home, zoneRadius * 2f, filter, rnd);
if (result.Succeeded()) if (result.Succeeded())
{ {
crowd.requestMoveTarget(ag, result.result.getRandomRef(), result.result.getRandomPt()); crowd.RequestMoveTarget(ag, result.result.GetRandomRef(), result.result.GetRandomPt());
} }
} }
} }
private void moveVillager(NavMeshQuery navquery, QueryFilter filter, CrowdAgent ag, AgentData agentData) private void MoveVillager(NavMeshQuery navquery, QueryFilter filter, CrowdAgent ag, AgentData agentData)
{ {
// Move somewhere close // Move somewhere close
Result<FindNearestPolyResult> nearestPoly = navquery.findNearestPoly(ag.npos, crowd.getQueryExtents(), filter); Result<FindNearestPolyResult> nearestPoly = navquery.FindNearestPoly(ag.npos, crowd.GetQueryExtents(), filter);
if (nearestPoly.Succeeded()) if (nearestPoly.Succeeded())
{ {
Result<FindRandomPointResult> result = navquery.findRandomPointAroundCircle(nearestPoly.result.getNearestRef(), Result<FindRandomPointResult> result = navquery.FindRandomPointAroundCircle(nearestPoly.result.GetNearestRef(),
agentData.home, zoneRadius * 0.2f, filter, rnd); agentData.home, zoneRadius * 0.2f, filter, rnd);
if (result.Succeeded()) if (result.Succeeded())
{ {
crowd.requestMoveTarget(ag, result.result.getRandomRef(), result.result.getRandomPt()); crowd.RequestMoveTarget(ag, result.result.GetRandomRef(), result.result.GetRandomPt());
} }
} }
} }
private void moveTraveller(NavMeshQuery navquery, QueryFilter filter, CrowdAgent ag, AgentData agentData) private void MoveTraveller(NavMeshQuery navquery, QueryFilter filter, CrowdAgent ag, AgentData agentData)
{ {
// Move to another zone // Move to another zone
List<FindRandomPointResult> potentialTargets = new(); List<FindRandomPointResult> potentialTargets = new();
foreach (FindRandomPointResult zone in zones) foreach (FindRandomPointResult zone in zones)
{ {
if (RecastMath.vDistSqr(zone.getRandomPt(), ag.npos) > zoneRadius * zoneRadius) if (RecastMath.VDistSqr(zone.GetRandomPt(), ag.npos) > zoneRadius * zoneRadius)
{ {
potentialTargets.Add(zone); potentialTargets.Add(zone);
} }
@ -322,11 +322,11 @@ public class CrowdProfilingTool
if (0 < potentialTargets.Count) if (0 < potentialTargets.Count)
{ {
potentialTargets.Shuffle(); potentialTargets.Shuffle();
crowd.requestMoveTarget(ag, potentialTargets[0].getRandomRef(), potentialTargets[0].getRandomPt()); crowd.RequestMoveTarget(ag, potentialTargets[0].GetRandomRef(), potentialTargets[0].GetRandomPt());
} }
} }
private bool needsNewTarget(CrowdAgent ag) private bool NeedsNewTarget(CrowdAgent ag)
{ {
if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_NONE if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_NONE
|| ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_FAILED) || ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_FAILED)
@ -345,7 +345,7 @@ public class CrowdProfilingTool
return false; return false;
} }
public void setup(float maxAgentRadius, NavMesh nav) public void Setup(float maxAgentRadius, NavMesh nav)
{ {
navMesh = nav; navMesh = nav;
if (nav != null) if (nav != null)
@ -354,20 +354,20 @@ public class CrowdProfilingTool
} }
} }
public void handleRender(NavMeshRenderer renderer) public void HandleRender(NavMeshRenderer renderer)
{ {
RecastDebugDraw dd = renderer.getDebugDraw(); RecastDebugDraw dd = renderer.GetDebugDraw();
dd.depthMask(false); dd.DepthMask(false);
if (crowd != null) if (crowd != null)
{ {
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
float radius = ag.option.radius; float radius = ag.option.radius;
Vector3f pos = ag.npos; Vector3f pos = ag.npos;
dd.debugDrawCircle(pos.x, pos.y, pos.z, radius, duRGBA(0, 0, 0, 32), 2.0f); dd.DebugDrawCircle(pos.x, pos.y, pos.z, radius, DuRGBA(0, 0, 0, 32), 2.0f);
} }
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
AgentData agentData = (AgentData)ag.option.userData; AgentData agentData = (AgentData)ag.option.userData;
@ -375,40 +375,40 @@ public class CrowdProfilingTool
float radius = ag.option.radius; float radius = ag.option.radius;
Vector3f pos = ag.npos; Vector3f pos = ag.npos;
int col = duRGBA(220, 220, 220, 128); int col = DuRGBA(220, 220, 220, 128);
if (agentData.type == AgentType.TRAVELLER) if (agentData.type == AgentType.TRAVELLER)
{ {
col = duRGBA(100, 160, 100, 128); col = DuRGBA(100, 160, 100, 128);
} }
if (agentData.type == AgentType.VILLAGER) if (agentData.type == AgentType.VILLAGER)
{ {
col = duRGBA(120, 80, 160, 128); col = DuRGBA(120, 80, 160, 128);
} }
if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING
|| ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE) || ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE)
col = duLerpCol(col, duRGBA(255, 255, 32, 128), 128); col = DuLerpCol(col, DuRGBA(255, 255, 32, 128), 128);
else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH) else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH)
col = duLerpCol(col, duRGBA(255, 64, 32, 128), 128); col = DuLerpCol(col, DuRGBA(255, 64, 32, 128), 128);
else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_FAILED) else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_FAILED)
col = duRGBA(255, 32, 16, 128); col = DuRGBA(255, 32, 16, 128);
else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY) else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY)
col = duLerpCol(col, duRGBA(64, 255, 0, 128), 128); col = DuLerpCol(col, DuRGBA(64, 255, 0, 128), 128);
dd.debugDrawCylinder(pos.x - radius, pos.y + radius * 0.1f, pos.z - radius, pos.x + radius, pos.y + height, dd.DebugDrawCylinder(pos.x - radius, pos.y + radius * 0.1f, pos.z - radius, pos.x + radius, pos.y + height,
pos.z + radius, col); pos.z + radius, col);
} }
} }
dd.depthMask(true); dd.DepthMask(true);
} }
private CrowdAgent addAgent(Vector3f p, AgentType type) private CrowdAgent AddAgent(Vector3f p, AgentType type)
{ {
CrowdAgentParams ap = agentParamsSupplier.Invoke(); CrowdAgentParams ap = agentParamsSupplier.Invoke();
ap.userData = new AgentData(type, p); ap.userData = new AgentData(type, p);
return crowd.addAgent(p, ap); return crowd.AddAgent(p, ap);
} }
public enum AgentType public enum AgentType
@ -430,11 +430,11 @@ public class CrowdProfilingTool
} }
} }
public void updateAgentParams(int updateFlags, int obstacleAvoidanceType, float separationWeight) public void UpdateAgentParams(int updateFlags, int obstacleAvoidanceType, float separationWeight)
{ {
if (crowd != null) if (crowd != null)
{ {
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
CrowdAgentParams option = new CrowdAgentParams(); CrowdAgentParams option = new CrowdAgentParams();
option.radius = ag.option.radius; option.radius = ag.option.radius;
@ -448,7 +448,7 @@ public class CrowdProfilingTool
option.updateFlags = updateFlags; option.updateFlags = updateFlags;
option.obstacleAvoidanceType = obstacleAvoidanceType; option.obstacleAvoidanceType = obstacleAvoidanceType;
option.separationWeight = separationWeight; option.separationWeight = separationWeight;
crowd.updateAgentParameters(ag, option); crowd.UpdateAgentParameters(ag, option);
} }
} }
} }

View File

@ -89,51 +89,51 @@ public class CrowdTool : Tool
public CrowdTool() public CrowdTool()
{ {
m_agentDebug.vod = new ObstacleAvoidanceDebugData(2048); m_agentDebug.vod = new ObstacleAvoidanceDebugData(2048);
profilingTool = new CrowdProfilingTool(getAgentParams); profilingTool = new CrowdProfilingTool(GetAgentParams);
} }
public override void setSample(Sample psample) public override void SetSample(Sample psample)
{ {
if (sample != psample) if (sample != psample)
{ {
sample = psample; sample = psample;
} }
NavMesh nav = sample.getNavMesh(); NavMesh nav = sample.GetNavMesh();
if (nav != null && m_nav != nav) if (nav != null && m_nav != nav)
{ {
m_nav = nav; m_nav = nav;
CrowdConfig config = new CrowdConfig(sample.getSettingsUI().getAgentRadius()); CrowdConfig config = new CrowdConfig(sample.GetSettingsUI().GetAgentRadius());
crowd = new Crowd(config, nav, __ => new DefaultQueryFilter(SampleAreaModifications.SAMPLE_POLYFLAGS_ALL, crowd = new Crowd(config, nav, __ => new DefaultQueryFilter(SampleAreaModifications.SAMPLE_POLYFLAGS_ALL,
SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED, new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f })); SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED, new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f }));
// Setup local avoidance option to different qualities. // Setup local avoidance option to different qualities.
// Use mostly default settings, copy from dtCrowd. // Use mostly default settings, copy from dtCrowd.
ObstacleAvoidanceParams option = new ObstacleAvoidanceParams(crowd.getObstacleAvoidanceParams(0)); ObstacleAvoidanceParams option = new ObstacleAvoidanceParams(crowd.GetObstacleAvoidanceParams(0));
// Low (11) // Low (11)
option.velBias = 0.5f; option.velBias = 0.5f;
option.adaptiveDivs = 5; option.adaptiveDivs = 5;
option.adaptiveRings = 2; option.adaptiveRings = 2;
option.adaptiveDepth = 1; option.adaptiveDepth = 1;
crowd.setObstacleAvoidanceParams(0, option); crowd.SetObstacleAvoidanceParams(0, option);
// Medium (22) // Medium (22)
option.velBias = 0.5f; option.velBias = 0.5f;
option.adaptiveDivs = 5; option.adaptiveDivs = 5;
option.adaptiveRings = 2; option.adaptiveRings = 2;
option.adaptiveDepth = 2; option.adaptiveDepth = 2;
crowd.setObstacleAvoidanceParams(1, option); crowd.SetObstacleAvoidanceParams(1, option);
// Good (45) // Good (45)
option.velBias = 0.5f; option.velBias = 0.5f;
option.adaptiveDivs = 7; option.adaptiveDivs = 7;
option.adaptiveRings = 2; option.adaptiveRings = 2;
option.adaptiveDepth = 3; option.adaptiveDepth = 3;
crowd.setObstacleAvoidanceParams(2, option); crowd.SetObstacleAvoidanceParams(2, option);
// High (66) // High (66)
option.velBias = 0.5f; option.velBias = 0.5f;
@ -141,13 +141,13 @@ public class CrowdTool : Tool
option.adaptiveRings = 3; option.adaptiveRings = 3;
option.adaptiveDepth = 3; option.adaptiveDepth = 3;
crowd.setObstacleAvoidanceParams(3, option); crowd.SetObstacleAvoidanceParams(3, option);
profilingTool.setup(sample.getSettingsUI().getAgentRadius(), m_nav); profilingTool.Setup(sample.GetSettingsUI().GetAgentRadius(), m_nav);
} }
} }
public override void handleClick(Vector3f s, Vector3f p, bool shift) public override void HandleClick(Vector3f s, Vector3f p, bool shift)
{ {
if (m_mode == CrowdToolMode.PROFILING) if (m_mode == CrowdToolMode.PROFILING)
{ {
@ -164,67 +164,67 @@ public class CrowdTool : Tool
if (shift) if (shift)
{ {
// Delete // Delete
CrowdAgent ahit = hitTestAgents(s, p); CrowdAgent ahit = HitTestAgents(s, p);
if (ahit != null) if (ahit != null)
{ {
removeAgent(ahit); RemoveAgent(ahit);
} }
} }
else else
{ {
// Add // Add
addAgent(p); AddAgent(p);
} }
} }
else if (m_mode == CrowdToolMode.MOVE_TARGET) else if (m_mode == CrowdToolMode.MOVE_TARGET)
{ {
setMoveTarget(p, shift); SetMoveTarget(p, shift);
} }
else if (m_mode == CrowdToolMode.SELECT) else if (m_mode == CrowdToolMode.SELECT)
{ {
// Highlight // Highlight
CrowdAgent ahit = hitTestAgents(s, p); CrowdAgent ahit = HitTestAgents(s, p);
hilightAgent(ahit); HilightAgent(ahit);
} }
else if (m_mode == CrowdToolMode.TOGGLE_POLYS) else if (m_mode == CrowdToolMode.TOGGLE_POLYS)
{ {
NavMesh nav = sample.getNavMesh(); NavMesh nav = sample.GetNavMesh();
NavMeshQuery navquery = sample.getNavMeshQuery(); NavMeshQuery navquery = sample.GetNavMeshQuery();
if (nav != null && navquery != null) if (nav != null && navquery != null)
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
Vector3f halfExtents = crowd.getQueryExtents(); Vector3f halfExtents = crowd.GetQueryExtents();
Result<FindNearestPolyResult> result = navquery.findNearestPoly(p, halfExtents, filter); Result<FindNearestPolyResult> result = navquery.FindNearestPoly(p, halfExtents, filter);
long refs = result.result.getNearestRef(); long refs = result.result.GetNearestRef();
if (refs != 0) if (refs != 0)
{ {
Result<int> flags = nav.getPolyFlags(refs); Result<int> flags = nav.GetPolyFlags(refs);
if (flags.Succeeded()) if (flags.Succeeded())
{ {
nav.setPolyFlags(refs, flags.result ^ SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED); nav.SetPolyFlags(refs, flags.result ^ SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED);
} }
} }
} }
} }
} }
private void removeAgent(CrowdAgent agent) private void RemoveAgent(CrowdAgent agent)
{ {
crowd.removeAgent(agent); crowd.RemoveAgent(agent);
if (agent == m_agentDebug.agent) if (agent == m_agentDebug.agent)
{ {
m_agentDebug.agent = null; m_agentDebug.agent = null;
} }
} }
private void addAgent(Vector3f p) private void AddAgent(Vector3f p)
{ {
CrowdAgentParams ap = getAgentParams(); CrowdAgentParams ap = GetAgentParams();
CrowdAgent ag = crowd.addAgent(p, ap); CrowdAgent ag = crowd.AddAgent(p, ap);
if (ag != null) if (ag != null)
{ {
if (m_targetRef != 0) if (m_targetRef != 0)
crowd.requestMoveTarget(ag, m_targetRef, m_targetPos); crowd.RequestMoveTarget(ag, m_targetRef, m_targetPos);
// Init trail // Init trail
if (!m_trails.TryGetValue(ag.idx, out var trail)) if (!m_trails.TryGetValue(ag.idx, out var trail))
@ -244,32 +244,32 @@ public class CrowdTool : Tool
} }
} }
private CrowdAgentParams getAgentParams() private CrowdAgentParams GetAgentParams()
{ {
CrowdAgentParams ap = new CrowdAgentParams(); CrowdAgentParams ap = new CrowdAgentParams();
ap.radius = sample.getSettingsUI().getAgentRadius(); ap.radius = sample.GetSettingsUI().GetAgentRadius();
ap.height = sample.getSettingsUI().getAgentHeight(); ap.height = sample.GetSettingsUI().GetAgentHeight();
ap.maxAcceleration = 8.0f; ap.maxAcceleration = 8.0f;
ap.maxSpeed = 3.5f; ap.maxSpeed = 3.5f;
ap.collisionQueryRange = ap.radius * 12.0f; ap.collisionQueryRange = ap.radius * 12.0f;
ap.pathOptimizationRange = ap.radius * 30.0f; ap.pathOptimizationRange = ap.radius * 30.0f;
ap.updateFlags = getUpdateFlags(); ap.updateFlags = GetUpdateFlags();
ap.obstacleAvoidanceType = toolParams.m_obstacleAvoidanceType; ap.obstacleAvoidanceType = toolParams.m_obstacleAvoidanceType;
ap.separationWeight = toolParams.m_separationWeight; ap.separationWeight = toolParams.m_separationWeight;
return ap; return ap;
} }
private CrowdAgent hitTestAgents(Vector3f s, Vector3f p) private CrowdAgent HitTestAgents(Vector3f s, Vector3f p)
{ {
CrowdAgent isel = null; CrowdAgent isel = null;
float tsel = float.MaxValue; float tsel = float.MaxValue;
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Vector3f bmin = new Vector3f(); Vector3f bmin = new Vector3f();
Vector3f bmax = new Vector3f(); Vector3f bmax = new Vector3f();
getAgentBounds(ag, ref bmin, ref bmax); GetAgentBounds(ag, ref bmin, ref bmax);
float[] isect = Intersections.intersectSegmentAABB(s, p, bmin, bmax); float[] isect = Intersections.IntersectSegmentAABB(s, p, bmin, bmax);
if (null != isect) if (null != isect)
{ {
float tmin = isect[0]; float tmin = isect[0];
@ -284,7 +284,7 @@ public class CrowdTool : Tool
return isel; return isel;
} }
private void getAgentBounds(CrowdAgent ag, ref Vector3f bmin, ref Vector3f bmax) private void GetAgentBounds(CrowdAgent ag, ref Vector3f bmin, ref Vector3f bmax)
{ {
Vector3f p = ag.npos; Vector3f p = ag.npos;
float r = ag.option.radius; float r = ag.option.radius;
@ -297,141 +297,141 @@ public class CrowdTool : Tool
bmax.z = p.z + r; bmax.z = p.z + r;
} }
private void setMoveTarget(Vector3f p, bool adjust) private void SetMoveTarget(Vector3f p, bool adjust)
{ {
if (sample == null || crowd == null) if (sample == null || crowd == null)
return; return;
// Find nearest point on navmesh and set move request to that location. // Find nearest point on navmesh and set move request to that location.
NavMeshQuery navquery = sample.getNavMeshQuery(); NavMeshQuery navquery = sample.GetNavMeshQuery();
QueryFilter filter = crowd.getFilter(0); QueryFilter filter = crowd.GetFilter(0);
Vector3f halfExtents = crowd.getQueryExtents(); Vector3f halfExtents = crowd.GetQueryExtents();
if (adjust) if (adjust)
{ {
// Request velocity // Request velocity
if (m_agentDebug.agent != null) if (m_agentDebug.agent != null)
{ {
Vector3f vel = calcVel(m_agentDebug.agent.npos, p, m_agentDebug.agent.option.maxSpeed); Vector3f vel = CalcVel(m_agentDebug.agent.npos, p, m_agentDebug.agent.option.maxSpeed);
crowd.requestMoveVelocity(m_agentDebug.agent, vel); crowd.RequestMoveVelocity(m_agentDebug.agent, vel);
} }
else else
{ {
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Vector3f vel = calcVel(ag.npos, p, ag.option.maxSpeed); Vector3f vel = CalcVel(ag.npos, p, ag.option.maxSpeed);
crowd.requestMoveVelocity(ag, vel); crowd.RequestMoveVelocity(ag, vel);
} }
} }
} }
else else
{ {
Result<FindNearestPolyResult> result = navquery.findNearestPoly(p, halfExtents, filter); Result<FindNearestPolyResult> result = navquery.FindNearestPoly(p, halfExtents, filter);
m_targetRef = result.result.getNearestRef(); m_targetRef = result.result.GetNearestRef();
m_targetPos = result.result.getNearestPos(); m_targetPos = result.result.GetNearestPos();
if (m_agentDebug.agent != null) if (m_agentDebug.agent != null)
{ {
crowd.requestMoveTarget(m_agentDebug.agent, m_targetRef, m_targetPos); crowd.RequestMoveTarget(m_agentDebug.agent, m_targetRef, m_targetPos);
} }
else else
{ {
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
crowd.requestMoveTarget(ag, m_targetRef, m_targetPos); crowd.RequestMoveTarget(ag, m_targetRef, m_targetPos);
} }
} }
} }
} }
private Vector3f calcVel(Vector3f pos, Vector3f tgt, float speed) private Vector3f CalcVel(Vector3f pos, Vector3f tgt, float speed)
{ {
Vector3f vel = vSub(tgt, pos); Vector3f vel = VSub(tgt, pos);
vel.y = 0.0f; vel.y = 0.0f;
vNormalize(ref vel); VNormalize(ref vel);
return vScale(vel, speed); return VScale(vel, speed);
} }
public override void handleRender(NavMeshRenderer renderer) public override void HandleRender(NavMeshRenderer renderer)
{ {
if (m_mode == CrowdToolMode.PROFILING) if (m_mode == CrowdToolMode.PROFILING)
{ {
profilingTool.handleRender(renderer); profilingTool.HandleRender(renderer);
return; return;
} }
RecastDebugDraw dd = renderer.getDebugDraw(); RecastDebugDraw dd = renderer.GetDebugDraw();
float rad = sample.getSettingsUI().getAgentRadius(); float rad = sample.GetSettingsUI().GetAgentRadius();
NavMesh nav = sample.getNavMesh(); NavMesh nav = sample.GetNavMesh();
if (nav == null || crowd == null) if (nav == null || crowd == null)
return; return;
if (toolParams.m_showNodes && crowd.getPathQueue() != null) if (toolParams.m_showNodes && crowd.GetPathQueue() != null)
{ {
// NavMeshQuery navquery = crowd.getPathQueue().getNavQuery(); // NavMeshQuery navquery = crowd.GetPathQueue().GetNavQuery();
// if (navquery != null) { // if (navquery != null) {
// dd.debugDrawNavMeshNodes(navquery); // dd.DebugDrawNavMeshNodes(navquery);
// } // }
} }
dd.depthMask(false); dd.DepthMask(false);
// Draw paths // Draw paths
if (toolParams.m_showPath) if (toolParams.m_showPath)
{ {
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
if (!toolParams.m_showDetailAll && ag != m_agentDebug.agent) if (!toolParams.m_showDetailAll && ag != m_agentDebug.agent)
continue; continue;
List<long> path = ag.corridor.getPath(); List<long> path = ag.corridor.GetPath();
int npath = ag.corridor.getPathCount(); int npath = ag.corridor.GetPathCount();
for (int j = 0; j < npath; ++j) for (int j = 0; j < npath; ++j)
{ {
dd.debugDrawNavMeshPoly(nav, path[j], duRGBA(255, 255, 255, 24)); dd.DebugDrawNavMeshPoly(nav, path[j], DuRGBA(255, 255, 255, 24));
} }
} }
} }
if (m_targetRef != 0) if (m_targetRef != 0)
dd.debugDrawCross(m_targetPos.x, m_targetPos.y + 0.1f, m_targetPos.z, rad, duRGBA(255, 255, 255, 192), 2.0f); dd.DebugDrawCross(m_targetPos.x, m_targetPos.y + 0.1f, m_targetPos.z, rad, DuRGBA(255, 255, 255, 192), 2.0f);
// Occupancy grid. // Occupancy grid.
if (toolParams.m_showGrid) if (toolParams.m_showGrid)
{ {
float gridy = -float.MaxValue; float gridy = -float.MaxValue;
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Vector3f pos = ag.corridor.getPos(); Vector3f pos = ag.corridor.GetPos();
gridy = Math.Max(gridy, pos.y); gridy = Math.Max(gridy, pos.y);
} }
gridy += 1.0f; gridy += 1.0f;
dd.begin(QUADS); dd.Begin(QUADS);
ProximityGrid grid = crowd.getGrid(); ProximityGrid grid = crowd.GetGrid();
float cs = grid.GetCellSize(); float cs = grid.GetCellSize();
foreach (var (combinedKey, count) in grid.GetItemCounts()) foreach (var (combinedKey, count) in grid.GetItemCounts())
{ {
ProximityGrid.DecomposeKey(combinedKey, out var x, out var y); ProximityGrid.DecomposeKey(combinedKey, out var x, out var y);
if (count != 0) if (count != 0)
{ {
int col = duRGBA(128, 0, 0, Math.Min(count * 40, 255)); int col = DuRGBA(128, 0, 0, Math.Min(count * 40, 255));
dd.vertex(x * cs, gridy, y * cs, col); dd.Vertex(x * cs, gridy, y * cs, col);
dd.vertex(x * cs, gridy, y * cs + cs, col); dd.Vertex(x * cs, gridy, y * cs + cs, col);
dd.vertex(x * cs + cs, gridy, y * cs + cs, col); dd.Vertex(x * cs + cs, gridy, y * cs + cs, col);
dd.vertex(x * cs + cs, gridy, y * cs, col); dd.Vertex(x * cs + cs, gridy, y * cs, col);
} }
} }
dd.end(); dd.End();
} }
// Trail // Trail
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
AgentTrail trail = m_trails[ag.idx]; AgentTrail trail = m_trails[ag.idx];
Vector3f pos = ag.npos; Vector3f pos = ag.npos;
dd.begin(LINES, 3.0f); dd.Begin(LINES, 3.0f);
Vector3f prev = new Vector3f(); Vector3f prev = new Vector3f();
float preva = 1; float preva = 1;
prev = pos; prev = pos;
@ -440,17 +440,17 @@ public class CrowdTool : Tool
int idx = (trail.htrail + AGENT_MAX_TRAIL - j) % AGENT_MAX_TRAIL; int idx = (trail.htrail + AGENT_MAX_TRAIL - j) % AGENT_MAX_TRAIL;
int v = idx * 3; int v = idx * 3;
float a = 1 - j / (float)AGENT_MAX_TRAIL; float a = 1 - j / (float)AGENT_MAX_TRAIL;
dd.vertex(prev.x, prev.y + 0.1f, prev.z, duRGBA(0, 0, 0, (int)(128 * preva))); dd.Vertex(prev.x, prev.y + 0.1f, prev.z, DuRGBA(0, 0, 0, (int)(128 * preva)));
dd.vertex(trail.trail[v], trail.trail[v + 1] + 0.1f, trail.trail[v + 2], duRGBA(0, 0, 0, (int)(128 * a))); dd.Vertex(trail.trail[v], trail.trail[v + 1] + 0.1f, trail.trail[v + 2], DuRGBA(0, 0, 0, (int)(128 * a)));
preva = a; preva = a;
vCopy(ref prev, trail.trail, v); VCopy(ref prev, trail.trail, v);
} }
dd.end(); dd.End();
} }
// Corners & co // Corners & co
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
if (toolParams.m_showDetailAll == false && ag != m_agentDebug.agent) if (toolParams.m_showDetailAll == false && ag != m_agentDebug.agent)
continue; continue;
@ -462,29 +462,29 @@ public class CrowdTool : Tool
{ {
if (0 < ag.corners.Count) if (0 < ag.corners.Count)
{ {
dd.begin(LINES, 2.0f); dd.Begin(LINES, 2.0f);
for (int j = 0; j < ag.corners.Count; ++j) for (int j = 0; j < ag.corners.Count; ++j)
{ {
Vector3f va = j == 0 ? pos : ag.corners[j - 1].getPos(); Vector3f va = j == 0 ? pos : ag.corners[j - 1].GetPos();
Vector3f vb = ag.corners[j].getPos(); Vector3f vb = ag.corners[j].GetPos();
dd.vertex(va.x, va.y + radius, va.z, duRGBA(128, 0, 0, 192)); dd.Vertex(va.x, va.y + radius, va.z, DuRGBA(128, 0, 0, 192));
dd.vertex(vb.x, vb.y + radius, vb.z, duRGBA(128, 0, 0, 192)); dd.Vertex(vb.x, vb.y + radius, vb.z, DuRGBA(128, 0, 0, 192));
} }
if ((ag.corners[ag.corners.Count - 1].getFlags() if ((ag.corners[ag.corners.Count - 1].GetFlags()
& NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0) & NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
{ {
Vector3f v = ag.corners[ag.corners.Count - 1].getPos(); Vector3f v = ag.corners[ag.corners.Count - 1].GetPos();
dd.vertex(v.x, v.y, v.z, duRGBA(192, 0, 0, 192)); dd.Vertex(v.x, v.y, v.z, DuRGBA(192, 0, 0, 192));
dd.vertex(v.x, v.y + radius * 2, v.z, duRGBA(192, 0, 0, 192)); dd.Vertex(v.x, v.y + radius * 2, v.z, DuRGBA(192, 0, 0, 192));
} }
dd.end(); dd.End();
if (toolParams.m_anticipateTurns) if (toolParams.m_anticipateTurns)
{ {
/* float dvel[3], pos[3]; /* float dvel[3], pos[3];
calcSmoothSteerDirection(ag.pos, ag.cornerVerts, ag.ncorners, dvel); CalcSmoothSteerDirection(ag.pos, ag.cornerVerts, ag.ncorners, dvel);
pos.x = ag.pos.x + dvel.x; pos.x = ag.pos.x + dvel.x;
pos.y = ag.pos.y + dvel.y; pos.y = ag.pos.y + dvel.y;
pos.z = ag.pos.z + dvel.z; pos.z = ag.pos.z + dvel.z;
@ -493,107 +493,107 @@ public class CrowdTool : Tool
float[] tgt = &ag.cornerVerts.x; float[] tgt = &ag.cornerVerts.x;
float y = ag.pos.y+off; float y = ag.pos.y+off;
dd.begin(DU_DRAW_LINES, 2.0f); dd.Begin(DU_DRAW_LINES, 2.0f);
dd.vertex(ag.pos.x,y,ag.pos.z, duRGBA(255,0,0,192)); dd.Vertex(ag.pos.x,y,ag.pos.z, DuRGBA(255,0,0,192));
dd.vertex(pos.x,y,pos.z, duRGBA(255,0,0,192)); dd.Vertex(pos.x,y,pos.z, DuRGBA(255,0,0,192));
dd.vertex(pos.x,y,pos.z, duRGBA(255,0,0,192)); dd.Vertex(pos.x,y,pos.z, DuRGBA(255,0,0,192));
dd.vertex(tgt.x,y,tgt.z, duRGBA(255,0,0,192)); dd.Vertex(tgt.x,y,tgt.z, DuRGBA(255,0,0,192));
dd.end();*/ dd.End();*/
} }
} }
} }
if (toolParams.m_showCollisionSegments) if (toolParams.m_showCollisionSegments)
{ {
Vector3f center = ag.boundary.getCenter(); Vector3f center = ag.boundary.GetCenter();
dd.debugDrawCross(center.x, center.y + radius, center.z, 0.2f, duRGBA(192, 0, 128, 255), 2.0f); dd.DebugDrawCross(center.x, center.y + radius, center.z, 0.2f, DuRGBA(192, 0, 128, 255), 2.0f);
dd.debugDrawCircle(center.x, center.y + radius, center.z, ag.option.collisionQueryRange, duRGBA(192, 0, 128, 128), 2.0f); dd.DebugDrawCircle(center.x, center.y + radius, center.z, ag.option.collisionQueryRange, DuRGBA(192, 0, 128, 128), 2.0f);
dd.begin(LINES, 3.0f); dd.Begin(LINES, 3.0f);
for (int j = 0; j < ag.boundary.getSegmentCount(); ++j) for (int j = 0; j < ag.boundary.GetSegmentCount(); ++j)
{ {
int col = duRGBA(192, 0, 128, 192); int col = DuRGBA(192, 0, 128, 192);
Vector3f[] s = ag.boundary.getSegment(j); Vector3f[] s = ag.boundary.GetSegment(j);
Vector3f s0 = s[0]; Vector3f s0 = s[0];
Vector3f s3 = s[1]; Vector3f s3 = s[1];
if (triArea2D(pos, s0, s3) < 0.0f) if (TriArea2D(pos, s0, s3) < 0.0f)
col = duDarkenCol(col); col = DuDarkenCol(col);
dd.appendArrow(s[0].x, s[0].y + 0.2f, s[0].z, s[1].x, s[1].z + 0.2f, s[1].z, 0.0f, 0.3f, col); dd.AppendArrow(s[0].x, s[0].y + 0.2f, s[0].z, s[1].x, s[1].z + 0.2f, s[1].z, 0.0f, 0.3f, col);
} }
dd.end(); dd.End();
} }
if (toolParams.m_showNeis) if (toolParams.m_showNeis)
{ {
dd.debugDrawCircle(pos.x, pos.y + radius, pos.z, ag.option.collisionQueryRange, duRGBA(0, 192, 128, 128), dd.DebugDrawCircle(pos.x, pos.y + radius, pos.z, ag.option.collisionQueryRange, DuRGBA(0, 192, 128, 128),
2.0f); 2.0f);
dd.begin(LINES, 2.0f); dd.Begin(LINES, 2.0f);
for (int j = 0; j < ag.neis.Count; ++j) for (int j = 0; j < ag.neis.Count; ++j)
{ {
CrowdAgent nei = ag.neis[j].agent; CrowdAgent nei = ag.neis[j].agent;
if (nei != null) if (nei != null)
{ {
dd.vertex(pos.x, pos.y + radius, pos.z, duRGBA(0, 192, 128, 128)); dd.Vertex(pos.x, pos.y + radius, pos.z, DuRGBA(0, 192, 128, 128));
dd.vertex(nei.npos.x, nei.npos.y + radius, nei.npos.z, duRGBA(0, 192, 128, 128)); dd.Vertex(nei.npos.x, nei.npos.y + radius, nei.npos.z, DuRGBA(0, 192, 128, 128));
} }
} }
dd.end(); dd.End();
} }
if (toolParams.m_showOpt) if (toolParams.m_showOpt)
{ {
dd.begin(LINES, 2.0f); dd.Begin(LINES, 2.0f);
dd.vertex(m_agentDebug.optStart.x, m_agentDebug.optStart.y + 0.3f, m_agentDebug.optStart.z, dd.Vertex(m_agentDebug.optStart.x, m_agentDebug.optStart.y + 0.3f, m_agentDebug.optStart.z,
duRGBA(0, 128, 0, 192)); DuRGBA(0, 128, 0, 192));
dd.vertex(m_agentDebug.optEnd.x, m_agentDebug.optEnd.y + 0.3f, m_agentDebug.optEnd.z, duRGBA(0, 128, 0, 192)); dd.Vertex(m_agentDebug.optEnd.x, m_agentDebug.optEnd.y + 0.3f, m_agentDebug.optEnd.z, DuRGBA(0, 128, 0, 192));
dd.end(); dd.End();
} }
} }
// Agent cylinders. // Agent cylinders.
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
float radius = ag.option.radius; float radius = ag.option.radius;
Vector3f pos = ag.npos; Vector3f pos = ag.npos;
int col = duRGBA(0, 0, 0, 32); int col = DuRGBA(0, 0, 0, 32);
if (m_agentDebug.agent == ag) if (m_agentDebug.agent == ag)
col = duRGBA(255, 0, 0, 128); col = DuRGBA(255, 0, 0, 128);
dd.debugDrawCircle(pos.x, pos.y, pos.z, radius, col, 2.0f); dd.DebugDrawCircle(pos.x, pos.y, pos.z, radius, col, 2.0f);
} }
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
float height = ag.option.height; float height = ag.option.height;
float radius = ag.option.radius; float radius = ag.option.radius;
Vector3f pos = ag.npos; Vector3f pos = ag.npos;
int col = duRGBA(220, 220, 220, 128); int col = DuRGBA(220, 220, 220, 128);
if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING
|| ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE) || ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE)
col = duLerpCol(col, duRGBA(128, 0, 255, 128), 32); col = DuLerpCol(col, DuRGBA(128, 0, 255, 128), 32);
else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH) else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH)
col = duLerpCol(col, duRGBA(128, 0, 255, 128), 128); col = DuLerpCol(col, DuRGBA(128, 0, 255, 128), 128);
else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_FAILED) else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_FAILED)
col = duRGBA(255, 32, 16, 128); col = DuRGBA(255, 32, 16, 128);
else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY) else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY)
col = duLerpCol(col, duRGBA(64, 255, 0, 128), 128); col = DuLerpCol(col, DuRGBA(64, 255, 0, 128), 128);
dd.debugDrawCylinder(pos.x - radius, pos.y + radius * 0.1f, pos.z - radius, pos.x + radius, pos.y + height, dd.DebugDrawCylinder(pos.x - radius, pos.y + radius * 0.1f, pos.z - radius, pos.x + radius, pos.y + height,
pos.z + radius, col); pos.z + radius, col);
} }
if (toolParams.m_showVO) if (toolParams.m_showVO)
{ {
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
if (toolParams.m_showDetailAll == false && ag != m_agentDebug.agent) if (toolParams.m_showDetailAll == false && ag != m_agentDebug.agent)
continue; continue;
@ -605,29 +605,29 @@ public class CrowdTool : Tool
float dy = ag.npos.y + ag.option.height; float dy = ag.npos.y + ag.option.height;
float dz = ag.npos.z; float dz = ag.npos.z;
dd.debugDrawCircle(dx, dy, dz, ag.option.maxSpeed, duRGBA(255, 255, 255, 64), 2.0f); dd.DebugDrawCircle(dx, dy, dz, ag.option.maxSpeed, DuRGBA(255, 255, 255, 64), 2.0f);
dd.begin(QUADS); dd.Begin(QUADS);
for (int j = 0; j < vod.getSampleCount(); ++j) for (int j = 0; j < vod.GetSampleCount(); ++j)
{ {
Vector3f p = vod.getSampleVelocity(j); Vector3f p = vod.GetSampleVelocity(j);
float sr = vod.getSampleSize(j); float sr = vod.GetSampleSize(j);
float pen = vod.getSamplePenalty(j); float pen = vod.GetSamplePenalty(j);
float pen2 = vod.getSamplePreferredSidePenalty(j); float pen2 = vod.GetSamplePreferredSidePenalty(j);
int col = duLerpCol(duRGBA(255, 255, 255, 220), duRGBA(128, 96, 0, 220), (int)(pen * 255)); int col = DuLerpCol(DuRGBA(255, 255, 255, 220), DuRGBA(128, 96, 0, 220), (int)(pen * 255));
col = duLerpCol(col, duRGBA(128, 0, 0, 220), (int)(pen2 * 128)); col = DuLerpCol(col, DuRGBA(128, 0, 0, 220), (int)(pen2 * 128));
dd.vertex(dx + p.x - sr, dy, dz + p.z - sr, col); dd.Vertex(dx + p.x - sr, dy, dz + p.z - sr, col);
dd.vertex(dx + p.x - sr, dy, dz + p.z + sr, col); dd.Vertex(dx + p.x - sr, dy, dz + p.z + sr, col);
dd.vertex(dx + p.x + sr, dy, dz + p.z + sr, col); dd.Vertex(dx + p.x + sr, dy, dz + p.z + sr, col);
dd.vertex(dx + p.x + sr, dy, dz + p.z - sr, col); dd.Vertex(dx + p.x + sr, dy, dz + p.z - sr, col);
} }
dd.end(); dd.End();
} }
} }
// Velocity stuff. // Velocity stuff.
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
float radius = ag.option.radius; float radius = ag.option.radius;
float height = ag.option.height; float height = ag.option.height;
@ -635,54 +635,54 @@ public class CrowdTool : Tool
Vector3f vel = ag.vel; Vector3f vel = ag.vel;
Vector3f dvel = ag.dvel; Vector3f dvel = ag.dvel;
int col = duRGBA(220, 220, 220, 192); int col = DuRGBA(220, 220, 220, 192);
if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING
|| ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE) || ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE)
col = duLerpCol(col, duRGBA(128, 0, 255, 192), 48); col = DuLerpCol(col, DuRGBA(128, 0, 255, 192), 48);
else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH) else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH)
col = duLerpCol(col, duRGBA(128, 0, 255, 192), 128); col = DuLerpCol(col, DuRGBA(128, 0, 255, 192), 128);
else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_FAILED) else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_FAILED)
col = duRGBA(255, 32, 16, 192); col = DuRGBA(255, 32, 16, 192);
else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY) else if (ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY)
col = duLerpCol(col, duRGBA(64, 255, 0, 192), 128); col = DuLerpCol(col, DuRGBA(64, 255, 0, 192), 128);
dd.debugDrawCircle(pos.x, pos.y + height, pos.z, radius, col, 2.0f); dd.DebugDrawCircle(pos.x, pos.y + height, pos.z, radius, col, 2.0f);
dd.debugDrawArrow(pos.x, pos.y + height, pos.z, pos.x + dvel.x, pos.y + height + dvel.y, pos.z + dvel.z, dd.DebugDrawArrow(pos.x, pos.y + height, pos.z, pos.x + dvel.x, pos.y + height + dvel.y, pos.z + dvel.z,
0.0f, 0.4f, duRGBA(0, 192, 255, 192), m_agentDebug.agent == ag ? 2.0f : 1.0f); 0.0f, 0.4f, DuRGBA(0, 192, 255, 192), m_agentDebug.agent == ag ? 2.0f : 1.0f);
dd.debugDrawArrow(pos.x, pos.y + height, pos.z, pos.x + vel.x, pos.y + height + vel.y, pos.z + vel.z, 0.0f, dd.DebugDrawArrow(pos.x, pos.y + height, pos.z, pos.x + vel.x, pos.y + height + vel.y, pos.z + vel.z, 0.0f,
0.4f, duRGBA(0, 0, 0, 160), 2.0f); 0.4f, DuRGBA(0, 0, 0, 160), 2.0f);
} }
dd.depthMask(true); dd.DepthMask(true);
} }
public override void handleUpdate(float dt) public override void HandleUpdate(float dt)
{ {
updateTick(dt); UpdateTick(dt);
} }
private void updateTick(float dt) private void UpdateTick(float dt)
{ {
if (m_mode == CrowdToolMode.PROFILING) if (m_mode == CrowdToolMode.PROFILING)
{ {
profilingTool.update(dt); profilingTool.Update(dt);
return; return;
} }
if (crowd == null) if (crowd == null)
return; return;
NavMesh nav = sample.getNavMesh(); NavMesh nav = sample.GetNavMesh();
if (nav == null) if (nav == null)
return; return;
long startTime = FrequencyWatch.Ticks; long startTime = FrequencyWatch.Ticks;
crowd.update(dt, m_agentDebug); crowd.Update(dt, m_agentDebug);
long endTime = FrequencyWatch.Ticks; long endTime = FrequencyWatch.Ticks;
// Update agent trails // Update agent trails
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
AgentTrail trail = m_trails[ag.idx]; AgentTrail trail = m_trails[ag.idx];
// Update agent movement trail. // Update agent movement trail.
@ -692,18 +692,18 @@ public class CrowdTool : Tool
trail.trail[trail.htrail * 3 + 2] = ag.npos.z; trail.trail[trail.htrail * 3 + 2] = ag.npos.z;
} }
m_agentDebug.vod.normalizeSamples(); m_agentDebug.vod.NormalizeSamples();
// m_crowdSampleCount.addSample((float) crowd.getVelocitySampleCount()); // m_crowdSampleCount.addSample((float) crowd.GetVelocitySampleCount());
crowdUpdateTime = (endTime - startTime) / TimeSpan.TicksPerMillisecond; crowdUpdateTime = (endTime - startTime) / TimeSpan.TicksPerMillisecond;
} }
private void hilightAgent(CrowdAgent agent) private void HilightAgent(CrowdAgent agent)
{ {
m_agentDebug.agent = agent; m_agentDebug.agent = agent;
} }
public override void layout() public override void Layout()
{ {
ImGui.Text($"Crowd Tool Mode"); ImGui.Text($"Crowd Tool Mode");
ImGui.Separator(); ImGui.Separator();
@ -744,13 +744,13 @@ public class CrowdTool : Tool
|| m_obstacleAvoidanceType != toolParams.m_obstacleAvoidanceType || m_obstacleAvoidanceType != toolParams.m_obstacleAvoidanceType
|| m_separationWeight != toolParams.m_separationWeight) || m_separationWeight != toolParams.m_separationWeight)
{ {
updateAgentParams(); UpdateAgentParams();
} }
if (m_mode == CrowdToolMode.PROFILING) if (m_mode == CrowdToolMode.PROFILING)
{ {
profilingTool.layout(); profilingTool.Layout();
} }
if (m_mode != CrowdToolMode.PROFILING) if (m_mode != CrowdToolMode.PROFILING)
@ -773,16 +773,16 @@ public class CrowdTool : Tool
} }
} }
private void updateAgentParams() private void UpdateAgentParams()
{ {
if (crowd == null) if (crowd == null)
{ {
return; return;
} }
int updateFlags = getUpdateFlags(); int updateFlags = GetUpdateFlags();
profilingTool.updateAgentParams(updateFlags, toolParams.m_obstacleAvoidanceType, toolParams.m_separationWeight); profilingTool.UpdateAgentParams(updateFlags, toolParams.m_obstacleAvoidanceType, toolParams.m_separationWeight);
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
CrowdAgentParams option = new CrowdAgentParams(); CrowdAgentParams option = new CrowdAgentParams();
option.radius = ag.option.radius; option.radius = ag.option.radius;
@ -797,11 +797,11 @@ public class CrowdTool : Tool
option.updateFlags = updateFlags; option.updateFlags = updateFlags;
option.obstacleAvoidanceType = toolParams.m_obstacleAvoidanceType; option.obstacleAvoidanceType = toolParams.m_obstacleAvoidanceType;
option.separationWeight = toolParams.m_separationWeight; option.separationWeight = toolParams.m_separationWeight;
crowd.updateAgentParameters(ag, option); crowd.UpdateAgentParameters(ag, option);
} }
} }
private int getUpdateFlags() private int GetUpdateFlags()
{ {
int updateFlags = 0; int updateFlags = 0;
if (toolParams.m_anticipateTurns) if (toolParams.m_anticipateTurns)
@ -832,7 +832,7 @@ public class CrowdTool : Tool
return updateFlags; return updateFlags;
} }
public override string getName() public override string GetName()
{ {
return "Crowd"; return "Crowd";
} }

View File

@ -6,9 +6,9 @@ namespace DotRecast.Recast.Demo.Tools;
public static class DemoObjImporter public static class DemoObjImporter
{ {
public static DemoInputGeomProvider load(byte[] chunk) public static DemoInputGeomProvider Load(byte[] chunk)
{ {
var context = ObjImporter.loadContext(chunk); var context = ObjImporter.LoadContext(chunk);
return new DemoInputGeomProvider(context.vertexPositions, context.meshFaces); return new DemoInputGeomProvider(context.vertexPositions, context.meshFaces);
} }
} }

View File

@ -16,6 +16,7 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@ -125,17 +126,17 @@ public class DynamicUpdateTool : Tool
public DynamicUpdateTool() public DynamicUpdateTool()
{ {
executor = Task.Factory; executor = Task.Factory;
bridgeGeom = DemoObjImporter.load(Loader.ToBytes("bridge.obj")); bridgeGeom = DemoObjImporter.Load(Loader.ToBytes("bridge.obj"));
houseGeom = DemoObjImporter.load(Loader.ToBytes("house.obj")); houseGeom = DemoObjImporter.Load(Loader.ToBytes("house.obj"));
convexGeom = DemoObjImporter.load(Loader.ToBytes("convex.obj")); convexGeom = DemoObjImporter.Load(Loader.ToBytes("convex.obj"));
} }
public override void setSample(Sample sample) public override void SetSample(Sample sample)
{ {
this.sample = sample; this.sample = sample;
} }
public override void handleClick(Vector3f s, Vector3f p, bool shift) public override void HandleClick(Vector3f s, Vector3f p, bool shift)
{ {
if (mode == DynamicUpdateToolMode.COLLIDERS) if (mode == DynamicUpdateToolMode.COLLIDERS)
{ {
@ -146,41 +147,41 @@ public class DynamicUpdateTool : Tool
{ {
if (colliderShape == ColliderShape.SPHERE) if (colliderShape == ColliderShape.SPHERE)
{ {
colliderWithGizmo = sphereCollider(p); colliderWithGizmo = SphereCollider(p);
} }
else if (colliderShape == ColliderShape.CAPSULE) else if (colliderShape == ColliderShape.CAPSULE)
{ {
colliderWithGizmo = capsuleCollider(p); colliderWithGizmo = CapsuleCollider(p);
} }
else if (colliderShape == ColliderShape.BOX) else if (colliderShape == ColliderShape.BOX)
{ {
colliderWithGizmo = boxCollider(p); colliderWithGizmo = BoxCollider(p);
} }
else if (colliderShape == ColliderShape.CYLINDER) else if (colliderShape == ColliderShape.CYLINDER)
{ {
colliderWithGizmo = cylinderCollider(p); colliderWithGizmo = CylinderCollider(p);
} }
else if (colliderShape == ColliderShape.COMPOSITE) else if (colliderShape == ColliderShape.COMPOSITE)
{ {
colliderWithGizmo = compositeCollider(p); colliderWithGizmo = CompositeCollider(p);
} }
else if (colliderShape == ColliderShape.TRIMESH_BRIDGE) else if (colliderShape == ColliderShape.TRIMESH_BRIDGE)
{ {
colliderWithGizmo = trimeshBridge(p); colliderWithGizmo = TrimeshBridge(p);
} }
else if (colliderShape == ColliderShape.TRIMESH_HOUSE) else if (colliderShape == ColliderShape.TRIMESH_HOUSE)
{ {
colliderWithGizmo = trimeshHouse(p); colliderWithGizmo = TrimeshHouse(p);
} }
else if (colliderShape == ColliderShape.CONVEX) else if (colliderShape == ColliderShape.CONVEX)
{ {
colliderWithGizmo = convexTrimesh(p); colliderWithGizmo = ConvexTrimesh(p);
} }
} }
if (colliderWithGizmo != null) if (colliderWithGizmo != null)
{ {
long id = dynaMesh.addCollider(colliderWithGizmo.Item1); long id = dynaMesh.AddCollider(colliderWithGizmo.Item1);
colliders.Add(id, colliderWithGizmo.Item1); colliders.Add(id, colliderWithGizmo.Item1);
colliderGizmos.Add(id, colliderWithGizmo.Item2); colliderGizmos.Add(id, colliderWithGizmo.Item2);
} }
@ -205,7 +206,7 @@ public class DynamicUpdateTool : Tool
Vector3f sp = Vector3f.Of(spos.x, spos.y + 1.3f, spos.z); Vector3f sp = Vector3f.Of(spos.x, spos.y + 1.3f, spos.z);
Vector3f ep = Vector3f.Of(epos.x, epos.y + 1.3f, epos.z); Vector3f ep = Vector3f.Of(epos.x, epos.y + 1.3f, epos.z);
long t1 = FrequencyWatch.Ticks; long t1 = FrequencyWatch.Ticks;
float? hitPos = dynaMesh.voxelQuery().raycast(sp, ep); float? hitPos = dynaMesh.VoxelQuery().Raycast(sp, ep);
long t2 = FrequencyWatch.Ticks; long t2 = FrequencyWatch.Ticks;
raycastTime = (t2 - t1) / TimeSpan.TicksPerMillisecond; raycastTime = (t2 - t1) / TimeSpan.TicksPerMillisecond;
raycastHit = hitPos.HasValue; raycastHit = hitPos.HasValue;
@ -216,15 +217,15 @@ public class DynamicUpdateTool : Tool
} }
} }
private Tuple<Collider, ColliderGizmo> sphereCollider(Vector3f p) private Tuple<Collider, ColliderGizmo> SphereCollider(Vector3f p)
{ {
float radius = 1 + (float)random.NextDouble() * 10; float radius = 1 + (float)random.NextDouble() * 10;
return Tuple.Create<Collider, ColliderGizmo>( return Tuple.Create<Collider, ColliderGizmo>(
new SphereCollider(p, radius, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, dynaMesh.config.walkableClimb), new SphereCollider(p, radius, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, dynaMesh.config.walkableClimb),
GizmoFactory.sphere(p, radius)); GizmoFactory.Sphere(p, radius));
} }
private Tuple<Collider, ColliderGizmo> capsuleCollider(Vector3f p) private Tuple<Collider, ColliderGizmo> CapsuleCollider(Vector3f p)
{ {
float radius = 0.4f + (float)random.NextDouble() * 4f; float radius = 0.4f + (float)random.NextDouble() * 4f;
Vector3f a = Vector3f.Of( Vector3f a = Vector3f.Of(
@ -232,7 +233,7 @@ public class DynamicUpdateTool : Tool
0.01f + (float)random.NextDouble(), 0.01f + (float)random.NextDouble(),
(1f - 2 * (float)random.NextDouble()) (1f - 2 * (float)random.NextDouble())
); );
vNormalize(ref a); VNormalize(ref a);
float len = 1f + (float)random.NextDouble() * 20f; float len = 1f + (float)random.NextDouble() * 20f;
a.x *= len; a.x *= len;
a.y *= len; a.y *= len;
@ -240,10 +241,10 @@ public class DynamicUpdateTool : Tool
Vector3f start = Vector3f.Of(p.x, p.y, p.z); Vector3f start = Vector3f.Of(p.x, p.y, p.z);
Vector3f end = Vector3f.Of(p.x + a.x, p.y + a.y, p.z + a.z); Vector3f end = Vector3f.Of(p.x + a.x, p.y + a.y, p.z + a.z);
return Tuple.Create<Collider, ColliderGizmo>(new CapsuleCollider( return Tuple.Create<Collider, ColliderGizmo>(new CapsuleCollider(
start, end, radius, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, dynaMesh.config.walkableClimb), GizmoFactory.capsule(start, end, radius)); start, end, radius, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, dynaMesh.config.walkableClimb), GizmoFactory.Capsule(start, end, radius));
} }
private Tuple<Collider, ColliderGizmo> boxCollider(Vector3f p) private Tuple<Collider, ColliderGizmo> BoxCollider(Vector3f p)
{ {
Vector3f extent = Vector3f.Of( Vector3f extent = Vector3f.Of(
0.5f + (float)random.NextDouble() * 6f, 0.5f + (float)random.NextDouble() * 6f,
@ -252,16 +253,16 @@ public class DynamicUpdateTool : Tool
); );
Vector3f forward = Vector3f.Of((1f - 2 * (float)random.NextDouble()), 0, (1f - 2 * (float)random.NextDouble())); Vector3f forward = Vector3f.Of((1f - 2 * (float)random.NextDouble()), 0, (1f - 2 * (float)random.NextDouble()));
Vector3f up = Vector3f.Of((1f - 2 * (float)random.NextDouble()), 0.01f + (float)random.NextDouble(), (1f - 2 * (float)random.NextDouble())); Vector3f up = Vector3f.Of((1f - 2 * (float)random.NextDouble()), 0.01f + (float)random.NextDouble(), (1f - 2 * (float)random.NextDouble()));
Vector3f[] halfEdges = BoxCollider.getHalfEdges(up, forward, extent); Vector3f[] halfEdges = Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(up, forward, extent);
return Tuple.Create<Collider, ColliderGizmo>( return Tuple.Create<Collider, ColliderGizmo>(
new BoxCollider(p, halfEdges, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, dynaMesh.config.walkableClimb), GizmoFactory.box(p, halfEdges)); new BoxCollider(p, halfEdges, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, dynaMesh.config.walkableClimb), GizmoFactory.Box(p, halfEdges));
} }
private Tuple<Collider, ColliderGizmo> cylinderCollider(Vector3f p) private Tuple<Collider, ColliderGizmo> CylinderCollider(Vector3f p)
{ {
float radius = 0.7f + (float)random.NextDouble() * 4f; float radius = 0.7f + (float)random.NextDouble() * 4f;
float[] a = new float[] { (1f - 2 * (float)random.NextDouble()), 0.01f + (float)random.NextDouble(), (1f - 2 * (float)random.NextDouble()) }; float[] a = new float[] { (1f - 2 * (float)random.NextDouble()), 0.01f + (float)random.NextDouble(), (1f - 2 * (float)random.NextDouble()) };
vNormalize(a); VNormalize(a);
float len = 2f + (float)random.NextDouble() * 20f; float len = 2f + (float)random.NextDouble() * 20f;
a[0] *= len; a[0] *= len;
a[1] *= len; a[1] *= len;
@ -269,25 +270,25 @@ public class DynamicUpdateTool : Tool
Vector3f start = Vector3f.Of(p.x, p.y, p.z); Vector3f start = Vector3f.Of(p.x, p.y, p.z);
Vector3f end = Vector3f.Of(p.x + a[0], p.y + a[1], p.z + a[2]); Vector3f end = Vector3f.Of(p.x + a[0], p.y + a[1], p.z + a[2]);
return Tuple.Create<Collider, ColliderGizmo>(new CylinderCollider(start, end, radius, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, return Tuple.Create<Collider, ColliderGizmo>(new CylinderCollider(start, end, radius, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER,
dynaMesh.config.walkableClimb), GizmoFactory.cylinder(start, end, radius)); dynaMesh.config.walkableClimb), GizmoFactory.Cylinder(start, end, radius));
} }
private Tuple<Collider, ColliderGizmo> compositeCollider(Vector3f p) private Tuple<Collider, ColliderGizmo> CompositeCollider(Vector3f p)
{ {
Vector3f baseExtent = Vector3f.Of(5, 3, 8); Vector3f baseExtent = Vector3f.Of(5, 3, 8);
Vector3f baseCenter = Vector3f.Of(p.x, p.y + 3, p.z); Vector3f baseCenter = Vector3f.Of(p.x, p.y + 3, p.z);
Vector3f baseUp = Vector3f.Of(0, 1, 0); Vector3f baseUp = Vector3f.Of(0, 1, 0);
Vector3f forward = Vector3f.Of((1f - 2 * (float)random.NextDouble()), 0, (1f - 2 * (float)random.NextDouble())); Vector3f forward = Vector3f.Of((1f - 2 * (float)random.NextDouble()), 0, (1f - 2 * (float)random.NextDouble()));
vNormalize(ref forward); VNormalize(ref forward);
Vector3f side = vCross(forward, baseUp); Vector3f side = VCross(forward, baseUp);
BoxCollider @base = new BoxCollider(baseCenter, BoxCollider.getHalfEdges(baseUp, forward, baseExtent), BoxCollider @base = new BoxCollider(baseCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(baseUp, forward, baseExtent),
SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, dynaMesh.config.walkableClimb); SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, dynaMesh.config.walkableClimb);
var roofUp = Vector3f.Zero; var roofUp = Vector3f.Zero;
Vector3f roofExtent = Vector3f.Of(4.5f, 4.5f, 8f); Vector3f roofExtent = Vector3f.Of(4.5f, 4.5f, 8f);
float[] rx = GLU.build_4x4_rotation_matrix(45, forward.x, forward.y, forward.z); float[] rx = GLU.Build_4x4_rotation_matrix(45, forward.x, forward.y, forward.z);
roofUp = mulMatrixVector(ref roofUp, rx, baseUp); roofUp = MulMatrixVector(ref roofUp, rx, baseUp);
Vector3f roofCenter = Vector3f.Of(p.x, p.y + 6, p.z); Vector3f roofCenter = Vector3f.Of(p.x, p.y + 6, p.z);
BoxCollider roof = new BoxCollider(roofCenter, BoxCollider.getHalfEdges(roofUp, forward, roofExtent), BoxCollider roof = new BoxCollider(roofCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(roofUp, forward, roofExtent),
SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, dynaMesh.config.walkableClimb); SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, dynaMesh.config.walkableClimb);
Vector3f trunkStart = Vector3f.Of( Vector3f trunkStart = Vector3f.Of(
baseCenter.x - forward.x * 15 + side.x * 6, baseCenter.x - forward.x * 15 + side.x * 6,
@ -304,45 +305,45 @@ public class DynamicUpdateTool : Tool
SphereCollider crown = new SphereCollider(crownCenter, 4f, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GRASS, SphereCollider crown = new SphereCollider(crownCenter, 4f, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GRASS,
dynaMesh.config.walkableClimb); dynaMesh.config.walkableClimb);
CompositeCollider collider = new CompositeCollider(@base, roof, trunk, crown); CompositeCollider collider = new CompositeCollider(@base, roof, trunk, crown);
ColliderGizmo baseGizmo = GizmoFactory.box(baseCenter, BoxCollider.getHalfEdges(baseUp, forward, baseExtent)); ColliderGizmo baseGizmo = GizmoFactory.Box(baseCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(baseUp, forward, baseExtent));
ColliderGizmo roofGizmo = GizmoFactory.box(roofCenter, BoxCollider.getHalfEdges(roofUp, forward, roofExtent)); ColliderGizmo roofGizmo = GizmoFactory.Box(roofCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(roofUp, forward, roofExtent));
ColliderGizmo trunkGizmo = GizmoFactory.capsule(trunkStart, trunkEnd, 0.5f); ColliderGizmo trunkGizmo = GizmoFactory.Capsule(trunkStart, trunkEnd, 0.5f);
ColliderGizmo crownGizmo = GizmoFactory.sphere(crownCenter, 4f); ColliderGizmo crownGizmo = GizmoFactory.Sphere(crownCenter, 4f);
ColliderGizmo gizmo = GizmoFactory.composite(baseGizmo, roofGizmo, trunkGizmo, crownGizmo); ColliderGizmo gizmo = GizmoFactory.Composite(baseGizmo, roofGizmo, trunkGizmo, crownGizmo);
return Tuple.Create<Collider, ColliderGizmo>(collider, gizmo); return Tuple.Create<Collider, ColliderGizmo>(collider, gizmo);
} }
private Tuple<Collider, ColliderGizmo> trimeshBridge(Vector3f p) private Tuple<Collider, ColliderGizmo> TrimeshBridge(Vector3f p)
{ {
return trimeshCollider(p, bridgeGeom); return TrimeshCollider(p, bridgeGeom);
} }
private Tuple<Collider, ColliderGizmo> trimeshHouse(Vector3f p) private Tuple<Collider, ColliderGizmo> TrimeshHouse(Vector3f p)
{ {
return trimeshCollider(p, houseGeom); return TrimeshCollider(p, houseGeom);
} }
private Tuple<Collider, ColliderGizmo> convexTrimesh(Vector3f p) private Tuple<Collider, ColliderGizmo> ConvexTrimesh(Vector3f p)
{ {
float[] verts = transformVertices(p, convexGeom, 360); float[] verts = TransformVertices(p, convexGeom, 360);
ConvexTrimeshCollider collider = new ConvexTrimeshCollider(verts, convexGeom.faces, ConvexTrimeshCollider collider = new ConvexTrimeshCollider(verts, convexGeom.faces,
SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, dynaMesh.config.walkableClimb * 10); SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, dynaMesh.config.walkableClimb * 10);
return Tuple.Create<Collider, ColliderGizmo>(collider, GizmoFactory.trimesh(verts, convexGeom.faces)); return Tuple.Create<Collider, ColliderGizmo>(collider, GizmoFactory.Trimesh(verts, convexGeom.faces));
} }
private Tuple<Collider, ColliderGizmo> trimeshCollider(Vector3f p, DemoInputGeomProvider geom) private Tuple<Collider, ColliderGizmo> TrimeshCollider(Vector3f p, DemoInputGeomProvider geom)
{ {
float[] verts = transformVertices(p, geom, 0); float[] verts = TransformVertices(p, geom, 0);
TrimeshCollider collider = new TrimeshCollider(verts, geom.faces, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, TrimeshCollider collider = new TrimeshCollider(verts, geom.faces, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD,
dynaMesh.config.walkableClimb * 10); dynaMesh.config.walkableClimb * 10);
return Tuple.Create<Collider, ColliderGizmo>(collider, GizmoFactory.trimesh(verts, geom.faces)); return Tuple.Create<Collider, ColliderGizmo>(collider, GizmoFactory.Trimesh(verts, geom.faces));
} }
private float[] transformVertices(Vector3f p, DemoInputGeomProvider geom, float ax) private float[] TransformVertices(Vector3f p, DemoInputGeomProvider geom, float ax)
{ {
float[] rx = GLU.build_4x4_rotation_matrix((float)random.NextDouble() * ax, 1, 0, 0); float[] rx = GLU.Build_4x4_rotation_matrix((float)random.NextDouble() * ax, 1, 0, 0);
float[] ry = GLU.build_4x4_rotation_matrix((float)random.NextDouble() * 360, 0, 1, 0); float[] ry = GLU.Build_4x4_rotation_matrix((float)random.NextDouble() * 360, 0, 1, 0);
float[] m = GLU.mul(rx, ry); float[] m = GLU.Mul(rx, ry);
float[] verts = new float[geom.vertices.Length]; float[] verts = new float[geom.vertices.Length];
Vector3f v = new Vector3f(); Vector3f v = new Vector3f();
Vector3f vr = new Vector3f(); Vector3f vr = new Vector3f();
@ -351,7 +352,7 @@ public class DynamicUpdateTool : Tool
v.x = geom.vertices[i]; v.x = geom.vertices[i];
v.y = geom.vertices[i + 1]; v.y = geom.vertices[i + 1];
v.z = geom.vertices[i + 2]; v.z = geom.vertices[i + 2];
mulMatrixVector(ref vr, m, v); MulMatrixVector(ref vr, m, v);
vr.x += p.x; vr.x += p.x;
vr.y += p.y - 0.1f; vr.y += p.y - 0.1f;
vr.z += p.z; vr.z += p.z;
@ -363,7 +364,7 @@ public class DynamicUpdateTool : Tool
return verts; return verts;
} }
private float[] mulMatrixVector(float[] resultvector, float[] matrix, float[] pvector) private float[] MulMatrixVector(float[] resultvector, float[] matrix, float[] pvector)
{ {
resultvector[0] = matrix[0] * pvector[0] + matrix[4] * pvector[1] + matrix[8] * pvector[2]; resultvector[0] = matrix[0] * pvector[0] + matrix[4] * pvector[1] + matrix[8] * pvector[2];
resultvector[1] = matrix[1] * pvector[0] + matrix[5] * pvector[1] + matrix[9] * pvector[2]; resultvector[1] = matrix[1] * pvector[0] + matrix[5] * pvector[1] + matrix[9] * pvector[2];
@ -371,7 +372,7 @@ public class DynamicUpdateTool : Tool
return resultvector; return resultvector;
} }
private Vector3f mulMatrixVector(ref Vector3f resultvector, float[] matrix, Vector3f pvector) private Vector3f MulMatrixVector(ref Vector3f resultvector, float[] matrix, Vector3f pvector)
{ {
resultvector.x = matrix[0] * pvector.x + matrix[4] * pvector.y + matrix[8] * pvector.z; resultvector.x = matrix[0] * pvector.x + matrix[4] * pvector.y + matrix[8] * pvector.z;
resultvector.y = matrix[1] * pvector.x + matrix[5] * pvector.y + matrix[9] * pvector.z; resultvector.y = matrix[1] * pvector.x + matrix[5] * pvector.y + matrix[9] * pvector.z;
@ -380,7 +381,7 @@ public class DynamicUpdateTool : Tool
} }
public override void handleClickRay(Vector3f start, float[] dir, bool shift) public override void HandleClickRay(Vector3f start, float[] dir, bool shift)
{ {
if (mode == DynamicUpdateToolMode.COLLIDERS) if (mode == DynamicUpdateToolMode.COLLIDERS)
{ {
@ -388,9 +389,9 @@ public class DynamicUpdateTool : Tool
{ {
foreach (var e in colliders) foreach (var e in colliders)
{ {
if (hit(start, dir, e.Value.bounds())) if (Hit(start, dir, e.Value.Bounds()))
{ {
dynaMesh.removeCollider(e.Key); dynaMesh.RemoveCollider(e.Key);
colliders.Remove(e.Key); colliders.Remove(e.Key);
colliderGizmos.Remove(e.Key); colliderGizmos.Remove(e.Key);
break; break;
@ -400,7 +401,7 @@ public class DynamicUpdateTool : Tool
} }
} }
private bool hit(Vector3f point, float[] dir, float[] bounds) private bool Hit(Vector3f point, float[] dir, float[] bounds)
{ {
float cx = 0.5f * (bounds[0] + bounds[3]); float cx = 0.5f * (bounds[0] + bounds[3]);
float cy = 0.5f * (bounds[1] + bounds[4]); float cy = 0.5f * (bounds[1] + bounds[4]);
@ -428,85 +429,85 @@ public class DynamicUpdateTool : Tool
return disc >= 0.0f; return disc >= 0.0f;
} }
public override void handleRender(NavMeshRenderer renderer) public override void HandleRender(NavMeshRenderer renderer)
{ {
if (mode == DynamicUpdateToolMode.COLLIDERS) if (mode == DynamicUpdateToolMode.COLLIDERS)
{ {
if (showColliders) if (showColliders)
{ {
colliderGizmos.Values.forEach(g => g.render(renderer.getDebugDraw())); colliderGizmos.Values.ForEach(g => g.Render(renderer.GetDebugDraw()));
} }
} }
if (mode == DynamicUpdateToolMode.RAYCAST) if (mode == DynamicUpdateToolMode.RAYCAST)
{ {
RecastDebugDraw dd = renderer.getDebugDraw(); RecastDebugDraw dd = renderer.GetDebugDraw();
int startCol = duRGBA(128, 25, 0, 192); int startCol = DuRGBA(128, 25, 0, 192);
int endCol = duRGBA(51, 102, 0, 129); int endCol = DuRGBA(51, 102, 0, 129);
if (sposSet) if (sposSet)
{ {
drawAgent(dd, spos, startCol); DrawAgent(dd, spos, startCol);
} }
if (eposSet) if (eposSet)
{ {
drawAgent(dd, epos, endCol); DrawAgent(dd, epos, endCol);
} }
dd.depthMask(false); dd.DepthMask(false);
if (raycastHitPos != Vector3f.Zero) if (raycastHitPos != Vector3f.Zero)
{ {
int spathCol = raycastHit ? duRGBA(128, 32, 16, 220) : duRGBA(64, 128, 240, 220); int spathCol = raycastHit ? DuRGBA(128, 32, 16, 220) : DuRGBA(64, 128, 240, 220);
dd.begin(LINES, 2.0f); dd.Begin(LINES, 2.0f);
dd.vertex(spos.x, spos.y + 1.3f, spos.z, spathCol); dd.Vertex(spos.x, spos.y + 1.3f, spos.z, spathCol);
dd.vertex(raycastHitPos.x, raycastHitPos.y, raycastHitPos.z, spathCol); dd.Vertex(raycastHitPos.x, raycastHitPos.y, raycastHitPos.z, spathCol);
dd.end(); dd.End();
} }
dd.depthMask(true); dd.DepthMask(true);
} }
} }
private void drawAgent(RecastDebugDraw dd, Vector3f pos, int col) private void DrawAgent(RecastDebugDraw dd, Vector3f pos, int col)
{ {
float r = sample.getSettingsUI().getAgentRadius(); float r = sample.GetSettingsUI().GetAgentRadius();
float h = sample.getSettingsUI().getAgentHeight(); float h = sample.GetSettingsUI().GetAgentHeight();
float c = sample.getSettingsUI().getAgentMaxClimb(); float c = sample.GetSettingsUI().GetAgentMaxClimb();
dd.depthMask(false); dd.DepthMask(false);
// Agent dimensions. // Agent dimensions.
dd.debugDrawCylinderWire(pos.x - r, pos.y + 0.02f, pos.z - r, pos.x + r, pos.y + h, pos.z + r, col, 2.0f); dd.DebugDrawCylinderWire(pos.x - r, pos.y + 0.02f, pos.z - r, pos.x + r, pos.y + h, pos.z + r, col, 2.0f);
dd.debugDrawCircle(pos.x, pos.y + c, pos.z, r, duRGBA(0, 0, 0, 64), 1.0f); dd.DebugDrawCircle(pos.x, pos.y + c, pos.z, r, DuRGBA(0, 0, 0, 64), 1.0f);
int colb = duRGBA(0, 0, 0, 196); int colb = DuRGBA(0, 0, 0, 196);
dd.begin(LINES); dd.Begin(LINES);
dd.vertex(pos.x, pos.y - c, pos.z, colb); dd.Vertex(pos.x, pos.y - c, pos.z, colb);
dd.vertex(pos.x, pos.y + c, pos.z, colb); dd.Vertex(pos.x, pos.y + c, pos.z, colb);
dd.vertex(pos.x - r / 2, pos.y + 0.02f, pos.z, colb); dd.Vertex(pos.x - r / 2, pos.y + 0.02f, pos.z, colb);
dd.vertex(pos.x + r / 2, pos.y + 0.02f, pos.z, colb); dd.Vertex(pos.x + r / 2, pos.y + 0.02f, pos.z, colb);
dd.vertex(pos.x, pos.y + 0.02f, pos.z - r / 2, colb); dd.Vertex(pos.x, pos.y + 0.02f, pos.z - r / 2, colb);
dd.vertex(pos.x, pos.y + 0.02f, pos.z + r / 2, colb); dd.Vertex(pos.x, pos.y + 0.02f, pos.z + r / 2, colb);
dd.end(); dd.End();
dd.depthMask(true); dd.DepthMask(true);
} }
public override void handleUpdate(float dt) public override void HandleUpdate(float dt)
{ {
if (dynaMesh != null) if (dynaMesh != null)
{ {
updateDynaMesh(); UpdateDynaMesh();
} }
} }
private void updateDynaMesh() private void UpdateDynaMesh()
{ {
long t = FrequencyWatch.Ticks; long t = FrequencyWatch.Ticks;
try try
{ {
bool updated = dynaMesh.update(executor).Result; bool updated = dynaMesh.Update(executor).Result;
if (updated) if (updated)
{ {
buildTime = (FrequencyWatch.Ticks - t) / TimeSpan.TicksPerMillisecond; buildTime = (FrequencyWatch.Ticks - t) / TimeSpan.TicksPerMillisecond;
sample.update(null, dynaMesh.recastResults(), dynaMesh.navMesh()); sample.Update(null, dynaMesh.RecastResults(), dynaMesh.NavMesh());
sample.setChanged(false); sample.SetChanged(false);
} }
} }
catch (Exception e) catch (Exception e)
@ -515,7 +516,7 @@ public class DynamicUpdateTool : Tool
} }
} }
public override void layout() public override void Layout()
{ {
ImGui.Text($"Dynamic Update Tool Modes"); ImGui.Text($"Dynamic Update Tool Modes");
ImGui.Separator(); ImGui.Separator();
@ -548,7 +549,7 @@ public class DynamicUpdateTool : Tool
var picker = ImFilePicker.GetFilePicker(loadVoxelPopupStrId, Path.Combine(Environment.CurrentDirectory), ".voxels"); var picker = ImFilePicker.GetFilePicker(loadVoxelPopupStrId, Path.Combine(Environment.CurrentDirectory), ".voxels");
if (picker.Draw()) if (picker.Draw())
{ {
load(picker.SelectedFile); Load(picker.SelectedFile);
ImFilePicker.RemoveFilePicker(loadVoxelPopupStrId); ImFilePicker.RemoveFilePicker(loadVoxelPopupStrId);
} }
@ -571,7 +572,7 @@ public class DynamicUpdateTool : Tool
if (picker.Draw()) if (picker.Draw())
{ {
if (string.IsNullOrEmpty(picker.SelectedFile)) if (string.IsNullOrEmpty(picker.SelectedFile))
save(picker.SelectedFile); Save(picker.SelectedFile);
ImFilePicker.RemoveFilePicker(saveVoxelPopupStrId); ImFilePicker.RemoveFilePicker(saveVoxelPopupStrId);
} }
@ -597,7 +598,7 @@ public class DynamicUpdateTool : Tool
ImGui.Text("Partitioning"); ImGui.Text("Partitioning");
ImGui.Separator(); ImGui.Separator();
PartitionType.Values.forEach(partition => PartitionType.Values.ForEach(partition =>
{ {
var label = partition.Name.Substring(0, 1).ToUpper() var label = partition.Name.Substring(0, 1).ToUpper()
+ partition.Name.Substring(1).ToLower(); + partition.Name.Substring(1).ToLower();
@ -636,8 +637,8 @@ public class DynamicUpdateTool : Tool
{ {
if (dynaMesh != null) if (dynaMesh != null)
{ {
buildDynaMesh(); BuildDynaMesh();
sample.setChanged(false); sample.SetChanged(false);
} }
} }
} }
@ -692,18 +693,18 @@ public class DynamicUpdateTool : Tool
} }
private void load(string filename) private void Load(string filename)
{ {
try try
{ {
using var fs = new FileStream(filename, FileMode.Open, FileAccess.Read); using var fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
using var br = new BinaryReader(fs); using var br = new BinaryReader(fs);
VoxelFileReader reader = new VoxelFileReader(); VoxelFileReader reader = new VoxelFileReader();
VoxelFile voxelFile = reader.read(br); VoxelFile voxelFile = reader.Read(br);
dynaMesh = new DynamicNavMesh(voxelFile); dynaMesh = new DynamicNavMesh(voxelFile);
dynaMesh.config.keepIntermediateResults = true; dynaMesh.config.keepIntermediateResults = true;
updateUI(); UpdateUI();
buildDynaMesh(); BuildDynaMesh();
colliders.Clear(); colliders.Clear();
} }
@ -715,22 +716,22 @@ public class DynamicUpdateTool : Tool
} }
private void save(string filename) private void Save(string filename)
{ {
using var fs = new FileStream(filename, FileMode.CreateNew, FileAccess.Write); using var fs = new FileStream(filename, FileMode.CreateNew, FileAccess.Write);
using var bw = new BinaryWriter(fs); using var bw = new BinaryWriter(fs);
VoxelFile voxelFile = VoxelFile.from(dynaMesh); VoxelFile voxelFile = VoxelFile.From(dynaMesh);
VoxelFileWriter writer = new VoxelFileWriter(); VoxelFileWriter writer = new VoxelFileWriter();
writer.write(bw, voxelFile, compression); writer.Write(bw, voxelFile, compression);
} }
private void buildDynaMesh() private void BuildDynaMesh()
{ {
configDynaMesh(); ConfigDynaMesh();
long t = FrequencyWatch.Ticks; long t = FrequencyWatch.Ticks;
try try
{ {
var _ = dynaMesh.build(executor).Result; var _ = dynaMesh.Build(executor).Result;
} }
catch (Exception e) catch (Exception e)
{ {
@ -738,10 +739,10 @@ public class DynamicUpdateTool : Tool
} }
buildTime = (FrequencyWatch.Ticks - t) / TimeSpan.TicksPerMillisecond; buildTime = (FrequencyWatch.Ticks - t) / TimeSpan.TicksPerMillisecond;
sample.update(null, dynaMesh.recastResults(), dynaMesh.navMesh()); sample.Update(null, dynaMesh.RecastResults(), dynaMesh.NavMesh());
} }
private void configDynaMesh() private void ConfigDynaMesh()
{ {
dynaMesh.config.partitionType = partitioning; dynaMesh.config.partitionType = partitioning;
dynaMesh.config.walkableHeight = walkableHeight; dynaMesh.config.walkableHeight = walkableHeight;
@ -761,7 +762,7 @@ public class DynamicUpdateTool : Tool
dynaMesh.config.detailSampleMaxError = detailSampleMaxError; dynaMesh.config.detailSampleMaxError = detailSampleMaxError;
} }
private void updateUI() private void UpdateUI()
{ {
cellSize = dynaMesh.config.cellSize; cellSize = dynaMesh.config.cellSize;
partitioning = dynaMesh.config.partitionType; partitioning = dynaMesh.config.partitionType;
@ -782,7 +783,7 @@ public class DynamicUpdateTool : Tool
filterWalkableLowHeightSpans = dynaMesh.config.filterWalkableLowHeightSpans; filterWalkableLowHeightSpans = dynaMesh.config.filterWalkableLowHeightSpans;
} }
public override string getName() public override string GetName()
{ {
return "Dynamic Updates"; return "Dynamic Updates";
} }

View File

@ -29,7 +29,7 @@ public class BoxGizmo : ColliderGizmo
private readonly Vector3f[] halfEdges; private readonly Vector3f[] halfEdges;
public BoxGizmo(Vector3f center, Vector3f extent, Vector3f forward, Vector3f up) : public BoxGizmo(Vector3f center, Vector3f extent, Vector3f forward, Vector3f up) :
this(center, BoxCollider.getHalfEdges(up, forward, extent)) this(center, BoxCollider.GetHalfEdges(up, forward, extent))
{ {
} }
@ -48,7 +48,7 @@ public class BoxGizmo : ColliderGizmo
} }
} }
public void render(RecastDebugDraw debugDraw) public void Render(RecastDebugDraw debugDraw)
{ {
var trX = Vector3f.Of(halfEdges[0].x, halfEdges[1].x, halfEdges[2].x); var trX = Vector3f.Of(halfEdges[0].x, halfEdges[1].x, halfEdges[2].x);
var trY = Vector3f.Of(halfEdges[0].y, halfEdges[1].y, halfEdges[2].y); var trY = Vector3f.Of(halfEdges[0].y, halfEdges[1].y, halfEdges[2].y);
@ -56,31 +56,31 @@ public class BoxGizmo : ColliderGizmo
float[] vertices = new float[8 * 3]; float[] vertices = new float[8 * 3];
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
vertices[i * 3 + 0] = RecastVectors.dot(VERTS[i], trX) + center.x; vertices[i * 3 + 0] = RecastVectors.Dot(VERTS[i], trX) + center.x;
vertices[i * 3 + 1] = RecastVectors.dot(VERTS[i], trY) + center.y; vertices[i * 3 + 1] = RecastVectors.Dot(VERTS[i], trY) + center.y;
vertices[i * 3 + 2] = RecastVectors.dot(VERTS[i], trZ) + center.z; vertices[i * 3 + 2] = RecastVectors.Dot(VERTS[i], trZ) + center.z;
} }
debugDraw.begin(DebugDrawPrimitives.TRIS); debugDraw.Begin(DebugDrawPrimitives.TRIS);
for (int i = 0; i < 12; i++) for (int i = 0; i < 12; i++)
{ {
int col = DebugDraw.duRGBA(200, 200, 50, 160); int col = DebugDraw.DuRGBA(200, 200, 50, 160);
if (i == 4 || i == 5 || i == 8 || i == 9) if (i == 4 || i == 5 || i == 8 || i == 9)
{ {
col = DebugDraw.duRGBA(160, 160, 40, 160); col = DebugDraw.DuRGBA(160, 160, 40, 160);
} }
else if (i > 4) else if (i > 4)
{ {
col = DebugDraw.duRGBA(120, 120, 30, 160); col = DebugDraw.DuRGBA(120, 120, 30, 160);
} }
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
int v = TRIANLGES[i * 3 + j] * 3; int v = TRIANLGES[i * 3 + j] * 3;
debugDraw.vertex(vertices[v], vertices[v + 1], vertices[v + 2], col); debugDraw.Vertex(vertices[v], vertices[v + 1], vertices[v + 2], col);
} }
} }
debugDraw.end(); debugDraw.End();
} }
} }

View File

@ -23,17 +23,17 @@ public class CapsuleGizmo : ColliderGizmo
Vector3f axis = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); Vector3f axis = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
Vector3f[] normals = new Vector3f[3]; Vector3f[] normals = new Vector3f[3];
normals[1] = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); normals[1] = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
normalize(ref normals[1]); Normalize(ref normals[1]);
normals[0] = getSideVector(axis); normals[0] = GetSideVector(axis);
normals[2] = Vector3f.Zero; normals[2] = Vector3f.Zero;
cross(ref normals[2], normals[0], normals[1]); Cross(ref normals[2], normals[0], normals[1]);
normalize(ref normals[2]); Normalize(ref normals[2]);
triangles = generateSphericalTriangles(); triangles = GenerateSphericalTriangles();
var trX = Vector3f.Of(normals[0].x, normals[1].x, normals[2].x); var trX = Vector3f.Of(normals[0].x, normals[1].x, normals[2].x);
var trY = Vector3f.Of(normals[0].y, normals[1].y, normals[2].y); var trY = Vector3f.Of(normals[0].y, normals[1].y, normals[2].y);
var trZ = Vector3f.Of(normals[0].z, normals[1].z, normals[2].z); var trZ = Vector3f.Of(normals[0].z, normals[1].z, normals[2].z);
float[] spVertices = generateSphericalVertices(); float[] spVertices = GenerateSphericalVertices();
float halfLength = 0.5f * vLen(axis); float halfLength = 0.5f * VLen(axis);
vertices = new float[spVertices.Length]; vertices = new float[spVertices.Length];
gradient = new float[spVertices.Length / 3]; gradient = new float[spVertices.Length / 3];
Vector3f v = new Vector3f(); Vector3f v = new Vector3f();
@ -49,12 +49,12 @@ public class CapsuleGizmo : ColliderGizmo
v.x = vertices[i] - center[0]; v.x = vertices[i] - center[0];
v.y = vertices[i + 1] - center[1]; v.y = vertices[i + 1] - center[1];
v.z = vertices[i + 2] - center[2]; v.z = vertices[i + 2] - center[2];
normalize(ref v); Normalize(ref v);
gradient[i / 3] = clamp(0.57735026f * (v.x + v.y + v.z), -1, 1); gradient[i / 3] = Clamp(0.57735026f * (v.x + v.y + v.z), -1, 1);
} }
} }
private Vector3f getSideVector(Vector3f axis) private Vector3f GetSideVector(Vector3f axis)
{ {
Vector3f side = Vector3f.Of(1, 0, 0); Vector3f side = Vector3f.Of(1, 0, 0);
if (axis.x > 0.8) if (axis.x > 0.8)
@ -63,27 +63,27 @@ public class CapsuleGizmo : ColliderGizmo
} }
Vector3f forward = new Vector3f(); Vector3f forward = new Vector3f();
cross(ref forward, side, axis); Cross(ref forward, side, axis);
cross(ref side, axis, forward); Cross(ref side, axis, forward);
normalize(ref side); Normalize(ref side);
return side; return side;
} }
public void render(RecastDebugDraw debugDraw) public void Render(RecastDebugDraw debugDraw)
{ {
debugDraw.begin(DebugDrawPrimitives.TRIS); debugDraw.Begin(DebugDrawPrimitives.TRIS);
for (int i = 0; i < triangles.Length; i += 3) for (int i = 0; i < triangles.Length; i += 3)
{ {
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
int v = triangles[i + j] * 3; int v = triangles[i + j] * 3;
float c = gradient[triangles[i + j]]; float c = gradient[triangles[i + j]];
int col = DebugDraw.duLerpCol(DebugDraw.duRGBA(32, 32, 0, 160), DebugDraw.duRGBA(220, 220, 0, 160), int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160),
(int)(127 * (1 + c))); (int)(127 * (1 + c)));
debugDraw.vertex(vertices[v], vertices[v + 1], vertices[v + 2], col); debugDraw.Vertex(vertices[v], vertices[v + 1], vertices[v + 2], col);
} }
} }
debugDraw.end(); debugDraw.End();
} }
} }

View File

@ -4,5 +4,5 @@ namespace DotRecast.Recast.Demo.Tools.Gizmos;
public interface ColliderGizmo public interface ColliderGizmo
{ {
void render(RecastDebugDraw debugDraw); void Render(RecastDebugDraw debugDraw);
} }

View File

@ -1,4 +1,5 @@
using DotRecast.Core; using System;
using DotRecast.Core;
using DotRecast.Recast.Demo.Draw; using DotRecast.Recast.Demo.Draw;
namespace DotRecast.Recast.Demo.Tools.Gizmos; namespace DotRecast.Recast.Demo.Tools.Gizmos;
@ -12,8 +13,8 @@ public class CompositeGizmo : ColliderGizmo
this.gizmos = gizmos; this.gizmos = gizmos;
} }
public void render(RecastDebugDraw debugDraw) public void Render(RecastDebugDraw debugDraw)
{ {
gizmos.forEach(g => g.render(debugDraw)); gizmos.ForEach(g => g.Render(debugDraw));
} }
} }

View File

@ -23,17 +23,17 @@ public class CylinderGizmo : ColliderGizmo
Vector3f axis = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); Vector3f axis = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
Vector3f[] normals = new Vector3f[3]; Vector3f[] normals = new Vector3f[3];
normals[1] = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); normals[1] = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
normalize(ref normals[1]); Normalize(ref normals[1]);
normals[0] = getSideVector(axis); normals[0] = GetSideVector(axis);
normals[2] = Vector3f.Zero; normals[2] = Vector3f.Zero;
cross(ref normals[2], normals[0], normals[1]); Cross(ref normals[2], normals[0], normals[1]);
normalize(ref normals[2]); Normalize(ref normals[2]);
triangles = generateCylindricalTriangles(); triangles = GenerateCylindricalTriangles();
Vector3f trX = Vector3f.Of(normals[0].x, normals[1].x, normals[2].x); Vector3f trX = Vector3f.Of(normals[0].x, normals[1].x, normals[2].x);
Vector3f trY = Vector3f.Of(normals[0].y, normals[1].y, normals[2].y); Vector3f trY = Vector3f.Of(normals[0].y, normals[1].y, normals[2].y);
Vector3f trZ = Vector3f.Of(normals[0].z, normals[1].z, normals[2].z); Vector3f trZ = Vector3f.Of(normals[0].z, normals[1].z, normals[2].z);
vertices = generateCylindricalVertices(); vertices = GenerateCylindricalVertices();
float halfLength = 0.5f * vLen(axis); float halfLength = 0.5f * VLen(axis);
gradient = new float[vertices.Length / 3]; gradient = new float[vertices.Length / 3];
Vector3f v = new Vector3f(); Vector3f v = new Vector3f();
for (int i = 0; i < vertices.Length; i += 3) for (int i = 0; i < vertices.Length; i += 3)
@ -54,13 +54,13 @@ public class CylinderGizmo : ColliderGizmo
v.x = vertices[i] - center.x; v.x = vertices[i] - center.x;
v.y = vertices[i + 1] - center.y; v.y = vertices[i + 1] - center.y;
v.z = vertices[i + 2] - center.z; v.z = vertices[i + 2] - center.z;
normalize(ref v); Normalize(ref v);
gradient[i / 3] = clamp(0.57735026f * (v.x + v.y + v.z), -1, 1); gradient[i / 3] = Clamp(0.57735026f * (v.x + v.y + v.z), -1, 1);
} }
} }
} }
private Vector3f getSideVector(Vector3f axis) private Vector3f GetSideVector(Vector3f axis)
{ {
Vector3f side = Vector3f.Of(1, 0, 0); Vector3f side = Vector3f.Of(1, 0, 0);
if (axis.x > 0.8) if (axis.x > 0.8)
@ -69,27 +69,27 @@ public class CylinderGizmo : ColliderGizmo
} }
Vector3f forward = new Vector3f(); Vector3f forward = new Vector3f();
cross(ref forward, side, axis); Cross(ref forward, side, axis);
cross(ref side, axis, forward); Cross(ref side, axis, forward);
normalize(ref side); Normalize(ref side);
return side; return side;
} }
public void render(RecastDebugDraw debugDraw) public void Render(RecastDebugDraw debugDraw)
{ {
debugDraw.begin(DebugDrawPrimitives.TRIS); debugDraw.Begin(DebugDrawPrimitives.TRIS);
for (int i = 0; i < triangles.Length; i += 3) for (int i = 0; i < triangles.Length; i += 3)
{ {
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
int v = triangles[i + j] * 3; int v = triangles[i + j] * 3;
float c = gradient[triangles[i + j]]; float c = gradient[triangles[i + j]];
int col = DebugDraw.duLerpCol(DebugDraw.duRGBA(32, 32, 0, 160), DebugDraw.duRGBA(220, 220, 0, 160), int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160),
(int)(127 * (1 + c))); (int)(127 * (1 + c)));
debugDraw.vertex(vertices[v], vertices[v + 1], vertices[v + 2], col); debugDraw.Vertex(vertices[v], vertices[v + 1], vertices[v + 2], col);
} }
} }
debugDraw.end(); debugDraw.End();
} }
} }

View File

@ -4,32 +4,32 @@ namespace DotRecast.Recast.Demo.Tools.Gizmos;
public static class GizmoFactory public static class GizmoFactory
{ {
public static ColliderGizmo box(Vector3f center, Vector3f[] halfEdges) public static ColliderGizmo Box(Vector3f center, Vector3f[] halfEdges)
{ {
return new BoxGizmo(center, halfEdges); return new BoxGizmo(center, halfEdges);
} }
public static ColliderGizmo sphere(Vector3f center, float radius) public static ColliderGizmo Sphere(Vector3f center, float radius)
{ {
return new SphereGizmo(center, radius); return new SphereGizmo(center, radius);
} }
public static ColliderGizmo capsule(Vector3f start, Vector3f end, float radius) public static ColliderGizmo Capsule(Vector3f start, Vector3f end, float radius)
{ {
return new CapsuleGizmo(start, end, radius); return new CapsuleGizmo(start, end, radius);
} }
public static ColliderGizmo cylinder(Vector3f start, Vector3f end, float radius) public static ColliderGizmo Cylinder(Vector3f start, Vector3f end, float radius)
{ {
return new CylinderGizmo(start, end, radius); return new CylinderGizmo(start, end, radius);
} }
public static ColliderGizmo trimesh(float[] verts, int[] faces) public static ColliderGizmo Trimesh(float[] verts, int[] faces)
{ {
return new TrimeshGizmo(verts, faces); return new TrimeshGizmo(verts, faces);
} }
public static ColliderGizmo composite(params ColliderGizmo[] gizmos) public static ColliderGizmo Composite(params ColliderGizmo[] gizmos)
{ {
return new CompositeGizmo(gizmos); return new CompositeGizmo(gizmos);
} }

View File

@ -12,17 +12,17 @@ public class GizmoHelper
private static float[] sphericalVertices; private static float[] sphericalVertices;
public static float[] generateSphericalVertices() public static float[] GenerateSphericalVertices()
{ {
if (sphericalVertices == null) if (sphericalVertices == null)
{ {
sphericalVertices = generateSphericalVertices(SEGMENTS, RINGS); sphericalVertices = GenerateSphericalVertices(SEGMENTS, RINGS);
} }
return sphericalVertices; return sphericalVertices;
} }
private static float[] generateSphericalVertices(int segments, int rings) private static float[] GenerateSphericalVertices(int segments, int rings)
{ {
float[] vertices = new float[6 + 3 * (segments + 1) * (rings + 1)]; float[] vertices = new float[6 + 3 * (segments + 1) * (rings + 1)];
// top // top
@ -33,7 +33,7 @@ public class GizmoHelper
for (int r = 0; r <= rings; r++) for (int r = 0; r <= rings; r++)
{ {
double theta = Math.PI * (r + 1) / (rings + 2); double theta = Math.PI * (r + 1) / (rings + 2);
vi = generateRingVertices(segments, vertices, vi, theta); vi = GenerateRingVertices(segments, vertices, vi, theta);
} }
// bottom // bottom
@ -43,24 +43,24 @@ public class GizmoHelper
return vertices; return vertices;
} }
public static float[] generateCylindricalVertices() public static float[] GenerateCylindricalVertices()
{ {
return generateCylindricalVertices(SEGMENTS); return GenerateCylindricalVertices(SEGMENTS);
} }
private static float[] generateCylindricalVertices(int segments) private static float[] GenerateCylindricalVertices(int segments)
{ {
float[] vertices = new float[3 * (segments + 1) * 4]; float[] vertices = new float[3 * (segments + 1) * 4];
int vi = 0; int vi = 0;
for (int r = 0; r < 4; r++) for (int r = 0; r < 4; r++)
{ {
vi = generateRingVertices(segments, vertices, vi, Math.PI * 0.5); vi = GenerateRingVertices(segments, vertices, vi, Math.PI * 0.5);
} }
return vertices; return vertices;
} }
private static int generateRingVertices(int segments, float[] vertices, int vi, double theta) private static int GenerateRingVertices(int segments, float[] vertices, int vi, double theta)
{ {
double cosTheta = Math.Cos(theta); double cosTheta = Math.Cos(theta);
double sinTheta = Math.Sin(theta); double sinTheta = Math.Sin(theta);
@ -77,21 +77,21 @@ public class GizmoHelper
return vi; return vi;
} }
public static int[] generateSphericalTriangles() public static int[] GenerateSphericalTriangles()
{ {
return generateSphericalTriangles(SEGMENTS, RINGS); return GenerateSphericalTriangles(SEGMENTS, RINGS);
} }
private static int[] generateSphericalTriangles(int segments, int rings) private static int[] GenerateSphericalTriangles(int segments, int rings)
{ {
int[] triangles = new int[6 * (segments + rings * (segments + 1))]; int[] triangles = new int[6 * (segments + rings * (segments + 1))];
int ti = generateSphereUpperCapTriangles(segments, triangles, 0); int ti = GenerateSphereUpperCapTriangles(segments, triangles, 0);
ti = generateRingTriangles(segments, rings, triangles, 1, ti); ti = GenerateRingTriangles(segments, rings, triangles, 1, ti);
generateSphereLowerCapTriangles(segments, rings, triangles, ti); GenerateSphereLowerCapTriangles(segments, rings, triangles, ti);
return triangles; return triangles;
} }
public static int generateRingTriangles(int segments, int rings, int[] triangles, int vertexOffset, int ti) public static int GenerateRingTriangles(int segments, int rings, int[] triangles, int vertexOffset, int ti)
{ {
for (int r = 0; r < rings; r++) for (int r = 0; r < rings; r++)
{ {
@ -113,7 +113,7 @@ public class GizmoHelper
return ti; return ti;
} }
private static int generateSphereUpperCapTriangles(int segments, int[] triangles, int ti) private static int GenerateSphereUpperCapTriangles(int segments, int[] triangles, int ti)
{ {
for (int p = 0; p < segments; p++) for (int p = 0; p < segments; p++)
{ {
@ -125,7 +125,7 @@ public class GizmoHelper
return ti; return ti;
} }
private static void generateSphereLowerCapTriangles(int segments, int rings, int[] triangles, int ti) private static void GenerateSphereLowerCapTriangles(int segments, int rings, int[] triangles, int ti)
{ {
int lastVertex = 1 + (segments + 1) * (rings + 1); int lastVertex = 1 + (segments + 1) * (rings + 1);
for (int p = 0; p < segments; p++) for (int p = 0; p < segments; p++)
@ -136,24 +136,24 @@ public class GizmoHelper
} }
} }
public static int[] generateCylindricalTriangles() public static int[] GenerateCylindricalTriangles()
{ {
return generateCylindricalTriangles(SEGMENTS); return GenerateCylindricalTriangles(SEGMENTS);
} }
private static int[] generateCylindricalTriangles(int segments) private static int[] GenerateCylindricalTriangles(int segments)
{ {
int circleTriangles = segments - 2; int circleTriangles = segments - 2;
int[] triangles = new int[6 * (circleTriangles + (segments + 1))]; int[] triangles = new int[6 * (circleTriangles + (segments + 1))];
int vi = 0; int vi = 0;
int ti = generateCircleTriangles(segments, triangles, vi, 0, false); int ti = GenerateCircleTriangles(segments, triangles, vi, 0, false);
ti = generateRingTriangles(segments, 1, triangles, segments + 1, ti); ti = GenerateRingTriangles(segments, 1, triangles, segments + 1, ti);
int vertexCount = (segments + 1) * 4; int vertexCount = (segments + 1) * 4;
ti = generateCircleTriangles(segments, triangles, vertexCount - segments, ti, true); ti = GenerateCircleTriangles(segments, triangles, vertexCount - segments, ti, true);
return triangles; return triangles;
} }
private static int generateCircleTriangles(int segments, int[] triangles, int vi, int ti, bool invert) private static int GenerateCircleTriangles(int segments, int[] triangles, int vi, int ti, bool invert)
{ {
for (int p = 0; p < segments - 2; p++) for (int p = 0; p < segments - 2; p++)
{ {
@ -174,7 +174,7 @@ public class GizmoHelper
return ti; return ti;
} }
public static int getColorByNormal(float[] vertices, int v0, int v1, int v2) public static int GetColorByNormal(float[] vertices, int v0, int v1, int v2)
{ {
Vector3f e0 = new Vector3f(); Vector3f e0 = new Vector3f();
Vector3f e1 = new Vector3f(); Vector3f e1 = new Vector3f();
@ -188,9 +188,9 @@ public class GizmoHelper
normal.x = e0.y * e1.z - e0.z * e1.y; normal.x = e0.y * e1.z - e0.z * e1.y;
normal.y = e0.z * e1.x - e0.x * e1.z; normal.y = e0.z * e1.x - e0.x * e1.z;
normal.z = e0.x * e1.y - e0.y * e1.x; normal.z = e0.x * e1.y - e0.y * e1.x;
RecastVectors.normalize(ref normal); RecastVectors.Normalize(ref normal);
float c = clamp(0.57735026f * (normal.x + normal.y + normal.z), -1, 1); float c = Clamp(0.57735026f * (normal.x + normal.y + normal.z), -1, 1);
int col = DebugDraw.duLerpCol(DebugDraw.duRGBA(32, 32, 0, 160), DebugDraw.duRGBA(220, 220, 0, 160), int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160),
(int)(127 * (1 + c))); (int)(127 * (1 + c)));
return col; return col;
} }

View File

@ -17,26 +17,26 @@ public class SphereGizmo : ColliderGizmo
{ {
this.center = center; this.center = center;
this.radius = radius; this.radius = radius;
vertices = generateSphericalVertices(); vertices = GenerateSphericalVertices();
triangles = generateSphericalTriangles(); triangles = GenerateSphericalTriangles();
} }
public void render(RecastDebugDraw debugDraw) public void Render(RecastDebugDraw debugDraw)
{ {
debugDraw.begin(DebugDrawPrimitives.TRIS); debugDraw.Begin(DebugDrawPrimitives.TRIS);
for (int i = 0; i < triangles.Length; i += 3) for (int i = 0; i < triangles.Length; i += 3)
{ {
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
int v = triangles[i + j] * 3; int v = triangles[i + j] * 3;
float c = clamp(0.57735026f * (vertices[v] + vertices[v + 1] + vertices[v + 2]), -1, 1); float c = Clamp(0.57735026f * (vertices[v] + vertices[v + 1] + vertices[v + 2]), -1, 1);
int col = DebugDraw.duLerpCol(DebugDraw.duRGBA(32, 32, 0, 160), DebugDraw.duRGBA(220, 220, 0, 160), int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160),
(int)(127 * (1 + c))); (int)(127 * (1 + c)));
debugDraw.vertex(radius * vertices[v] + center.x, radius * vertices[v + 1] + center.y, debugDraw.Vertex(radius * vertices[v] + center.x, radius * vertices[v + 1] + center.y,
radius * vertices[v + 2] + center.z, col); radius * vertices[v + 2] + center.z, col);
} }
} }
debugDraw.end(); debugDraw.End();
} }
} }

View File

@ -13,20 +13,20 @@ public class TrimeshGizmo : ColliderGizmo
this.triangles = triangles; this.triangles = triangles;
} }
public void render(RecastDebugDraw debugDraw) public void Render(RecastDebugDraw debugDraw)
{ {
debugDraw.begin(DebugDrawPrimitives.TRIS); debugDraw.Begin(DebugDrawPrimitives.TRIS);
for (int i = 0; i < triangles.Length; i += 3) for (int i = 0; i < triangles.Length; i += 3)
{ {
int v0 = 3 * triangles[i]; int v0 = 3 * triangles[i];
int v1 = 3 * triangles[i + 1]; int v1 = 3 * triangles[i + 1];
int v2 = 3 * triangles[i + 2]; int v2 = 3 * triangles[i + 2];
int col = GizmoHelper.getColorByNormal(vertices, v0, v1, v2); int col = GizmoHelper.GetColorByNormal(vertices, v0, v1, v2);
debugDraw.vertex(vertices[v0], vertices[v0 + 1], vertices[v0 + 2], col); debugDraw.Vertex(vertices[v0], vertices[v0 + 1], vertices[v0 + 2], col);
debugDraw.vertex(vertices[v1], vertices[v1 + 1], vertices[v1 + 2], col); debugDraw.Vertex(vertices[v1], vertices[v1 + 1], vertices[v1 + 2], col);
debugDraw.vertex(vertices[v2], vertices[v2 + 1], vertices[v2 + 2], col); debugDraw.Vertex(vertices[v2], vertices[v2 + 1], vertices[v2 + 2], col);
} }
debugDraw.end(); debugDraw.End();
} }
} }

View File

@ -39,124 +39,124 @@ public class JumpLinkBuilderTool : Tool
private readonly int selEdge = -1; private readonly int selEdge = -1;
private readonly JumpLinkBuilderToolParams option = new JumpLinkBuilderToolParams(); private readonly JumpLinkBuilderToolParams option = new JumpLinkBuilderToolParams();
public override void setSample(Sample sample) public override void SetSample(Sample sample)
{ {
this.sample = sample; this.sample = sample;
annotationBuilder = null; annotationBuilder = null;
} }
public override void handleClick(Vector3f s, Vector3f p, bool shift) public override void HandleClick(Vector3f s, Vector3f p, bool shift)
{ {
} }
public override void handleRender(NavMeshRenderer renderer) public override void HandleRender(NavMeshRenderer renderer)
{ {
int col0 = duLerpCol(duRGBA(32, 255, 96, 255), duRGBA(255, 255, 255, 255), 200); int col0 = DuLerpCol(DuRGBA(32, 255, 96, 255), DuRGBA(255, 255, 255, 255), 200);
int col1 = duRGBA(32, 255, 96, 255); int col1 = DuRGBA(32, 255, 96, 255);
RecastDebugDraw dd = renderer.getDebugDraw(); RecastDebugDraw dd = renderer.GetDebugDraw();
dd.depthMask(false); dd.DepthMask(false);
if ((option.flags & JumpLinkBuilderToolParams.DRAW_WALKABLE_BORDER) != 0) if ((option.flags & JumpLinkBuilderToolParams.DRAW_WALKABLE_BORDER) != 0)
{ {
if (annotationBuilder != null) if (annotationBuilder != null)
{ {
foreach (Edge[] edges in annotationBuilder.getEdges()) foreach (Edge[] edges in annotationBuilder.GetEdges())
{ {
dd.begin(LINES, 3.0f); dd.Begin(LINES, 3.0f);
for (int i = 0; i < edges.Length; ++i) for (int i = 0; i < edges.Length; ++i)
{ {
int col = duRGBA(0, 96, 128, 255); int col = DuRGBA(0, 96, 128, 255);
if (i == selEdge) if (i == selEdge)
continue; continue;
dd.vertex(edges[i].sp, col); dd.Vertex(edges[i].sp, col);
dd.vertex(edges[i].sq, col); dd.Vertex(edges[i].sq, col);
} }
dd.end(); dd.End();
dd.begin(POINTS, 8.0f); dd.Begin(POINTS, 8.0f);
for (int i = 0; i < edges.Length; ++i) for (int i = 0; i < edges.Length; ++i)
{ {
int col = duRGBA(0, 96, 128, 255); int col = DuRGBA(0, 96, 128, 255);
if (i == selEdge) if (i == selEdge)
continue; continue;
dd.vertex(edges[i].sp, col); dd.Vertex(edges[i].sp, col);
dd.vertex(edges[i].sq, col); dd.Vertex(edges[i].sq, col);
} }
dd.end(); dd.End();
if (selEdge >= 0 && selEdge < edges.Length) if (selEdge >= 0 && selEdge < edges.Length)
{ {
int col = duRGBA(48, 16, 16, 255); // duRGBA(255,192,0,255); int col = DuRGBA(48, 16, 16, 255); // DuRGBA(255,192,0,255);
dd.begin(LINES, 3.0f); dd.Begin(LINES, 3.0f);
dd.vertex(edges[selEdge].sp, col); dd.Vertex(edges[selEdge].sp, col);
dd.vertex(edges[selEdge].sq, col); dd.Vertex(edges[selEdge].sq, col);
dd.end(); dd.End();
dd.begin(POINTS, 8.0f); dd.Begin(POINTS, 8.0f);
dd.vertex(edges[selEdge].sp, col); dd.Vertex(edges[selEdge].sp, col);
dd.vertex(edges[selEdge].sq, col); dd.Vertex(edges[selEdge].sq, col);
dd.end(); dd.End();
} }
dd.begin(POINTS, 4.0f); dd.Begin(POINTS, 4.0f);
for (int i = 0; i < edges.Length; ++i) for (int i = 0; i < edges.Length; ++i)
{ {
int col = duRGBA(190, 190, 190, 255); int col = DuRGBA(190, 190, 190, 255);
dd.vertex(edges[i].sp, col); dd.Vertex(edges[i].sp, col);
dd.vertex(edges[i].sq, col); dd.Vertex(edges[i].sq, col);
} }
dd.end(); dd.End();
} }
} }
} }
if ((option.flags & JumpLinkBuilderToolParams.DRAW_ANNOTATIONS) != 0) if ((option.flags & JumpLinkBuilderToolParams.DRAW_ANNOTATIONS) != 0)
{ {
dd.begin(QUADS); dd.Begin(QUADS);
foreach (JumpLink link in links) foreach (JumpLink link in links)
{ {
for (int j = 0; j < link.nspine - 1; ++j) for (int j = 0; j < link.nspine - 1; ++j)
{ {
int u = (j * 255) / link.nspine; int u = (j * 255) / link.nspine;
int col = duTransCol(duLerpCol(col0, col1, u), 128); int col = DuTransCol(DuLerpCol(col0, col1, u), 128);
dd.vertex(link.spine1[j * 3], link.spine1[j * 3 + 1], link.spine1[j * 3 + 2], col); dd.Vertex(link.spine1[j * 3], link.spine1[j * 3 + 1], link.spine1[j * 3 + 2], col);
dd.vertex(link.spine1[(j + 1) * 3], link.spine1[(j + 1) * 3 + 1], link.spine1[(j + 1) * 3 + 2], dd.Vertex(link.spine1[(j + 1) * 3], link.spine1[(j + 1) * 3 + 1], link.spine1[(j + 1) * 3 + 2],
col); col);
dd.vertex(link.spine0[(j + 1) * 3], link.spine0[(j + 1) * 3 + 1], link.spine0[(j + 1) * 3 + 2], dd.Vertex(link.spine0[(j + 1) * 3], link.spine0[(j + 1) * 3 + 1], link.spine0[(j + 1) * 3 + 2],
col); col);
dd.vertex(link.spine0[j * 3], link.spine0[j * 3 + 1], link.spine0[j * 3 + 2], col); dd.Vertex(link.spine0[j * 3], link.spine0[j * 3 + 1], link.spine0[j * 3 + 2], col);
} }
} }
dd.end(); dd.End();
dd.begin(LINES, 3.0f); dd.Begin(LINES, 3.0f);
foreach (JumpLink link in links) foreach (JumpLink link in links)
{ {
for (int j = 0; j < link.nspine - 1; ++j) for (int j = 0; j < link.nspine - 1; ++j)
{ {
// int u = (j*255)/link.nspine; // int u = (j*255)/link.nspine;
int col = duTransCol(duDarkenCol(col1) /*duDarkenCol(duLerpCol(col0,col1,u))*/, 128); int col = DuTransCol(DuDarkenCol(col1) /*DuDarkenCol(DuLerpCol(col0,col1,u))*/, 128);
dd.vertex(link.spine0[j * 3], link.spine0[j * 3 + 1], link.spine0[j * 3 + 2], col); dd.Vertex(link.spine0[j * 3], link.spine0[j * 3 + 1], link.spine0[j * 3 + 2], col);
dd.vertex(link.spine0[(j + 1) * 3], link.spine0[(j + 1) * 3 + 1], link.spine0[(j + 1) * 3 + 2], dd.Vertex(link.spine0[(j + 1) * 3], link.spine0[(j + 1) * 3 + 1], link.spine0[(j + 1) * 3 + 2],
col); col);
dd.vertex(link.spine1[j * 3], link.spine1[j * 3 + 1], link.spine1[j * 3 + 2], col); dd.Vertex(link.spine1[j * 3], link.spine1[j * 3 + 1], link.spine1[j * 3 + 2], col);
dd.vertex(link.spine1[(j + 1) * 3], link.spine1[(j + 1) * 3 + 1], link.spine1[(j + 1) * 3 + 2], dd.Vertex(link.spine1[(j + 1) * 3], link.spine1[(j + 1) * 3 + 1], link.spine1[(j + 1) * 3 + 2],
col); col);
} }
dd.vertex(link.spine0[0], link.spine0[1], link.spine0[2], duDarkenCol(col1)); dd.Vertex(link.spine0[0], link.spine0[1], link.spine0[2], DuDarkenCol(col1));
dd.vertex(link.spine1[0], link.spine1[1], link.spine1[2], duDarkenCol(col1)); dd.Vertex(link.spine1[0], link.spine1[1], link.spine1[2], DuDarkenCol(col1));
dd.vertex(link.spine0[(link.nspine - 1) * 3], link.spine0[(link.nspine - 1) * 3 + 1], dd.Vertex(link.spine0[(link.nspine - 1) * 3], link.spine0[(link.nspine - 1) * 3 + 1],
link.spine0[(link.nspine - 1) * 3 + 2], duDarkenCol(col1)); link.spine0[(link.nspine - 1) * 3 + 2], DuDarkenCol(col1));
dd.vertex(link.spine1[(link.nspine - 1) * 3], link.spine1[(link.nspine - 1) * 3 + 1], dd.Vertex(link.spine1[(link.nspine - 1) * 3], link.spine1[(link.nspine - 1) * 3 + 1],
link.spine1[(link.nspine - 1) * 3 + 2], duDarkenCol(col1)); link.spine1[(link.nspine - 1) * 3 + 2], DuDarkenCol(col1));
} }
dd.end(); dd.End();
} }
if (annotationBuilder != null) if (annotationBuilder != null)
@ -167,97 +167,97 @@ public class JumpLinkBuilderTool : Tool
{ {
float r = link.start.height; float r = link.start.height;
int col = duLerpCol(duRGBA(255, 192, 0, 255), int col = DuLerpCol(DuRGBA(255, 192, 0, 255),
duRGBA(255, 255, 255, 255), 64); DuRGBA(255, 255, 255, 255), 64);
int cola = duTransCol(col, 192); int cola = DuTransCol(col, 192);
int colb = duRGBA(255, 255, 255, 255); int colb = DuRGBA(255, 255, 255, 255);
// Start segment. // Start segment.
dd.begin(LINES, 3.0f); dd.Begin(LINES, 3.0f);
dd.vertex(link.start.p, col); dd.Vertex(link.start.p, col);
dd.vertex(link.start.q, col); dd.Vertex(link.start.q, col);
dd.end(); dd.End();
dd.begin(LINES, 1.0f); dd.Begin(LINES, 1.0f);
dd.vertex(link.start.p.x, link.start.p.y, link.start.p.z, colb); dd.Vertex(link.start.p.x, link.start.p.y, link.start.p.z, colb);
dd.vertex(link.start.p.x, link.start.p.y + r, link.start.p.z, colb); dd.Vertex(link.start.p.x, link.start.p.y + r, link.start.p.z, colb);
dd.vertex(link.start.p.x, link.start.p.y + r, link.start.p.z, colb); dd.Vertex(link.start.p.x, link.start.p.y + r, link.start.p.z, colb);
dd.vertex(link.start.q.x, link.start.q.y + r, link.start.q.z, colb); dd.Vertex(link.start.q.x, link.start.q.y + r, link.start.q.z, colb);
dd.vertex(link.start.q.x, link.start.q.y + r, link.start.q.z, colb); dd.Vertex(link.start.q.x, link.start.q.y + r, link.start.q.z, colb);
dd.vertex(link.start.q.x, link.start.q.y, link.start.q.z, colb); dd.Vertex(link.start.q.x, link.start.q.y, link.start.q.z, colb);
dd.vertex(link.start.q.x, link.start.q.y, link.start.q.z, colb); dd.Vertex(link.start.q.x, link.start.q.y, link.start.q.z, colb);
dd.vertex(link.start.p.x, link.start.p.y, link.start.p.z, colb); dd.Vertex(link.start.p.x, link.start.p.y, link.start.p.z, colb);
dd.end(); dd.End();
GroundSegment end = link.end; GroundSegment end = link.end;
r = end.height; r = end.height;
// End segment. // End segment.
dd.begin(LINES, 3.0f); dd.Begin(LINES, 3.0f);
dd.vertex(end.p, col); dd.Vertex(end.p, col);
dd.vertex(end.q, col); dd.Vertex(end.q, col);
dd.end(); dd.End();
dd.begin(LINES, 1.0f); dd.Begin(LINES, 1.0f);
dd.vertex(end.p.x, end.p.y, end.p.z, colb); dd.Vertex(end.p.x, end.p.y, end.p.z, colb);
dd.vertex(end.p.x, end.p.y + r, end.p.z, colb); dd.Vertex(end.p.x, end.p.y + r, end.p.z, colb);
dd.vertex(end.p.x, end.p.y + r, end.p.z, colb); dd.Vertex(end.p.x, end.p.y + r, end.p.z, colb);
dd.vertex(end.q.x, end.q.y + r, end.q.z, colb); dd.Vertex(end.q.x, end.q.y + r, end.q.z, colb);
dd.vertex(end.q.x, end.q.y + r, end.q.z, colb); dd.Vertex(end.q.x, end.q.y + r, end.q.z, colb);
dd.vertex(end.q.x, end.q.y, end.q.z, colb); dd.Vertex(end.q.x, end.q.y, end.q.z, colb);
dd.vertex(end.q.x, end.q.y, end.q.z, colb); dd.Vertex(end.q.x, end.q.y, end.q.z, colb);
dd.vertex(end.p.x, end.p.y, end.p.z, colb); dd.Vertex(end.p.x, end.p.y, end.p.z, colb);
dd.end(); dd.End();
dd.begin(LINES, 4.0f); dd.Begin(LINES, 4.0f);
drawTrajectory(dd, link, link.start.p, end.p, link.trajectory, cola); DrawTrajectory(dd, link, link.start.p, end.p, link.trajectory, cola);
drawTrajectory(dd, link, link.start.q, end.q, link.trajectory, cola); DrawTrajectory(dd, link, link.start.q, end.q, link.trajectory, cola);
dd.end(); dd.End();
dd.begin(LINES, 8.0f); dd.Begin(LINES, 8.0f);
dd.vertex(link.start.p, duDarkenCol(col)); dd.Vertex(link.start.p, DuDarkenCol(col));
dd.vertex(link.start.q, duDarkenCol(col)); dd.Vertex(link.start.q, DuDarkenCol(col));
dd.vertex(end.p, duDarkenCol(col)); dd.Vertex(end.p, DuDarkenCol(col));
dd.vertex(end.q, duDarkenCol(col)); dd.Vertex(end.q, DuDarkenCol(col));
dd.end(); dd.End();
int colm = duRGBA(255, 255, 255, 255); int colm = DuRGBA(255, 255, 255, 255);
dd.begin(LINES, 3.0f); dd.Begin(LINES, 3.0f);
dd.vertex(link.start.p, colm); dd.Vertex(link.start.p, colm);
dd.vertex(link.start.q, colm); dd.Vertex(link.start.q, colm);
dd.vertex(end.p, colm); dd.Vertex(end.p, colm);
dd.vertex(end.q, colm); dd.Vertex(end.q, colm);
dd.end(); dd.End();
} }
if ((option.flags & JumpLinkBuilderToolParams.DRAW_LAND_SAMPLES) != 0) if ((option.flags & JumpLinkBuilderToolParams.DRAW_LAND_SAMPLES) != 0)
{ {
dd.begin(POINTS, 8.0f); dd.Begin(POINTS, 8.0f);
for (int i = 0; i < link.start.gsamples.Length; ++i) for (int i = 0; i < link.start.gsamples.Length; ++i)
{ {
GroundSample s = link.start.gsamples[i]; GroundSample s = link.start.gsamples[i];
float u = i / (float)(link.start.gsamples.Length - 1); float u = i / (float)(link.start.gsamples.Length - 1);
Vector3f spt = vLerp(link.start.p, link.start.q, u); Vector3f spt = VLerp(link.start.p, link.start.q, u);
int col = duRGBA(48, 16, 16, 255); // duRGBA(255,(s->flags & 4)?255:0,0,255); int col = DuRGBA(48, 16, 16, 255); // DuRGBA(255,(s->flags & 4)?255:0,0,255);
float off = 0.1f; float off = 0.1f;
if (!s.validHeight) if (!s.validHeight)
{ {
off = 0; off = 0;
col = duRGBA(220, 32, 32, 255); col = DuRGBA(220, 32, 32, 255);
} }
spt.y = s.p.y + off; spt.y = s.p.y + off;
dd.vertex(spt, col); dd.Vertex(spt, col);
} }
dd.end(); dd.End();
dd.begin(POINTS, 4.0f); dd.Begin(POINTS, 4.0f);
for (int i = 0; i < link.start.gsamples.Length; ++i) for (int i = 0; i < link.start.gsamples.Length; ++i)
{ {
GroundSample s = link.start.gsamples[i]; GroundSample s = link.start.gsamples[i];
float u = i / (float)(link.start.gsamples.Length - 1); float u = i / (float)(link.start.gsamples.Length - 1);
Vector3f spt = vLerp(link.start.p, link.start.q, u); Vector3f spt = VLerp(link.start.p, link.start.q, u);
int col = duRGBA(255, 255, 255, 255); int col = DuRGBA(255, 255, 255, 255);
float off = 0; float off = 0;
if (s.validHeight) if (s.validHeight)
{ {
@ -265,38 +265,38 @@ public class JumpLinkBuilderTool : Tool
} }
spt.y = s.p.y + off; spt.y = s.p.y + off;
dd.vertex(spt, col); dd.Vertex(spt, col);
} }
dd.end(); dd.End();
{ {
GroundSegment end = link.end; GroundSegment end = link.end;
dd.begin(POINTS, 8.0f); dd.Begin(POINTS, 8.0f);
for (int i = 0; i < end.gsamples.Length; ++i) for (int i = 0; i < end.gsamples.Length; ++i)
{ {
GroundSample s = end.gsamples[i]; GroundSample s = end.gsamples[i];
float u = i / (float)(end.gsamples.Length - 1); float u = i / (float)(end.gsamples.Length - 1);
Vector3f spt = vLerp(end.p, end.q, u); Vector3f spt = VLerp(end.p, end.q, u);
int col = duRGBA(48, 16, 16, 255); // duRGBA(255,(s->flags & 4)?255:0,0,255); int col = DuRGBA(48, 16, 16, 255); // DuRGBA(255,(s->flags & 4)?255:0,0,255);
float off = 0.1f; float off = 0.1f;
if (!s.validHeight) if (!s.validHeight)
{ {
off = 0; off = 0;
col = duRGBA(220, 32, 32, 255); col = DuRGBA(220, 32, 32, 255);
} }
spt.y = s.p.y + off; spt.y = s.p.y + off;
dd.vertex(spt, col); dd.Vertex(spt, col);
} }
dd.end(); dd.End();
dd.begin(POINTS, 4.0f); dd.Begin(POINTS, 4.0f);
for (int i = 0; i < end.gsamples.Length; ++i) for (int i = 0; i < end.gsamples.Length; ++i)
{ {
GroundSample s = end.gsamples[i]; GroundSample s = end.gsamples[i];
float u = i / (float)(end.gsamples.Length - 1); float u = i / (float)(end.gsamples.Length - 1);
Vector3f spt = vLerp(end.p, end.q, u); Vector3f spt = VLerp(end.p, end.q, u);
int col = duRGBA(255, 255, 255, 255); int col = DuRGBA(255, 255, 255, 255);
float off = 0; float off = 0;
if (s.validHeight) if (s.validHeight)
{ {
@ -304,29 +304,29 @@ public class JumpLinkBuilderTool : Tool
} }
spt.y = s.p.y + off; spt.y = s.p.y + off;
dd.vertex(spt, col); dd.Vertex(spt, col);
} }
dd.end(); dd.End();
} }
} }
} }
} }
dd.depthMask(true); dd.DepthMask(true);
} }
private void drawTrajectory(RecastDebugDraw dd, JumpLink link, Vector3f pa, Vector3f pb, Trajectory tra, int cola) private void DrawTrajectory(RecastDebugDraw dd, JumpLink link, Vector3f pa, Vector3f pb, Trajectory tra, int cola)
{ {
} }
public override void handleUpdate(float dt) public override void HandleUpdate(float dt)
{ {
} }
public override void layout() public override void Layout()
{ {
if (0 >= sample.getRecastResults().Count) if (0 >= sample.GetRecastResults().Count)
return; return;
ImGui.Text("Options"); ImGui.Text("Options");
@ -371,27 +371,27 @@ public class JumpLinkBuilderTool : Tool
{ {
if (annotationBuilder == null) if (annotationBuilder == null)
{ {
if (sample != null && 0 < sample.getRecastResults().Count) if (sample != null && 0 < sample.GetRecastResults().Count)
{ {
annotationBuilder = new JumpLinkBuilder(sample.getRecastResults()); annotationBuilder = new JumpLinkBuilder(sample.GetRecastResults());
} }
} }
links.Clear(); links.Clear();
if (annotationBuilder != null) if (annotationBuilder != null)
{ {
float cellSize = sample.getSettingsUI().getCellSize(); float cellSize = sample.GetSettingsUI().GetCellSize();
float agentHeight = sample.getSettingsUI().getAgentHeight(); float agentHeight = sample.GetSettingsUI().GetAgentHeight();
float agentRadius = sample.getSettingsUI().getAgentRadius(); float agentRadius = sample.GetSettingsUI().GetAgentRadius();
float agentClimb = sample.getSettingsUI().getAgentMaxClimb(); float agentClimb = sample.GetSettingsUI().GetAgentMaxClimb();
float cellHeight = sample.getSettingsUI().getCellHeight(); float cellHeight = sample.GetSettingsUI().GetCellHeight();
if ((option.buildTypes & JumpLinkType.EDGE_CLIMB_DOWN.Bit) != 0) if ((option.buildTypes & JumpLinkType.EDGE_CLIMB_DOWN.Bit) != 0)
{ {
JumpLinkBuilderConfig config = new JumpLinkBuilderConfig(cellSize, cellHeight, agentRadius, JumpLinkBuilderConfig config = new JumpLinkBuilderConfig(cellSize, cellHeight, agentRadius,
agentHeight, agentClimb, option.groundTolerance, -agentRadius * 0.2f, agentHeight, agentClimb, option.groundTolerance, -agentRadius * 0.2f,
cellSize + 2 * agentRadius + option.climbDownDistance, cellSize + 2 * agentRadius + option.climbDownDistance,
-option.climbDownMaxHeight, -option.climbDownMinHeight, 0); -option.climbDownMaxHeight, -option.climbDownMinHeight, 0);
links.AddRange(annotationBuilder.build(config, JumpLinkType.EDGE_CLIMB_DOWN)); links.AddRange(annotationBuilder.Build(config, JumpLinkType.EDGE_CLIMB_DOWN));
} }
if ((option.buildTypes & JumpLinkType.EDGE_JUMP.Bit) != 0) if ((option.buildTypes & JumpLinkType.EDGE_JUMP.Bit) != 0)
@ -400,17 +400,17 @@ public class JumpLinkBuilderTool : Tool
agentHeight, agentClimb, option.groundTolerance, -agentRadius * 0.2f, agentHeight, agentClimb, option.groundTolerance, -agentRadius * 0.2f,
option.edgeJumpEndDistance, -option.edgeJumpDownMaxHeight, option.edgeJumpEndDistance, -option.edgeJumpDownMaxHeight,
option.edgeJumpUpMaxHeight, option.edgeJumpHeight); option.edgeJumpUpMaxHeight, option.edgeJumpHeight);
links.AddRange(annotationBuilder.build(config, JumpLinkType.EDGE_JUMP)); links.AddRange(annotationBuilder.Build(config, JumpLinkType.EDGE_JUMP));
} }
if (buildOffMeshConnections) if (buildOffMeshConnections)
{ {
DemoInputGeomProvider geom = sample.getInputGeom(); DemoInputGeomProvider geom = sample.GetInputGeom();
if (geom != null) if (geom != null)
{ {
int area = SampleAreaModifications.SAMPLE_POLYAREA_TYPE_JUMP_AUTO; int area = SampleAreaModifications.SAMPLE_POLYAREA_TYPE_JUMP_AUTO;
geom.removeOffMeshConnections(c => c.area == area); geom.RemoveOffMeshConnections(c => c.area == area);
links.forEach(l => addOffMeshLink(l, geom, agentRadius)); links.ForEach(l => AddOffMeshLink(l, geom, agentRadius));
} }
} }
} }
@ -427,7 +427,7 @@ public class JumpLinkBuilderTool : Tool
//option.flags = newFlags; //option.flags = newFlags;
} }
private void addOffMeshLink(JumpLink link, DemoInputGeomProvider geom, float agentRadius) private void AddOffMeshLink(JumpLink link, DemoInputGeomProvider geom, float agentRadius)
{ {
int area = SampleAreaModifications.SAMPLE_POLYAREA_TYPE_JUMP_AUTO; int area = SampleAreaModifications.SAMPLE_POLYAREA_TYPE_JUMP_AUTO;
int flags = SampleAreaModifications.SAMPLE_POLYFLAGS_JUMP; int flags = SampleAreaModifications.SAMPLE_POLYFLAGS_JUMP;
@ -436,15 +436,15 @@ public class JumpLinkBuilderTool : Tool
{ {
Vector3f p = link.startSamples[i].p; Vector3f p = link.startSamples[i].p;
Vector3f q = link.endSamples[i].p; Vector3f q = link.endSamples[i].p;
if (i == 0 || vDist2D(prev, p) > agentRadius) if (i == 0 || VDist2D(prev, p) > agentRadius)
{ {
geom.addOffMeshConnection(p, q, agentRadius, false, area, flags); geom.AddOffMeshConnection(p, q, agentRadius, false, area, flags);
prev = p; prev = p;
} }
} }
} }
public override string getName() public override string GetName()
{ {
return "Annotation Builder"; return "Annotation Builder";
} }

View File

@ -36,14 +36,14 @@ public class OffMeshConnectionTool : Tool
private Vector3f hitPos; private Vector3f hitPos;
private int bidir; private int bidir;
public override void setSample(Sample m_sample) public override void SetSample(Sample m_sample)
{ {
sample = m_sample; sample = m_sample;
} }
public override void handleClick(Vector3f s, Vector3f p, bool shift) public override void HandleClick(Vector3f s, Vector3f p, bool shift)
{ {
DemoInputGeomProvider geom = sample.getInputGeom(); DemoInputGeomProvider geom = sample.GetInputGeom();
if (geom == null) if (geom == null)
{ {
return; return;
@ -55,10 +55,10 @@ public class OffMeshConnectionTool : Tool
// Find nearest link end-point // Find nearest link end-point
float nearestDist = float.MaxValue; float nearestDist = float.MaxValue;
DemoOffMeshConnection nearestConnection = null; DemoOffMeshConnection nearestConnection = null;
foreach (DemoOffMeshConnection offMeshCon in geom.getOffMeshConnections()) foreach (DemoOffMeshConnection offMeshCon in geom.GetOffMeshConnections())
{ {
float d = Math.Min(RecastMath.vDistSqr(p, offMeshCon.verts, 0), RecastMath.vDistSqr(p, offMeshCon.verts, 3)); float d = Math.Min(RecastMath.VDistSqr(p, offMeshCon.verts, 0), RecastMath.VDistSqr(p, offMeshCon.verts, 3));
if (d < nearestDist && Math.Sqrt(d) < sample.getSettingsUI().getAgentRadius()) if (d < nearestDist && Math.Sqrt(d) < sample.GetSettingsUI().GetAgentRadius())
{ {
nearestDist = d; nearestDist = d;
nearestConnection = offMeshCon; nearestConnection = offMeshCon;
@ -67,7 +67,7 @@ public class OffMeshConnectionTool : Tool
if (nearestConnection != null) if (nearestConnection != null)
{ {
geom.getOffMeshConnections().Remove(nearestConnection); geom.GetOffMeshConnections().Remove(nearestConnection);
} }
} }
else else
@ -82,46 +82,46 @@ public class OffMeshConnectionTool : Tool
{ {
int area = SampleAreaModifications.SAMPLE_POLYAREA_TYPE_JUMP; int area = SampleAreaModifications.SAMPLE_POLYAREA_TYPE_JUMP;
int flags = SampleAreaModifications.SAMPLE_POLYFLAGS_JUMP; int flags = SampleAreaModifications.SAMPLE_POLYFLAGS_JUMP;
geom.addOffMeshConnection(hitPos, p, sample.getSettingsUI().getAgentRadius(), 0 == bidir, area, flags); geom.AddOffMeshConnection(hitPos, p, sample.GetSettingsUI().GetAgentRadius(), 0 == bidir, area, flags);
hitPosSet = false; hitPosSet = false;
} }
} }
} }
public override void handleRender(NavMeshRenderer renderer) public override void HandleRender(NavMeshRenderer renderer)
{ {
if (sample == null) if (sample == null)
{ {
return; return;
} }
RecastDebugDraw dd = renderer.getDebugDraw(); RecastDebugDraw dd = renderer.GetDebugDraw();
float s = sample.getSettingsUI().getAgentRadius(); float s = sample.GetSettingsUI().GetAgentRadius();
if (hitPosSet) if (hitPosSet)
{ {
dd.debugDrawCross(hitPos.x, hitPos.y + 0.1f, hitPos.z, s, duRGBA(0, 0, 0, 128), 2.0f); dd.DebugDrawCross(hitPos.x, hitPos.y + 0.1f, hitPos.z, s, DuRGBA(0, 0, 0, 128), 2.0f);
} }
DemoInputGeomProvider geom = sample.getInputGeom(); DemoInputGeomProvider geom = sample.GetInputGeom();
if (geom != null) if (geom != null)
{ {
renderer.drawOffMeshConnections(geom, true); renderer.DrawOffMeshConnections(geom, true);
} }
} }
public override void layout() public override void Layout()
{ {
ImGui.RadioButton("One Way", ref bidir, 0); ImGui.RadioButton("One Way", ref bidir, 0);
ImGui.RadioButton("Bidirectional", ref bidir, 1); ImGui.RadioButton("Bidirectional", ref bidir, 1);
} }
public override string getName() public override string GetName()
{ {
return "Create Off-Mesh Links"; return "Create Off-Mesh Links";
} }
public override void handleUpdate(float dt) public override void HandleUpdate(float dt)
{ {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }

File diff suppressed because it is too large Load Diff

View File

@ -26,19 +26,19 @@ namespace DotRecast.Recast.Demo.Tools;
public abstract class Tool public abstract class Tool
{ {
public abstract void setSample(Sample m_sample); public abstract void SetSample(Sample m_sample);
public abstract void handleClick(Vector3f s, Vector3f p, bool shift); public abstract void HandleClick(Vector3f s, Vector3f p, bool shift);
public abstract void handleRender(NavMeshRenderer renderer); public abstract void HandleRender(NavMeshRenderer renderer);
public abstract void handleUpdate(float dt); public abstract void HandleUpdate(float dt);
public abstract void layout(); public abstract void Layout();
public abstract string getName(); public abstract string GetName();
public virtual void handleClickRay(Vector3f start, float[] direction, bool shift) public virtual void HandleClickRay(Vector3f start, float[] direction, bool shift)
{ {
// ... // ...
} }

View File

@ -22,5 +22,5 @@ namespace DotRecast.Recast.Demo.Tools;
public interface ToolUIModule public interface ToolUIModule
{ {
void layout(IWindow ctx); void Layout(IWindow ctx);
} }

View File

@ -59,9 +59,9 @@ public class RcSettingsView : IRcView
private bool tiled = false; private bool tiled = false;
private int tileSize = 32; private int tileSize = 32;
// public readonly NkColor white = NkColor.create(); // public readonly NkColor white = NkColor.Create();
// public readonly NkColor background = NkColor.create(); // public readonly NkColor background = NkColor.Create();
// public readonly NkColor transparent = NkColor.create(); // public readonly NkColor transparent = NkColor.Create();
private bool buildTriggered; private bool buildTriggered;
private long buildTime; private long buildTime;
private readonly int[] voxels = new int[2]; private readonly int[] voxels = new int[2];
@ -154,7 +154,7 @@ public class RcSettingsView : IRcView
ImGui.Text("Partitioning"); ImGui.Text("Partitioning");
ImGui.Separator(); ImGui.Separator();
PartitionType.Values.forEach(partition => PartitionType.Values.ForEach(partition =>
{ {
var label = partition.Name.Substring(0, 1).ToUpper() var label = partition.Name.Substring(0, 1).ToUpper()
+ partition.Name.Substring(1).ToLower(); + partition.Name.Substring(1).ToLower();
@ -226,145 +226,145 @@ public class RcSettingsView : IRcView
ImGui.Text("Draw"); ImGui.Text("Draw");
ImGui.Separator(); ImGui.Separator();
DrawMode.Values.forEach(dm => { ImGui.RadioButton(dm.Text, ref drawMode, dm.Idx); }); DrawMode.Values.ForEach(dm => { ImGui.RadioButton(dm.Text, ref drawMode, dm.Idx); });
ImGui.NewLine(); ImGui.NewLine();
ImGui.End(); ImGui.End();
} }
public float getCellSize() public float GetCellSize()
{ {
return cellSize; return cellSize;
} }
public float getCellHeight() public float GetCellHeight()
{ {
return cellHeight; return cellHeight;
} }
public float getAgentHeight() public float GetAgentHeight()
{ {
return agentHeight; return agentHeight;
} }
public float getAgentRadius() public float GetAgentRadius()
{ {
return agentRadius; return agentRadius;
} }
public float getAgentMaxClimb() public float GetAgentMaxClimb()
{ {
return agentMaxClimb; return agentMaxClimb;
} }
public float getAgentMaxSlope() public float GetAgentMaxSlope()
{ {
return agentMaxSlope; return agentMaxSlope;
} }
public int getMinRegionSize() public int GetMinRegionSize()
{ {
return minRegionSize; return minRegionSize;
} }
public int getMergedRegionSize() public int GetMergedRegionSize()
{ {
return mergedRegionSize; return mergedRegionSize;
} }
public PartitionType getPartitioning() public PartitionType GetPartitioning()
{ {
return partitioning; return partitioning;
} }
public bool isBuildTriggered() public bool IsBuildTriggered()
{ {
return buildTriggered; return buildTriggered;
} }
public bool isFilterLowHangingObstacles() public bool IsFilterLowHangingObstacles()
{ {
return filterLowHangingObstacles; return filterLowHangingObstacles;
} }
public bool isFilterLedgeSpans() public bool IsFilterLedgeSpans()
{ {
return filterLedgeSpans; return filterLedgeSpans;
} }
public bool isFilterWalkableLowHeightSpans() public bool IsFilterWalkableLowHeightSpans()
{ {
return filterWalkableLowHeightSpans; return filterWalkableLowHeightSpans;
} }
public void setBuildTime(long buildTime) public void SetBuildTime(long buildTime)
{ {
this.buildTime = buildTime; this.buildTime = buildTime;
} }
public DrawMode getDrawMode() public DrawMode GetDrawMode()
{ {
return DrawMode.Values[drawMode]; return DrawMode.Values[drawMode];
} }
public float getEdgeMaxLen() public float GetEdgeMaxLen()
{ {
return edgeMaxLen; return edgeMaxLen;
} }
public float getEdgeMaxError() public float GetEdgeMaxError()
{ {
return edgeMaxError; return edgeMaxError;
} }
public int getVertsPerPoly() public int GetVertsPerPoly()
{ {
return vertsPerPoly; return vertsPerPoly;
} }
public float getDetailSampleDist() public float GetDetailSampleDist()
{ {
return detailSampleDist; return detailSampleDist;
} }
public float getDetailSampleMaxError() public float GetDetailSampleMaxError()
{ {
return detailSampleMaxError; return detailSampleMaxError;
} }
public void setVoxels(int[] voxels) public void SetVoxels(int[] voxels)
{ {
this.voxels[0] = voxels[0]; this.voxels[0] = voxels[0];
this.voxels[1] = voxels[1]; this.voxels[1] = voxels[1];
} }
public bool isTiled() public bool IsTiled()
{ {
return tiled; return tiled;
} }
public int getTileSize() public int GetTileSize()
{ {
return tileSize; return tileSize;
} }
public void setTiles(int[] tiles) public void SetTiles(int[] tiles)
{ {
this.tiles[0] = tiles[0]; this.tiles[0] = tiles[0];
this.tiles[1] = tiles[1]; this.tiles[1] = tiles[1];
} }
public void setMaxTiles(int maxTiles) public void SetMaxTiles(int maxTiles)
{ {
this.maxTiles = maxTiles; this.maxTiles = maxTiles;
} }
public void setMaxPolys(int maxPolys) public void SetMaxPolys(int maxPolys)
{ {
this.maxPolys = maxPolys; this.maxPolys = maxPolys;
} }
public bool isMeshInputTrigerred() public bool IsMeshInputTrigerred()
{ {
return meshInputTrigerred; return meshInputTrigerred;
} }
@ -374,7 +374,7 @@ public class RcSettingsView : IRcView
return meshInputFilePath; return meshInputFilePath;
} }
public bool isNavMeshInputTrigerred() public bool IsNavMeshInputTrigerred()
{ {
return navMeshInputTrigerred; return navMeshInputTrigerred;
} }

View File

@ -47,54 +47,54 @@ public class RecastDemoCanvas
view.Bind(this); view.Bind(this);
} }
// setupClipboard(window); // SetupClipboard(window);
// glfwSetCharCallback(window, (w, codepoint) => nk_input_unicode(ctx, codepoint)); // GlfwSetCharCallback(window, (w, codepoint) => Nk_input_unicode(ctx, codepoint));
// glContext = new NuklearGL(this); // glContext = new NuklearGL(this);
} }
private void setupClipboard(long window) private void SetupClipboard(long window)
{ {
// ctx.clip().copy((handle, text, len) => { // ctx.Clip().copy((handle, text, len) => {
// if (len == 0) { // if (len == 0) {
// return; // return;
// } // }
// //
// try (MemoryStack stack = stackPush()) { // try (MemoryStack stack = StackPush()) {
// ByteBuffer str = stack.malloc(len + 1); // ByteBuffer str = stack.Malloc(len + 1);
// memCopy(text, memAddress(str), len); // MemCopy(text, MemAddress(str), len);
// str.put(len, (byte) 0); // str.Put(len, (byte) 0);
// glfwSetClipboardString(window, str); // GlfwSetClipboardString(window, str);
// } // }
// }); // });
// ctx.clip().paste((handle, edit) => { // ctx.Clip().paste((handle, edit) => {
// long text = nglfwGetClipboardString(window); // long text = NglfwGetClipboardString(window);
// if (text != NULL) { // if (text != NULL) {
// nnk_textedit_paste(edit, text, nnk_strlen(text)); // Nnk_textedit_paste(edit, text, Nnk_strlen(text));
// } // }
// }); // });
} }
public void inputBegin() public void InputBegin()
{ {
//nk_input_begin(ctx); //Nk_input_begin(ctx);
} }
public void inputEnd(IWindow win) public void InputEnd(IWindow win)
{ {
// NkMouse mouse = ctx.input().mouse(); // NkMouse mouse = ctx.Input().Mouse();
// if (mouse.grab()) { // if (mouse.Grab()) {
// glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); // GlfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
// } else if (mouse.grabbed()) { // } else if (mouse.Grabbed()) {
// float prevX = mouse.prev().x(); // float prevX = mouse.Prev().x();
// float prevY = mouse.prev().y(); // float prevY = mouse.Prev().y();
// glfwSetCursorPos(win, prevX, prevY); // GlfwSetCursorPos(win, prevX, prevY);
// mouse.pos().x(prevX); // mouse.Pos().x(prevX);
// mouse.pos().y(prevY); // mouse.Pos().y(prevY);
// } else if (mouse.ungrab()) { // } else if (mouse.Ungrab()) {
// glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); // GlfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
// } // }
// nk_input_end(ctx); // Nk_input_end(ctx);
} }
public void Update(double dt) public void Update(double dt)

View File

@ -17,17 +17,17 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
using System;
using System.Numerics; using System.Numerics;
using DotRecast.Core; using DotRecast.Core;
using DotRecast.Recast.Demo.Tools; using DotRecast.Recast.Demo.Tools;
using DotRecast.Recast.Demo.UI;
using ImGuiNET; using ImGuiNET;
namespace DotRecast.Recast.Demo.UI; namespace DotRecast.Recast.Demo.UI;
public class ToolsView : IRcView public class ToolsView : IRcView
{ {
//private readonly NkColor white = NkColor.create(); //private readonly NkColor white = NkColor.Create();
private int _currentToolIdx = 0; private int _currentToolIdx = 0;
private Tool currentTool; private Tool currentTool;
private bool enabled; private bool enabled;
@ -64,7 +64,7 @@ public class ToolsView : IRcView
for (int i = 0; i < tools.Length; ++i) for (int i = 0; i < tools.Length; ++i)
{ {
var tool = tools[i]; var tool = tools[i];
ImGui.RadioButton(tool.getName(), ref _currentToolIdx, i); ImGui.RadioButton(tool.GetName(), ref _currentToolIdx, i);
} }
ImGui.NewLine(); ImGui.NewLine();
@ -76,30 +76,30 @@ public class ToolsView : IRcView
} }
currentTool = tools[_currentToolIdx]; currentTool = tools[_currentToolIdx];
ImGui.Text(currentTool.getName()); ImGui.Text(currentTool.GetName());
ImGui.Separator(); ImGui.Separator();
currentTool.layout(); currentTool.Layout();
ImGui.End(); ImGui.End();
} }
public void setEnabled(bool enabled) public void SetEnabled(bool enabled)
{ {
this.enabled = enabled; this.enabled = enabled;
} }
public Tool getTool() public Tool GetTool()
{ {
return currentTool; return currentTool;
} }
public void setSample(Sample sample) public void SetSample(Sample sample)
{ {
tools.forEach(t => t.setSample(sample)); tools.ForEach(t => t.SetSample(sample));
} }
public void handleUpdate(float dt) public void HandleUpdate(float dt)
{ {
tools.forEach(t => t.handleUpdate(dt)); tools.ForEach(t => t.HandleUpdate(dt));
} }
} }

View File

@ -58,12 +58,12 @@ namespace DotRecast.Recast
Mask = other.Mask; Mask = other.Mask;
} }
public int getMaskedValue() public int GetMaskedValue()
{ {
return Value & Mask; return Value & Mask;
} }
public int apply(int area) public int Apply(int area)
{ {
return ((Value & Mask) | (area & ~Mask)); return ((Value & Mask) | (area & ~Mask));
} }

View File

@ -53,7 +53,7 @@ namespace DotRecast.Recast.Geom
int ntris; int ntris;
int maxTrisPerChunk; int maxTrisPerChunk;
private void calcExtends(BoundsItem[] items, int imin, int imax, ref Vector2f bmin, ref Vector2f bmax) private void CalcExtends(BoundsItem[] items, int imin, int imax, ref Vector2f bmin, ref Vector2f bmax)
{ {
bmin.x = items[imin].bmin.x; bmin.x = items[imin].bmin.x;
bmin.y = items[imin].bmin.y; bmin.y = items[imin].bmin.y;
@ -86,12 +86,12 @@ namespace DotRecast.Recast.Geom
} }
} }
private int longestAxis(float x, float y) private int LongestAxis(float x, float y)
{ {
return y > x ? 1 : 0; return y > x ? 1 : 0;
} }
private void subdivide(BoundsItem[] items, int imin, int imax, int trisPerChunk, List<ChunkyTriMeshNode> nodes, int[] inTris) private void Subdivide(BoundsItem[] items, int imin, int imax, int trisPerChunk, List<ChunkyTriMeshNode> nodes, int[] inTris)
{ {
int inum = imax - imin; int inum = imax - imin;
@ -101,7 +101,7 @@ namespace DotRecast.Recast.Geom
if (inum <= trisPerChunk) if (inum <= trisPerChunk)
{ {
// Leaf // Leaf
calcExtends(items, imin, imax, ref node.bmin, ref node.bmax); CalcExtends(items, imin, imax, ref node.bmin, ref node.bmax);
// Copy triangles. // Copy triangles.
node.i = nodes.Count; node.i = nodes.Count;
@ -119,9 +119,9 @@ namespace DotRecast.Recast.Geom
else else
{ {
// Split // Split
calcExtends(items, imin, imax, ref node.bmin, ref node.bmax); CalcExtends(items, imin, imax, ref node.bmin, ref node.bmax);
int axis = longestAxis(node.bmax.x - node.bmin.x, node.bmax.y - node.bmin.y); int axis = LongestAxis(node.bmax.x - node.bmin.x, node.bmax.y - node.bmin.y);
if (axis == 0) if (axis == 0)
{ {
@ -137,9 +137,9 @@ namespace DotRecast.Recast.Geom
int isplit = imin + inum / 2; int isplit = imin + inum / 2;
// Left // Left
subdivide(items, imin, isplit, trisPerChunk, nodes, inTris); Subdivide(items, imin, isplit, trisPerChunk, nodes, inTris);
// Right // Right
subdivide(items, isplit, imax, trisPerChunk, nodes, inTris); Subdivide(items, isplit, imax, trisPerChunk, nodes, inTris);
// Negative index means escape. // Negative index means escape.
node.i = -nodes.Count; node.i = -nodes.Count;
@ -189,7 +189,7 @@ namespace DotRecast.Recast.Geom
} }
} }
subdivide(items, 0, ntris, trisPerChunk, nodes, tris); Subdivide(items, 0, ntris, trisPerChunk, nodes, tris);
// Calc max tris per node. // Calc max tris per node.
maxTrisPerChunk = 0; maxTrisPerChunk = 0;
@ -208,7 +208,7 @@ namespace DotRecast.Recast.Geom
} }
} }
private bool checkOverlapRect(float[] amin, float[] amax, Vector2f bmin, Vector2f bmax) private bool CheckOverlapRect(float[] amin, float[] amax, Vector2f bmin, Vector2f bmax)
{ {
bool overlap = true; bool overlap = true;
overlap = (amin[0] > bmax.x || amax[0] < bmin.x) ? false : overlap; overlap = (amin[0] > bmax.x || amax[0] < bmin.x) ? false : overlap;
@ -216,7 +216,7 @@ namespace DotRecast.Recast.Geom
return overlap; return overlap;
} }
public List<ChunkyTriMeshNode> getChunksOverlappingRect(float[] bmin, float[] bmax) public List<ChunkyTriMeshNode> GetChunksOverlappingRect(float[] bmin, float[] bmax)
{ {
// Traverse tree // Traverse tree
List<ChunkyTriMeshNode> ids = new List<ChunkyTriMeshNode>(); List<ChunkyTriMeshNode> ids = new List<ChunkyTriMeshNode>();
@ -224,7 +224,7 @@ namespace DotRecast.Recast.Geom
while (i < nodes.Count) while (i < nodes.Count)
{ {
ChunkyTriMeshNode node = nodes[i]; ChunkyTriMeshNode node = nodes[i];
bool overlap = checkOverlapRect(bmin, bmax, node.bmin, node.bmax); bool overlap = CheckOverlapRect(bmin, bmax, node.bmin, node.bmax);
bool isLeafNode = node.i >= 0; bool isLeafNode = node.i >= 0;
if (isLeafNode && overlap) if (isLeafNode && overlap)
@ -245,7 +245,7 @@ namespace DotRecast.Recast.Geom
return ids; return ids;
} }
public List<ChunkyTriMeshNode> getChunksOverlappingSegment(float[] p, float[] q) public List<ChunkyTriMeshNode> GetChunksOverlappingSegment(float[] p, float[] q)
{ {
// Traverse tree // Traverse tree
List<ChunkyTriMeshNode> ids = new List<ChunkyTriMeshNode>(); List<ChunkyTriMeshNode> ids = new List<ChunkyTriMeshNode>();
@ -253,7 +253,7 @@ namespace DotRecast.Recast.Geom
while (i < nodes.Count) while (i < nodes.Count)
{ {
ChunkyTriMeshNode node = nodes[i]; ChunkyTriMeshNode node = nodes[i];
bool overlap = checkOverlapSegment(p, q, node.bmin, node.bmax); bool overlap = CheckOverlapSegment(p, q, node.bmin, node.bmax);
bool isLeafNode = node.i >= 0; bool isLeafNode = node.i >= 0;
if (isLeafNode && overlap) if (isLeafNode && overlap)
@ -274,7 +274,7 @@ namespace DotRecast.Recast.Geom
return ids; return ids;
} }
private bool checkOverlapSegment(float[] p, float[] q, Vector2f bmin, Vector2f bmax) private bool CheckOverlapSegment(float[] p, float[] q, Vector2f bmin, Vector2f bmax)
{ {
float EPSILON = 1e-6f; float EPSILON = 1e-6f;

View File

@ -22,6 +22,6 @@ namespace DotRecast.Recast.Geom
{ {
public interface ConvexVolumeProvider public interface ConvexVolumeProvider
{ {
IList<ConvexVolume> convexVolumes(); IList<ConvexVolume> ConvexVolumes();
} }
} }

View File

@ -25,10 +25,10 @@ namespace DotRecast.Recast.Geom
{ {
public interface InputGeomProvider : ConvexVolumeProvider public interface InputGeomProvider : ConvexVolumeProvider
{ {
Vector3f getMeshBoundsMin(); Vector3f GetMeshBoundsMin();
Vector3f getMeshBoundsMax(); Vector3f GetMeshBoundsMax();
IEnumerable<TriMesh> meshes(); IEnumerable<TriMesh> Meshes();
} }
} }

View File

@ -36,11 +36,11 @@ namespace DotRecast.Recast.Geom
private readonly TriMesh _mesh; private readonly TriMesh _mesh;
public SimpleInputGeomProvider(List<float> vertexPositions, List<int> meshFaces) public SimpleInputGeomProvider(List<float> vertexPositions, List<int> meshFaces)
: this(mapVertices(vertexPositions), mapFaces(meshFaces)) : this(MapVertices(vertexPositions), MapFaces(meshFaces))
{ {
} }
private static int[] mapFaces(List<int> meshFaces) private static int[] MapFaces(List<int> meshFaces)
{ {
int[] faces = new int[meshFaces.Count]; int[] faces = new int[meshFaces.Count];
for (int i = 0; i < faces.Length; i++) for (int i = 0; i < faces.Length; i++)
@ -51,7 +51,7 @@ namespace DotRecast.Recast.Geom
return faces; return faces;
} }
private static float[] mapVertices(List<float> vertexPositions) private static float[] MapVertices(List<float> vertexPositions)
{ {
float[] vertices = new float[vertexPositions.Count]; float[] vertices = new float[vertexPositions.Count];
for (int i = 0; i < vertices.Length; i++) for (int i = 0; i < vertices.Length; i++)
@ -67,36 +67,36 @@ namespace DotRecast.Recast.Geom
this.vertices = vertices; this.vertices = vertices;
this.faces = faces; this.faces = faces;
normals = new float[faces.Length]; normals = new float[faces.Length];
calculateNormals(); CalculateNormals();
bmin = Vector3f.Zero; bmin = Vector3f.Zero;
bmax = Vector3f.Zero; bmax = Vector3f.Zero;
RecastVectors.copy(ref bmin, vertices, 0); RecastVectors.Copy(ref bmin, vertices, 0);
RecastVectors.copy(ref bmax, vertices, 0); RecastVectors.Copy(ref bmax, vertices, 0);
for (int i = 1; i < vertices.Length / 3; i++) for (int i = 1; i < vertices.Length / 3; i++)
{ {
RecastVectors.min(ref bmin, vertices, i * 3); RecastVectors.Min(ref bmin, vertices, i * 3);
RecastVectors.max(ref bmax, vertices, i * 3); RecastVectors.Max(ref bmax, vertices, i * 3);
} }
_mesh = new TriMesh(vertices, faces); _mesh = new TriMesh(vertices, faces);
} }
public Vector3f getMeshBoundsMin() public Vector3f GetMeshBoundsMin()
{ {
return bmin; return bmin;
} }
public Vector3f getMeshBoundsMax() public Vector3f GetMeshBoundsMax()
{ {
return bmax; return bmax;
} }
public IList<ConvexVolume> convexVolumes() public IList<ConvexVolume> ConvexVolumes()
{ {
return volumes; return volumes;
} }
public void addConvexVolume(float[] verts, float minh, float maxh, AreaModification areaMod) public void AddConvexVolume(float[] verts, float minh, float maxh, AreaModification areaMod)
{ {
ConvexVolume vol = new ConvexVolume(); ConvexVolume vol = new ConvexVolume();
vol.hmin = minh; vol.hmin = minh;
@ -106,12 +106,12 @@ namespace DotRecast.Recast.Geom
volumes.Add(vol); volumes.Add(vol);
} }
public IEnumerable<TriMesh> meshes() public IEnumerable<TriMesh> Meshes()
{ {
return ImmutableArray.Create(_mesh); return ImmutableArray.Create(_mesh);
} }
public void calculateNormals() public void CalculateNormals()
{ {
for (int i = 0; i < faces.Length; i += 3) for (int i = 0; i < faces.Length; i += 3)
{ {

View File

@ -33,33 +33,33 @@ namespace DotRecast.Recast.Geom
{ {
bmin = Vector3f.Zero; bmin = Vector3f.Zero;
bmax = Vector3f.Zero; bmax = Vector3f.Zero;
RecastVectors.copy(ref bmin, vertices, 0); RecastVectors.Copy(ref bmin, vertices, 0);
RecastVectors.copy(ref bmax, vertices, 0); RecastVectors.Copy(ref bmax, vertices, 0);
for (int i = 1; i < vertices.Length / 3; i++) for (int i = 1; i < vertices.Length / 3; i++)
{ {
RecastVectors.min(ref bmin, vertices, i * 3); RecastVectors.Min(ref bmin, vertices, i * 3);
RecastVectors.max(ref bmax, vertices, i * 3); RecastVectors.Max(ref bmax, vertices, i * 3);
} }
_mesh = new TriMesh(vertices, faces); _mesh = new TriMesh(vertices, faces);
} }
public Vector3f getMeshBoundsMin() public Vector3f GetMeshBoundsMin()
{ {
return bmin; return bmin;
} }
public Vector3f getMeshBoundsMax() public Vector3f GetMeshBoundsMax()
{ {
return bmax; return bmax;
} }
public IEnumerable<TriMesh> meshes() public IEnumerable<TriMesh> Meshes()
{ {
return ImmutableArray.Create(_mesh); return ImmutableArray.Create(_mesh);
} }
public IList<ConvexVolume> convexVolumes() public IList<ConvexVolume> ConvexVolumes()
{ {
return ImmutableArray<ConvexVolume>.Empty; return ImmutableArray<ConvexVolume>.Empty;
} }

View File

@ -35,19 +35,19 @@ namespace DotRecast.Recast.Geom
chunkyTriMesh = new ChunkyTriMesh(vertices, faces, faces.Length / 3, 32); chunkyTriMesh = new ChunkyTriMesh(vertices, faces, faces.Length / 3, 32);
} }
public int[] getTris() public int[] GetTris()
{ {
return faces; return faces;
} }
public float[] getVerts() public float[] GetVerts()
{ {
return vertices; return vertices;
} }
public List<ChunkyTriMeshNode> getChunksOverlappingRect(float[] bmin, float[] bmax) public List<ChunkyTriMeshNode> GetChunksOverlappingRect(float[] bmin, float[] bmax)
{ {
return chunkyTriMesh.getChunksOverlappingRect(bmin, bmax); return chunkyTriMesh.GetChunksOverlappingRect(bmin, bmax);
} }
} }
} }

View File

@ -31,13 +31,13 @@ namespace DotRecast.Recast
public List<int> meshFaces = new List<int>(); public List<int> meshFaces = new List<int>();
} }
public static InputGeomProvider load(byte[] chunck) public static InputGeomProvider Load(byte[] chunck)
{ {
var context = loadContext(chunck); var context = LoadContext(chunck);
return new SimpleInputGeomProvider(context.vertexPositions, context.meshFaces); return new SimpleInputGeomProvider(context.vertexPositions, context.meshFaces);
} }
public static ObjImporterContext loadContext(byte[] chunck) public static ObjImporterContext LoadContext(byte[] chunck)
{ {
ObjImporterContext context = new ObjImporterContext(); ObjImporterContext context = new ObjImporterContext();
try try
@ -47,7 +47,7 @@ namespace DotRecast.Recast
while ((line = reader.ReadLine()) != null) while ((line = reader.ReadLine()) != null)
{ {
line = line.Trim(); line = line.Trim();
readLine(line, context); ReadLine(line, context);
} }
} }
catch (Exception e) catch (Exception e)
@ -59,23 +59,23 @@ namespace DotRecast.Recast
} }
public static void readLine(string line, ObjImporterContext context) public static void ReadLine(string line, ObjImporterContext context)
{ {
if (line.StartsWith("v")) if (line.StartsWith("v"))
{ {
readVertex(line, context); ReadVertex(line, context);
} }
else if (line.StartsWith("f")) else if (line.StartsWith("f"))
{ {
readFace(line, context); ReadFace(line, context);
} }
} }
private static void readVertex(string line, ObjImporterContext context) private static void ReadVertex(string line, ObjImporterContext context)
{ {
if (line.StartsWith("v ")) if (line.StartsWith("v "))
{ {
float[] vert = readVector3f(line); float[] vert = ReadVector3f(line);
foreach (float vp in vert) foreach (float vp in vert)
{ {
context.vertexPositions.Add(vp); context.vertexPositions.Add(vp);
@ -83,7 +83,7 @@ namespace DotRecast.Recast
} }
} }
private static float[] readVector3f(string line) private static float[] ReadVector3f(string line)
{ {
string[] v = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); string[] v = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (v.Length < 4) if (v.Length < 4)
@ -94,7 +94,7 @@ namespace DotRecast.Recast
return new float[] { float.Parse(v[1]), float.Parse(v[2]), float.Parse(v[3]) }; return new float[] { float.Parse(v[1]), float.Parse(v[2]), float.Parse(v[3]) };
} }
private static void readFace(string line, ObjImporterContext context) private static void ReadFace(string line, ObjImporterContext context)
{ {
string[] v = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); string[] v = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (v.Length < 4) if (v.Length < 4)
@ -104,21 +104,21 @@ namespace DotRecast.Recast
for (int j = 0; j < v.Length - 3; j++) for (int j = 0; j < v.Length - 3; j++)
{ {
context.meshFaces.Add(readFaceVertex(v[1], context)); context.meshFaces.Add(ReadFaceVertex(v[1], context));
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
context.meshFaces.Add(readFaceVertex(v[2 + j + i], context)); context.meshFaces.Add(ReadFaceVertex(v[2 + j + i], context));
} }
} }
} }
private static int readFaceVertex(string face, ObjImporterContext context) private static int ReadFaceVertex(string face, ObjImporterContext context)
{ {
string[] v = face.Split("/"); string[] v = face.Split("/");
return getIndex(int.Parse(v[0]), context.vertexPositions.Count); return GetIndex(int.Parse(v[0]), context.vertexPositions.Count);
} }
private static int getIndex(int posi, int size) private static int GetIndex(int posi, int size)
{ {
if (posi > 0) if (posi > 0)
{ {

View File

@ -24,13 +24,13 @@ namespace DotRecast.Recast
public static class PolyMeshRaycast public static class PolyMeshRaycast
{ {
public static float? raycast(IList<RecastBuilderResult> results, Vector3f src, Vector3f dst) public static float? Raycast(IList<RecastBuilderResult> results, Vector3f src, Vector3f dst)
{ {
foreach (RecastBuilderResult result in results) foreach (RecastBuilderResult result in results)
{ {
if (result.getMeshDetail() != null) if (result.GetMeshDetail() != null)
{ {
float? intersection = raycast(result.getMesh(), result.getMeshDetail(), src, dst); float? intersection = Raycast(result.GetMesh(), result.GetMeshDetail(), src, dst);
if (null != intersection) if (null != intersection)
{ {
return intersection; return intersection;
@ -41,7 +41,7 @@ namespace DotRecast.Recast
return null; return null;
} }
private static float? raycast(PolyMesh poly, PolyMeshDetail meshDetail, Vector3f sp, Vector3f sq) private static float? Raycast(PolyMesh poly, PolyMeshDetail meshDetail, Vector3f sp, Vector3f sq)
{ {
if (meshDetail != null) if (meshDetail != null)
{ {
@ -63,7 +63,7 @@ namespace DotRecast.Recast
vs[k].z = meshDetail.verts[verts + meshDetail.tris[tris + j * 4 + k] * 3 + 2]; vs[k].z = meshDetail.verts[verts + meshDetail.tris[tris + j * 4 + k] * 3 + 2];
} }
float? intersection = Intersections.intersectSegmentTriangle(sp, sq, vs[0], vs[1], vs[2]); float? intersection = Intersections.IntersectSegmentTriangle(sp, sq, vs[0], vs[1], vs[2]);
if (null != intersection) if (null != intersection)
{ {
return intersection; return intersection;

View File

@ -24,7 +24,7 @@ namespace DotRecast.Recast
{ {
public static class PolyUtils public static class PolyUtils
{ {
public static bool pointInPoly(float[] verts, Vector3f p) public static bool PointInPoly(float[] verts, Vector3f p)
{ {
int i, j; int i, j;
bool c = false; bool c = false;
@ -42,7 +42,7 @@ namespace DotRecast.Recast
return c; return c;
} }
public static int offsetPoly(float[] verts, int nverts, float offset, float[] outVerts, int maxOutVerts) public static int OffsetPoly(float[] verts, int nverts, float offset, float[] outVerts, int maxOutVerts)
{ {
float MITER_LIMIT = 1.20f; float MITER_LIMIT = 1.20f;

View File

@ -27,7 +27,7 @@ namespace DotRecast.Recast
public class Recast public class Recast
{ {
void calcBounds(float[] verts, int nv, float[] bmin, float[] bmax) void CalcBounds(float[] verts, int nv, float[] bmin, float[] bmax)
{ {
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
@ -46,25 +46,25 @@ namespace DotRecast.Recast
// Calculate bounding box. // Calculate bounding box.
} }
public static int[] calcGridSize(float[] bmin, float[] bmax, float cs) public static int[] CalcGridSize(float[] bmin, float[] bmax, float cs)
{ {
return new int[] { (int)((bmax[0] - bmin[0]) / cs + 0.5f), (int)((bmax[2] - bmin[2]) / cs + 0.5f) }; return new int[] { (int)((bmax[0] - bmin[0]) / cs + 0.5f), (int)((bmax[2] - bmin[2]) / cs + 0.5f) };
} }
public static int[] calcGridSize(Vector3f bmin, float[] bmax, float cs) public static int[] CalcGridSize(Vector3f bmin, float[] bmax, float cs)
{ {
return new int[] { (int)((bmax[0] - bmin.x) / cs + 0.5f), (int)((bmax[2] - bmin.z) / cs + 0.5f) }; return new int[] { (int)((bmax[0] - bmin.x) / cs + 0.5f), (int)((bmax[2] - bmin.z) / cs + 0.5f) };
} }
public static int[] calcGridSize(Vector3f bmin, Vector3f bmax, float cs) public static int[] CalcGridSize(Vector3f bmin, Vector3f bmax, float cs)
{ {
return new int[] { (int)((bmax.x - bmin.x) / cs + 0.5f), (int)((bmax.z - bmin.z) / cs + 0.5f) }; return new int[] { (int)((bmax.x - bmin.x) / cs + 0.5f), (int)((bmax.z - bmin.z) / cs + 0.5f) };
} }
public static int[] calcTileCount(Vector3f bmin, Vector3f bmax, float cs, int tileSizeX, int tileSizeZ) public static int[] CalcTileCount(Vector3f bmin, Vector3f bmax, float cs, int tileSizeX, int tileSizeZ)
{ {
int[] gwd = calcGridSize(bmin, bmax, cs); int[] gwd = CalcGridSize(bmin, bmax, cs);
int gw = gwd[0]; int gw = gwd[0];
int gd = gwd[1]; int gd = gwd[1];
int tw = (gw + tileSizeX - 1) / tileSizeX; int tw = (gw + tileSizeX - 1) / tileSizeX;
@ -79,7 +79,7 @@ namespace DotRecast.Recast
/// See the #rcConfig documentation for more information on the configuration parameters. /// See the #rcConfig documentation for more information on the configuration parameters.
/// ///
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
public static int[] markWalkableTriangles(Telemetry ctx, float walkableSlopeAngle, float[] verts, int[] tris, int nt, public static int[] MarkWalkableTriangles(Telemetry ctx, float walkableSlopeAngle, float[] verts, int[] tris, int nt,
AreaModification areaMod) AreaModification areaMod)
{ {
int[] areas = new int[nt]; int[] areas = new int[nt];
@ -88,33 +88,33 @@ namespace DotRecast.Recast
for (int i = 0; i < nt; ++i) for (int i = 0; i < nt; ++i)
{ {
int tri = i * 3; int tri = i * 3;
calcTriNormal(verts, tris[tri], tris[tri + 1], tris[tri + 2], ref norm); CalcTriNormal(verts, tris[tri], tris[tri + 1], tris[tri + 2], ref norm);
// Check if the face is walkable. // Check if the face is walkable.
if (norm.y > walkableThr) if (norm.y > walkableThr)
areas[i] = areaMod.apply(areas[i]); areas[i] = areaMod.Apply(areas[i]);
} }
return areas; return areas;
} }
static void calcTriNormal(float[] verts, int v0, int v1, int v2, float[] norm) static void CalcTriNormal(float[] verts, int v0, int v1, int v2, float[] norm)
{ {
Vector3f e0 = new Vector3f(); Vector3f e0 = new Vector3f();
Vector3f e1 = new Vector3f(); Vector3f e1 = new Vector3f();
RecastVectors.sub(ref e0, verts, v1 * 3, v0 * 3); RecastVectors.Sub(ref e0, verts, v1 * 3, v0 * 3);
RecastVectors.sub(ref e1, verts, v2 * 3, v0 * 3); RecastVectors.Sub(ref e1, verts, v2 * 3, v0 * 3);
RecastVectors.cross(norm, e0, e1); RecastVectors.Cross(norm, e0, e1);
RecastVectors.normalize(norm); RecastVectors.Normalize(norm);
} }
static void calcTriNormal(float[] verts, int v0, int v1, int v2, ref Vector3f norm) static void CalcTriNormal(float[] verts, int v0, int v1, int v2, ref Vector3f norm)
{ {
Vector3f e0 = new Vector3f(); Vector3f e0 = new Vector3f();
Vector3f e1 = new Vector3f(); Vector3f e1 = new Vector3f();
RecastVectors.sub(ref e0, verts, v1 * 3, v0 * 3); RecastVectors.Sub(ref e0, verts, v1 * 3, v0 * 3);
RecastVectors.sub(ref e1, verts, v2 * 3, v0 * 3); RecastVectors.Sub(ref e1, verts, v2 * 3, v0 * 3);
RecastVectors.cross(ref norm, e0, e1); RecastVectors.Cross(ref norm, e0, e1);
RecastVectors.normalize(ref norm); RecastVectors.Normalize(ref norm);
} }
@ -126,7 +126,7 @@ namespace DotRecast.Recast
/// See the #rcConfig documentation for more information on the configuration parameters. /// See the #rcConfig documentation for more information on the configuration parameters.
/// ///
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
public static void clearUnwalkableTriangles(Telemetry ctx, float walkableSlopeAngle, float[] verts, int nv, public static void ClearUnwalkableTriangles(Telemetry ctx, float walkableSlopeAngle, float[] verts, int nv,
int[] tris, int nt, int[] areas) int[] tris, int nt, int[] areas)
{ {
float walkableThr = (float)Math.Cos(walkableSlopeAngle / 180.0f * Math.PI); float walkableThr = (float)Math.Cos(walkableSlopeAngle / 180.0f * Math.PI);
@ -136,7 +136,7 @@ namespace DotRecast.Recast
for (int i = 0; i < nt; ++i) for (int i = 0; i < nt; ++i)
{ {
int tri = i * 3; int tri = i * 3;
calcTriNormal(verts, tris[tri], tris[tri + 1], tris[tri + 2], ref norm); CalcTriNormal(verts, tris[tri], tris[tri + 1], tris[tri + 2], ref norm);
// Check if the face is walkable. // Check if the face is walkable.
if (norm.y <= walkableThr) if (norm.y <= walkableThr)
areas[i] = RC_NULL_AREA; areas[i] = RC_NULL_AREA;

View File

@ -35,11 +35,11 @@ namespace DotRecast.Recast
/// This method is usually called immediately after the heightfield has been built. /// This method is usually called immediately after the heightfield has been built.
/// ///
/// @see rcCompactHeightfield, rcBuildCompactHeightfield, rcConfig::walkableRadius /// @see rcCompactHeightfield, rcBuildCompactHeightfield, rcConfig::walkableRadius
public static void erodeWalkableArea(Telemetry ctx, int radius, CompactHeightfield chf) public static void ErodeWalkableArea(Telemetry ctx, int radius, CompactHeightfield chf)
{ {
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
ctx.startTimer("ERODE_AREA"); ctx.StartTimer("ERODE_AREA");
int[] dist = new int[chf.spanCount]; int[] dist = new int[chf.spanCount];
Array.Fill(dist, 255); Array.Fill(dist, 255);
@ -206,7 +206,7 @@ namespace DotRecast.Recast
if (dist[i] < thr) if (dist[i] < thr)
chf.areas[i] = RC_NULL_AREA; chf.areas[i] = RC_NULL_AREA;
ctx.stopTimer("ERODE_AREA"); ctx.StopTimer("ERODE_AREA");
} }
/// @par /// @par
@ -215,12 +215,12 @@ namespace DotRecast.Recast
/// such as #rcMarkBoxArea, #rcMarkConvexPolyArea, and #rcMarkCylinderArea. /// such as #rcMarkBoxArea, #rcMarkConvexPolyArea, and #rcMarkCylinderArea.
/// ///
/// @see rcCompactHeightfield /// @see rcCompactHeightfield
public bool medianFilterWalkableArea(Telemetry ctx, CompactHeightfield chf) public bool MedianFilterWalkableArea(Telemetry ctx, CompactHeightfield chf)
{ {
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
ctx.startTimer("MEDIAN_AREA"); ctx.StartTimer("MEDIAN_AREA");
int[] areas = new int[chf.spanCount]; int[] areas = new int[chf.spanCount];
@ -273,7 +273,7 @@ namespace DotRecast.Recast
chf.areas = areas; chf.areas = areas;
ctx.stopTimer("MEDIAN_AREA"); ctx.StopTimer("MEDIAN_AREA");
return true; return true;
} }
@ -283,9 +283,9 @@ namespace DotRecast.Recast
/// The value of spacial parameters are in world units. /// The value of spacial parameters are in world units.
/// ///
/// @see rcCompactHeightfield, rcMedianFilterWalkableArea /// @see rcCompactHeightfield, rcMedianFilterWalkableArea
public void markBoxArea(Telemetry ctx, float[] bmin, float[] bmax, AreaModification areaMod, CompactHeightfield chf) public void MarkBoxArea(Telemetry ctx, float[] bmin, float[] bmax, AreaModification areaMod, CompactHeightfield chf)
{ {
ctx.startTimer("MARK_BOX_AREA"); ctx.StartTimer("MARK_BOX_AREA");
int minx = (int)((bmin[0] - chf.bmin.x) / chf.cs); int minx = (int)((bmin[0] - chf.bmin.x) / chf.cs);
int miny = (int)((bmin[1] - chf.bmin.y) / chf.ch); int miny = (int)((bmin[1] - chf.bmin.y) / chf.ch);
@ -323,16 +323,16 @@ namespace DotRecast.Recast
if (s.y >= miny && s.y <= maxy) if (s.y >= miny && s.y <= maxy)
{ {
if (chf.areas[i] != RC_NULL_AREA) if (chf.areas[i] != RC_NULL_AREA)
chf.areas[i] = areaMod.apply(chf.areas[i]); chf.areas[i] = areaMod.Apply(chf.areas[i]);
} }
} }
} }
} }
ctx.stopTimer("MARK_BOX_AREA"); ctx.StopTimer("MARK_BOX_AREA");
} }
static bool pointInPoly(float[] verts, Vector3f p) static bool PointInPoly(float[] verts, Vector3f p)
{ {
bool c = false; bool c = false;
int i, j; int i, j;
@ -357,19 +357,19 @@ namespace DotRecast.Recast
/// projected onto the xz-plane at @p hmin, then extruded to @p hmax. /// projected onto the xz-plane at @p hmin, then extruded to @p hmax.
/// ///
/// @see rcCompactHeightfield, rcMedianFilterWalkableArea /// @see rcCompactHeightfield, rcMedianFilterWalkableArea
public static void markConvexPolyArea(Telemetry ctx, float[] verts, float hmin, float hmax, AreaModification areaMod, public static void MarkConvexPolyArea(Telemetry ctx, float[] verts, float hmin, float hmax, AreaModification areaMod,
CompactHeightfield chf) CompactHeightfield chf)
{ {
ctx.startTimer("MARK_CONVEXPOLY_AREA"); ctx.StartTimer("MARK_CONVEXPOLY_AREA");
Vector3f bmin = new Vector3f(); Vector3f bmin = new Vector3f();
Vector3f bmax = new Vector3f(); Vector3f bmax = new Vector3f();
RecastVectors.copy(ref bmin, verts, 0); RecastVectors.Copy(ref bmin, verts, 0);
RecastVectors.copy(ref bmax, verts, 0); RecastVectors.Copy(ref bmax, verts, 0);
for (int i = 3; i < verts.Length; i += 3) for (int i = 3; i < verts.Length; i += 3)
{ {
RecastVectors.min(ref bmin, verts, i); RecastVectors.Min(ref bmin, verts, i);
RecastVectors.max(ref bmax, verts, i); RecastVectors.Max(ref bmax, verts, i);
} }
bmin.y = hmin; bmin.y = hmin;
@ -418,19 +418,19 @@ namespace DotRecast.Recast
p.y = 0; p.y = 0;
p.z = chf.bmin.z + (z + 0.5f) * chf.cs; p.z = chf.bmin.z + (z + 0.5f) * chf.cs;
if (pointInPoly(verts, p)) if (PointInPoly(verts, p))
{ {
chf.areas[i] = areaMod.apply(chf.areas[i]); chf.areas[i] = areaMod.Apply(chf.areas[i]);
} }
} }
} }
} }
} }
ctx.stopTimer("MARK_CONVEXPOLY_AREA"); ctx.StopTimer("MARK_CONVEXPOLY_AREA");
} }
int offsetPoly(float[] verts, int nverts, float offset, float[] outVerts, int maxOutVerts) int OffsetPoly(float[] verts, int nverts, float offset, float[] outVerts, int maxOutVerts)
{ {
float MITER_LIMIT = 1.20f; float MITER_LIMIT = 1.20f;
@ -513,10 +513,10 @@ namespace DotRecast.Recast
/// The value of spacial parameters are in world units. /// The value of spacial parameters are in world units.
/// ///
/// @see rcCompactHeightfield, rcMedianFilterWalkableArea /// @see rcCompactHeightfield, rcMedianFilterWalkableArea
public void markCylinderArea(Telemetry ctx, float[] pos, float r, float h, AreaModification areaMod, public void MarkCylinderArea(Telemetry ctx, float[] pos, float r, float h, AreaModification areaMod,
CompactHeightfield chf) CompactHeightfield chf)
{ {
ctx.startTimer("MARK_CYLINDER_AREA"); ctx.StartTimer("MARK_CYLINDER_AREA");
Vector3f bmin = new Vector3f(); Vector3f bmin = new Vector3f();
Vector3f bmax = new Vector3f(); Vector3f bmax = new Vector3f();
@ -574,14 +574,14 @@ namespace DotRecast.Recast
if (dx * dx + dz * dz < r2) if (dx * dx + dz * dz < r2)
{ {
chf.areas[i] = areaMod.apply(chf.areas[i]); chf.areas[i] = areaMod.Apply(chf.areas[i]);
} }
} }
} }
} }
} }
ctx.stopTimer("MARK_CYLINDER_AREA"); ctx.StopTimer("MARK_CYLINDER_AREA");
} }
} }
} }

View File

@ -31,7 +31,7 @@ namespace DotRecast.Recast
{ {
public interface RecastBuilderProgressListener public interface RecastBuilderProgressListener
{ {
void onProgress(int completed, int total); void OnProgress(int completed, int total);
} }
private readonly RecastBuilderProgressListener progressListener; private readonly RecastBuilderProgressListener progressListener;
@ -46,48 +46,48 @@ namespace DotRecast.Recast
this.progressListener = progressListener; this.progressListener = progressListener;
} }
public List<RecastBuilderResult> buildTiles(InputGeomProvider geom, RecastConfig cfg, TaskFactory taskFactory) public List<RecastBuilderResult> BuildTiles(InputGeomProvider geom, RecastConfig cfg, TaskFactory taskFactory)
{ {
Vector3f bmin = geom.getMeshBoundsMin(); Vector3f bmin = geom.GetMeshBoundsMin();
Vector3f bmax = geom.getMeshBoundsMax(); Vector3f bmax = geom.GetMeshBoundsMax();
int[] twh = Recast.calcTileCount(bmin, bmax, cfg.cs, cfg.tileSizeX, cfg.tileSizeZ); int[] twh = Recast.CalcTileCount(bmin, bmax, cfg.cs, cfg.tileSizeX, cfg.tileSizeZ);
int tw = twh[0]; int tw = twh[0];
int th = twh[1]; int th = twh[1];
List<RecastBuilderResult> results = new List<RecastBuilderResult>(); List<RecastBuilderResult> results = new List<RecastBuilderResult>();
if (null != taskFactory) if (null != taskFactory)
{ {
buildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, default); BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, default);
} }
else else
{ {
buildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results); BuildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results);
} }
return results; return results;
} }
public Task buildTilesAsync(InputGeomProvider geom, RecastConfig cfg, int threads, List<RecastBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken) public Task BuildTilesAsync(InputGeomProvider geom, RecastConfig cfg, int threads, List<RecastBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
{ {
Vector3f bmin = geom.getMeshBoundsMin(); Vector3f bmin = geom.GetMeshBoundsMin();
Vector3f bmax = geom.getMeshBoundsMax(); Vector3f bmax = geom.GetMeshBoundsMax();
int[] twh = Recast.calcTileCount(bmin, bmax, cfg.cs, cfg.tileSizeX, cfg.tileSizeZ); int[] twh = Recast.CalcTileCount(bmin, bmax, cfg.cs, cfg.tileSizeX, cfg.tileSizeZ);
int tw = twh[0]; int tw = twh[0];
int th = twh[1]; int th = twh[1];
Task task; Task task;
if (1 < threads) if (1 < threads)
{ {
task = buildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, cancellationToken); task = BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, cancellationToken);
} }
else else
{ {
task = buildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results); task = BuildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results);
} }
return task; return task;
} }
private Task buildSingleThreadAsync(InputGeomProvider geom, RecastConfig cfg, Vector3f bmin, Vector3f bmax, private Task BuildSingleThreadAsync(InputGeomProvider geom, RecastConfig cfg, Vector3f bmin, Vector3f bmax,
int tw, int th, List<RecastBuilderResult> results) int tw, int th, List<RecastBuilderResult> results)
{ {
AtomicInteger counter = new AtomicInteger(0); AtomicInteger counter = new AtomicInteger(0);
@ -95,14 +95,14 @@ namespace DotRecast.Recast
{ {
for (int x = 0; x < tw; ++x) for (int x = 0; x < tw; ++x)
{ {
results.Add(buildTile(geom, cfg, bmin, bmax, x, y, counter, tw * th)); results.Add(BuildTile(geom, cfg, bmin, bmax, x, y, counter, tw * th));
} }
} }
return Task.CompletedTask; return Task.CompletedTask;
} }
private Task buildMultiThreadAsync(InputGeomProvider geom, RecastConfig cfg, Vector3f bmin, Vector3f bmax, private Task BuildMultiThreadAsync(InputGeomProvider geom, RecastConfig cfg, Vector3f bmin, Vector3f bmax,
int tw, int th, List<RecastBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken) int tw, int th, List<RecastBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
{ {
AtomicInteger counter = new AtomicInteger(0); AtomicInteger counter = new AtomicInteger(0);
@ -122,7 +122,7 @@ namespace DotRecast.Recast
try try
{ {
RecastBuilderResult tile = buildTile(geom, cfg, bmin, bmax, tx, ty, counter, tw * th); RecastBuilderResult tile = BuildTile(geom, cfg, bmin, bmax, tx, ty, counter, tw * th);
lock (results) lock (results)
{ {
results.Add(tile); results.Add(tile);
@ -152,34 +152,34 @@ namespace DotRecast.Recast
return Task.WhenAll(tasks.ToArray()); return Task.WhenAll(tasks.ToArray());
} }
private RecastBuilderResult buildTile(InputGeomProvider geom, RecastConfig cfg, Vector3f bmin, Vector3f bmax, int tx, private RecastBuilderResult BuildTile(InputGeomProvider geom, RecastConfig cfg, Vector3f bmin, Vector3f bmax, int tx,
int ty, AtomicInteger counter, int total) int ty, AtomicInteger counter, int total)
{ {
RecastBuilderResult result = build(geom, new RecastBuilderConfig(cfg, bmin, bmax, tx, ty)); RecastBuilderResult result = Build(geom, new RecastBuilderConfig(cfg, bmin, bmax, tx, ty));
if (progressListener != null) if (progressListener != null)
{ {
progressListener.onProgress(counter.IncrementAndGet(), total); progressListener.OnProgress(counter.IncrementAndGet(), total);
} }
return result; return result;
} }
public RecastBuilderResult build(InputGeomProvider geom, RecastBuilderConfig builderCfg) public RecastBuilderResult Build(InputGeomProvider geom, RecastBuilderConfig builderCfg)
{ {
RecastConfig cfg = builderCfg.cfg; RecastConfig cfg = builderCfg.cfg;
Telemetry ctx = new Telemetry(); Telemetry ctx = new Telemetry();
// //
// Step 1. Rasterize input polygon soup. // Step 1. Rasterize input polygon soup.
// //
Heightfield solid = RecastVoxelization.buildSolidHeightfield(geom, builderCfg, ctx); Heightfield solid = RecastVoxelization.BuildSolidHeightfield(geom, builderCfg, ctx);
return build(builderCfg.tileX, builderCfg.tileZ, geom, cfg, solid, ctx); return Build(builderCfg.tileX, builderCfg.tileZ, geom, cfg, solid, ctx);
} }
public RecastBuilderResult build(int tileX, int tileZ, ConvexVolumeProvider geom, RecastConfig cfg, Heightfield solid, public RecastBuilderResult Build(int tileX, int tileZ, ConvexVolumeProvider geom, RecastConfig cfg, Heightfield solid,
Telemetry ctx) Telemetry ctx)
{ {
filterHeightfield(solid, cfg, ctx); FilterHeightfield(solid, cfg, ctx);
CompactHeightfield chf = buildCompactHeightfield(geom, cfg, ctx, solid); CompactHeightfield chf = BuildCompactHeightfield(geom, cfg, ctx, solid);
// Partition the heightfield so that we can use simple algorithm later // Partition the heightfield so that we can use simple algorithm later
// to triangulate the walkable areas. // to triangulate the walkable areas.
@ -223,20 +223,20 @@ namespace DotRecast.Recast
{ {
// Prepare for region partitioning, by calculating distance field // Prepare for region partitioning, by calculating distance field
// along the walkable surface. // along the walkable surface.
RecastRegion.buildDistanceField(ctx, chf); RecastRegion.BuildDistanceField(ctx, chf);
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
RecastRegion.buildRegions(ctx, chf, cfg.minRegionArea, cfg.mergeRegionArea); RecastRegion.BuildRegions(ctx, chf, cfg.minRegionArea, cfg.mergeRegionArea);
} }
else if (cfg.partitionType == PartitionType.MONOTONE) else if (cfg.partitionType == PartitionType.MONOTONE)
{ {
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
// Monotone partitioning does not need distancefield. // Monotone partitioning does not need distancefield.
RecastRegion.buildRegionsMonotone(ctx, chf, cfg.minRegionArea, cfg.mergeRegionArea); RecastRegion.BuildRegionsMonotone(ctx, chf, cfg.minRegionArea, cfg.mergeRegionArea);
} }
else else
{ {
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
RecastRegion.buildLayerRegions(ctx, chf, cfg.minRegionArea); RecastRegion.BuildLayerRegions(ctx, chf, cfg.minRegionArea);
} }
// //
@ -244,21 +244,21 @@ namespace DotRecast.Recast
// //
// Create contours. // Create contours.
ContourSet cset = RecastContour.buildContours(ctx, chf, cfg.maxSimplificationError, cfg.maxEdgeLen, ContourSet cset = RecastContour.BuildContours(ctx, chf, cfg.maxSimplificationError, cfg.maxEdgeLen,
RecastConstants.RC_CONTOUR_TESS_WALL_EDGES); RecastConstants.RC_CONTOUR_TESS_WALL_EDGES);
// //
// Step 6. Build polygons mesh from contours. // Step 6. Build polygons mesh from contours.
// //
PolyMesh pmesh = RecastMesh.buildPolyMesh(ctx, cset, cfg.maxVertsPerPoly); PolyMesh pmesh = RecastMesh.BuildPolyMesh(ctx, cset, cfg.maxVertsPerPoly);
// //
// Step 7. Create detail mesh which allows to access approximate height // Step 7. Create detail mesh which allows to access approximate height
// on each polygon. // on each polygon.
// //
PolyMeshDetail dmesh = cfg.buildMeshDetail PolyMeshDetail dmesh = cfg.buildMeshDetail
? RecastMeshDetail.buildPolyMeshDetail(ctx, pmesh, chf, cfg.detailSampleDist, cfg.detailSampleMaxError) ? RecastMeshDetail.BuildPolyMeshDetail(ctx, pmesh, chf, cfg.detailSampleDist, cfg.detailSampleMaxError)
: null; : null;
return new RecastBuilderResult(tileX, tileZ, solid, chf, cset, pmesh, dmesh, ctx); return new RecastBuilderResult(tileX, tileZ, solid, chf, cset, pmesh, dmesh, ctx);
} }
@ -266,59 +266,59 @@ namespace DotRecast.Recast
/* /*
* Step 2. Filter walkable surfaces. * Step 2. Filter walkable surfaces.
*/ */
private void filterHeightfield(Heightfield solid, RecastConfig cfg, Telemetry ctx) private void FilterHeightfield(Heightfield solid, RecastConfig cfg, Telemetry ctx)
{ {
// Once all geometry is rasterized, we do initial pass of filtering to // Once all geometry is rasterized, we do initial pass of filtering to
// remove unwanted overhangs caused by the conservative rasterization // remove unwanted overhangs caused by the conservative rasterization
// as well as filter spans where the character cannot possibly stand. // as well as filter spans where the character cannot possibly stand.
if (cfg.filterLowHangingObstacles) if (cfg.filterLowHangingObstacles)
{ {
RecastFilter.filterLowHangingWalkableObstacles(ctx, cfg.walkableClimb, solid); RecastFilter.FilterLowHangingWalkableObstacles(ctx, cfg.walkableClimb, solid);
} }
if (cfg.filterLedgeSpans) if (cfg.filterLedgeSpans)
{ {
RecastFilter.filterLedgeSpans(ctx, cfg.walkableHeight, cfg.walkableClimb, solid); RecastFilter.FilterLedgeSpans(ctx, cfg.walkableHeight, cfg.walkableClimb, solid);
} }
if (cfg.filterWalkableLowHeightSpans) if (cfg.filterWalkableLowHeightSpans)
{ {
RecastFilter.filterWalkableLowHeightSpans(ctx, cfg.walkableHeight, solid); RecastFilter.FilterWalkableLowHeightSpans(ctx, cfg.walkableHeight, solid);
} }
} }
/* /*
* Step 3. Partition walkable surface to simple regions. * Step 3. Partition walkable surface to simple regions.
*/ */
private CompactHeightfield buildCompactHeightfield(ConvexVolumeProvider volumeProvider, RecastConfig cfg, Telemetry ctx, private CompactHeightfield BuildCompactHeightfield(ConvexVolumeProvider volumeProvider, RecastConfig cfg, Telemetry ctx,
Heightfield solid) Heightfield solid)
{ {
// Compact the heightfield so that it is faster to handle from now on. // Compact the heightfield so that it is faster to handle from now on.
// This will result more cache coherent data as well as the neighbours // This will result more cache coherent data as well as the neighbours
// between walkable cells will be calculated. // between walkable cells will be calculated.
CompactHeightfield chf = RecastCompact.buildCompactHeightfield(ctx, cfg.walkableHeight, cfg.walkableClimb, solid); CompactHeightfield chf = RecastCompact.BuildCompactHeightfield(ctx, cfg.walkableHeight, cfg.walkableClimb, solid);
// Erode the walkable area by agent radius. // Erode the walkable area by agent radius.
RecastArea.erodeWalkableArea(ctx, cfg.walkableRadius, chf); RecastArea.ErodeWalkableArea(ctx, cfg.walkableRadius, chf);
// (Optional) Mark areas. // (Optional) Mark areas.
if (volumeProvider != null) if (volumeProvider != null)
{ {
foreach (ConvexVolume vol in volumeProvider.convexVolumes()) foreach (ConvexVolume vol in volumeProvider.ConvexVolumes())
{ {
RecastArea.markConvexPolyArea(ctx, vol.verts, vol.hmin, vol.hmax, vol.areaMod, chf); RecastArea.MarkConvexPolyArea(ctx, vol.verts, vol.hmin, vol.hmax, vol.areaMod, chf);
} }
} }
return chf; return chf;
} }
public HeightfieldLayerSet buildLayers(InputGeomProvider geom, RecastBuilderConfig builderCfg) public HeightfieldLayerSet BuildLayers(InputGeomProvider geom, RecastBuilderConfig builderCfg)
{ {
Telemetry ctx = new Telemetry(); Telemetry ctx = new Telemetry();
Heightfield solid = RecastVoxelization.buildSolidHeightfield(geom, builderCfg, ctx); Heightfield solid = RecastVoxelization.BuildSolidHeightfield(geom, builderCfg, ctx);
filterHeightfield(solid, builderCfg.cfg, ctx); FilterHeightfield(solid, builderCfg.cfg, ctx);
CompactHeightfield chf = buildCompactHeightfield(geom, builderCfg.cfg, ctx, solid); CompactHeightfield chf = BuildCompactHeightfield(geom, builderCfg.cfg, ctx, solid);
return RecastLayers.buildHeightfieldLayers(ctx, chf, builderCfg.cfg.walkableHeight); return RecastLayers.BuildHeightfieldLayers(ctx, chf, builderCfg.cfg.walkableHeight);
} }
} }
} }

View File

@ -94,7 +94,7 @@ namespace DotRecast.Recast
} }
else else
{ {
int[] wh = Recast.calcGridSize(this.bmin, this.bmax, cfg.cs); int[] wh = Recast.CalcGridSize(this.bmin, this.bmax, cfg.cs);
width = wh[0]; width = wh[0];
height = wh[1]; height = wh[1];
} }

View File

@ -23,32 +23,32 @@
telemetry = ctx; telemetry = ctx;
} }
public PolyMesh getMesh() public PolyMesh GetMesh()
{ {
return pmesh; return pmesh;
} }
public PolyMeshDetail getMeshDetail() public PolyMeshDetail GetMeshDetail()
{ {
return dmesh; return dmesh;
} }
public CompactHeightfield getCompactHeightfield() public CompactHeightfield GetCompactHeightfield()
{ {
return chf; return chf;
} }
public ContourSet getContourSet() public ContourSet GetContourSet()
{ {
return cs; return cs;
} }
public Heightfield getSolidHeightfield() public Heightfield GetSolidHeightfield()
{ {
return solid; return solid;
} }
public Telemetry getTelemetry() public Telemetry GetTelemetry()
{ {
return telemetry; return telemetry;
} }

View File

@ -59,7 +59,7 @@ namespace DotRecast.Recast
/// @param[in] x The x offset. [Limits: -1 <= value <= 1] /// @param[in] x The x offset. [Limits: -1 <= value <= 1]
/// @param[in] y The y offset. [Limits: -1 <= value <= 1] /// @param[in] y The y offset. [Limits: -1 <= value <= 1]
/// @return The direction that represents the offset. /// @return The direction that represents the offset.
public static int rcGetDirForOffset(int x, int y) public static int RcGetDirForOffset(int x, int y)
{ {
int[] dirs = { 3, 0, -1, 2, 1 }; int[] dirs = { 3, 0, -1, 2, 1 };
return dirs[((y + 1) << 1) + x]; return dirs[((y + 1) << 1) + x];

View File

@ -38,15 +38,15 @@ namespace DotRecast.Recast
/// See the #rcConfig documentation for more information on the configuration parameters. /// See the #rcConfig documentation for more information on the configuration parameters.
/// ///
/// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig /// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig
public static CompactHeightfield buildCompactHeightfield(Telemetry ctx, int walkableHeight, int walkableClimb, public static CompactHeightfield BuildCompactHeightfield(Telemetry ctx, int walkableHeight, int walkableClimb,
Heightfield hf) Heightfield hf)
{ {
ctx.startTimer("BUILD_COMPACTHEIGHTFIELD"); ctx.StartTimer("BUILD_COMPACTHEIGHTFIELD");
CompactHeightfield chf = new CompactHeightfield(); CompactHeightfield chf = new CompactHeightfield();
int w = hf.width; int w = hf.width;
int h = hf.height; int h = hf.height;
int spanCount = getHeightFieldSpanCount(hf); int spanCount = GetHeightFieldSpanCount(hf);
// Fill in header. // Fill in header.
chf.width = w; chf.width = w;
@ -93,8 +93,8 @@ namespace DotRecast.Recast
{ {
int bot = s.smax; int bot = s.smax;
int top = s.next != null ? (int)s.next.smin : MAX_HEIGHT; int top = s.next != null ? (int)s.next.smin : MAX_HEIGHT;
chf.spans[idx].y = clamp(bot, 0, MAX_HEIGHT); chf.spans[idx].y = Clamp(bot, 0, MAX_HEIGHT);
chf.spans[idx].h = clamp(top - bot, 0, MAX_HEIGHT); chf.spans[idx].h = Clamp(top - bot, 0, MAX_HEIGHT);
chf.areas[idx] = s.area; chf.areas[idx] = s.area;
idx++; idx++;
c.count++; c.count++;
@ -161,11 +161,11 @@ namespace DotRecast.Recast
+ " (max: " + MAX_LAYERS + ")"); + " (max: " + MAX_LAYERS + ")");
} }
ctx.stopTimer("BUILD_COMPACTHEIGHTFIELD"); ctx.StopTimer("BUILD_COMPACTHEIGHTFIELD");
return chf; return chf;
} }
private static int getHeightFieldSpanCount(Heightfield hf) private static int GetHeightFieldSpanCount(Heightfield hf)
{ {
int w = hf.width; int w = hf.width;
int h = hf.height; int h = hf.height;

View File

@ -179,7 +179,7 @@ namespace DotRecast.Recast
this.buildMeshDetail = buildMeshDetail; this.buildMeshDetail = buildMeshDetail;
} }
public static int calcBorder(float agentRadius, float cs) public static int CalcBorder(float agentRadius, float cs)
{ {
return 3 + (int)Math.Ceiling(agentRadius / cs); return 3 + (int)Math.Ceiling(agentRadius / cs);
} }

View File

@ -60,7 +60,7 @@ namespace DotRecast.Recast
} }
} }
private static CornerHeight getCornerHeight(int x, int y, int i, int dir, CompactHeightfield chf) private static CornerHeight GetCornerHeight(int x, int y, int i, int dir, CompactHeightfield chf)
{ {
bool isBorderVertex = false; bool isBorderVertex = false;
CompactSpan s = chf.spans[i]; CompactSpan s = chf.spans[i];
@ -138,7 +138,7 @@ namespace DotRecast.Recast
return new CornerHeight(ch, isBorderVertex); return new CornerHeight(ch, isBorderVertex);
} }
private static void walkContour(int x, int y, int i, CompactHeightfield chf, int[] flags, List<int> points) private static void WalkContour(int x, int y, int i, CompactHeightfield chf, int[] flags, List<int> points)
{ {
// Choose the first non-connected edge // Choose the first non-connected edge
int dir = 0; int dir = 0;
@ -157,7 +157,7 @@ namespace DotRecast.Recast
{ {
// Choose the edge corner // Choose the edge corner
bool isAreaBorder = false; bool isAreaBorder = false;
CornerHeight cornerHeight = getCornerHeight(x, y, i, dir, chf); CornerHeight cornerHeight = GetCornerHeight(x, y, i, dir, chf);
bool isBorderVertex = cornerHeight.borderVertex; bool isBorderVertex = cornerHeight.borderVertex;
int px = x; int px = x;
int py = cornerHeight.height; int py = cornerHeight.height;
@ -231,7 +231,7 @@ namespace DotRecast.Recast
} }
} }
private static float distancePtSeg(int x, int z, int px, int pz, int qx, int qz) private static float DistancePtSeg(int x, int z, int px, int pz, int qx, int qz)
{ {
float pqx = qx - px; float pqx = qx - px;
float pqz = qz - pz; float pqz = qz - pz;
@ -252,7 +252,7 @@ namespace DotRecast.Recast
return dx * dx + dz * dz; return dx * dx + dz * dz;
} }
private static void simplifyContour(List<int> points, List<int> simplified, float maxError, int maxEdgeLen, int buildFlags) private static void SimplifyContour(List<int> points, List<int> simplified, float maxError, int maxEdgeLen, int buildFlags)
{ {
// Add initial points. // Add initial points.
bool hasConnections = false; bool hasConnections = false;
@ -377,7 +377,7 @@ namespace DotRecast.Recast
{ {
while (ci != endi) while (ci != endi)
{ {
float d = distancePtSeg(points[ci * 4 + 0], points[ci * 4 + 2], ax, az, bx, bz); float d = DistancePtSeg(points[ci * 4 + 0], points[ci * 4 + 2], ax, az, bx, bz);
if (d > maxd) if (d > maxd)
{ {
maxd = d; maxd = d;
@ -480,7 +480,7 @@ namespace DotRecast.Recast
} }
} }
private static int calcAreaOfPolygon2D(int[] verts, int nverts) private static int CalcAreaOfPolygon2D(int[] verts, int nverts)
{ {
int area = 0; int area = 0;
for (int i = 0, j = nverts - 1; i < nverts; j = i++) for (int i = 0, j = nverts - 1; i < nverts; j = i++)
@ -493,7 +493,7 @@ namespace DotRecast.Recast
return (area + 1) / 2; return (area + 1) / 2;
} }
private static bool intersectSegContour(int d0, int d1, int i, int n, int[] verts, int[] d0verts, int[] d1verts) private static bool IntersectSegContour(int d0, int d1, int i, int n, int[] verts, int[] d0verts, int[] d1verts)
{ {
// For each edge (k,k+1) of P // For each edge (k,k+1) of P
int[] pverts = new int[4 * 4]; int[] pverts = new int[4 * 4];
@ -507,7 +507,7 @@ namespace DotRecast.Recast
d1 = 4; d1 = 4;
for (int k = 0; k < n; k++) for (int k = 0; k < n; k++)
{ {
int k1 = RecastMesh.next(k, n); int k1 = RecastMesh.Next(k, n);
// Skip edges incident to i. // Skip edges incident to i.
if (i == k || i == k1) if (i == k || i == k1)
continue; continue;
@ -521,22 +521,22 @@ namespace DotRecast.Recast
p0 = 8; p0 = 8;
p1 = 12; p1 = 12;
if (RecastMesh.vequal(pverts, d0, p0) || RecastMesh.vequal(pverts, d1, p0) if (RecastMesh.Vequal(pverts, d0, p0) || RecastMesh.Vequal(pverts, d1, p0)
|| RecastMesh.vequal(pverts, d0, p1) || RecastMesh.vequal(pverts, d1, p1)) || RecastMesh.Vequal(pverts, d0, p1) || RecastMesh.Vequal(pverts, d1, p1))
continue; continue;
if (RecastMesh.intersect(pverts, d0, d1, p0, p1)) if (RecastMesh.Intersect(pverts, d0, d1, p0, p1))
return true; return true;
} }
return false; return false;
} }
private static bool inCone(int i, int n, int[] verts, int pj, int[] vertpj) private static bool InCone(int i, int n, int[] verts, int pj, int[] vertpj)
{ {
int pi = i * 4; int pi = i * 4;
int pi1 = RecastMesh.next(i, n) * 4; int pi1 = RecastMesh.Next(i, n) * 4;
int pin1 = RecastMesh.prev(i, n) * 4; int pin1 = RecastMesh.Prev(i, n) * 4;
int[] pverts = new int[4 * 4]; int[] pverts = new int[4 * 4];
for (int g = 0; g < 4; g++) for (int g = 0; g < 4; g++)
{ {
@ -551,23 +551,23 @@ namespace DotRecast.Recast
pin1 = 8; pin1 = 8;
pj = 12; pj = 12;
// If P[i] is a convex vertex [ i+1 left or on (i-1,i) ]. // If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
if (RecastMesh.leftOn(pverts, pin1, pi, pi1)) if (RecastMesh.LeftOn(pverts, pin1, pi, pi1))
return RecastMesh.left(pverts, pi, pj, pin1) && RecastMesh.left(pverts, pj, pi, pi1); return RecastMesh.Left(pverts, pi, pj, pin1) && RecastMesh.Left(pverts, pj, pi, pi1);
// Assume (i-1,i,i+1) not collinear. // Assume (i-1,i,i+1) not collinear.
// else P[i] is reflex. // else P[i] is reflex.
return !(RecastMesh.leftOn(pverts, pi, pj, pi1) && RecastMesh.leftOn(pverts, pj, pi, pin1)); return !(RecastMesh.LeftOn(pverts, pi, pj, pi1) && RecastMesh.LeftOn(pverts, pj, pi, pin1));
} }
private static void removeDegenerateSegments(List<int> simplified) private static void RemoveDegenerateSegments(List<int> simplified)
{ {
// Remove adjacent vertices which are equal on xz-plane, // Remove adjacent vertices which are equal on xz-plane,
// or else the triangulator will get confused. // or else the triangulator will get confused.
int npts = simplified.Count / 4; int npts = simplified.Count / 4;
for (int i = 0; i < npts; ++i) for (int i = 0; i < npts; ++i)
{ {
int ni = RecastMesh.next(i, npts); int ni = RecastMesh.Next(i, npts);
// if (vequal(&simplified[i*4], &simplified[ni*4])) // if (Vequal(&simplified[i*4], &simplified[ni*4]))
if (simplified[i * 4] == simplified[ni * 4] if (simplified[i * 4] == simplified[ni * 4]
&& simplified[i * 4 + 2] == simplified[ni * 4 + 2]) && simplified[i * 4 + 2] == simplified[ni * 4 + 2])
{ {
@ -581,7 +581,7 @@ namespace DotRecast.Recast
} }
} }
private static void mergeContours(Contour ca, Contour cb, int ia, int ib) private static void MergeContours(Contour ca, Contour cb, int ia, int ib)
{ {
int maxVerts = ca.nverts + cb.nverts + 2; int maxVerts = ca.nverts + cb.nverts + 2;
int[] verts = new int[maxVerts * 4]; int[] verts = new int[maxVerts * 4];
@ -620,7 +620,7 @@ namespace DotRecast.Recast
} }
// Finds the lowest leftmost vertex of a contour. // Finds the lowest leftmost vertex of a contour.
private static int[] findLeftMostVertex(Contour contour) private static int[] FindLeftMostVertex(Contour contour)
{ {
int minx = contour.verts[0]; int minx = contour.verts[0];
int minz = contour.verts[2]; int minz = contour.verts[2];
@ -665,12 +665,12 @@ namespace DotRecast.Recast
} }
} }
private static void mergeRegionHoles(Telemetry ctx, ContourRegion region) private static void MergeRegionHoles(Telemetry ctx, ContourRegion region)
{ {
// Sort holes from left to right. // Sort holes from left to right.
for (int i = 0; i < region.nholes; i++) for (int i = 0; i < region.nholes; i++)
{ {
int[] minleft = findLeftMostVertex(region.holes[i].contour); int[] minleft = FindLeftMostVertex(region.holes[i].contour);
region.holes[i].minx = minleft[0]; region.holes[i].minx = minleft[0];
region.holes[i].minz = minleft[1]; region.holes[i].minz = minleft[1];
region.holes[i].leftmost = minleft[2]; region.holes[i].leftmost = minleft[2];
@ -711,7 +711,7 @@ namespace DotRecast.Recast
int corner = bestVertex * 4; int corner = bestVertex * 4;
for (int j = 0; j < outline.nverts; j++) for (int j = 0; j < outline.nverts; j++)
{ {
if (inCone(j, outline.nverts, outline.verts, corner, hole.verts)) if (InCone(j, outline.nverts, outline.verts, corner, hole.verts))
{ {
int dx = outline.verts[j * 4 + 0] - hole.verts[corner + 0]; int dx = outline.verts[j * 4 + 0] - hole.verts[corner + 0];
int dz = outline.verts[j * 4 + 2] - hole.verts[corner + 2]; int dz = outline.verts[j * 4 + 2] - hole.verts[corner + 2];
@ -729,10 +729,10 @@ namespace DotRecast.Recast
for (int j = 0; j < ndiags; j++) for (int j = 0; j < ndiags; j++)
{ {
int pt = diags[j].vert * 4; int pt = diags[j].vert * 4;
bool intersect = intersectSegContour(pt, corner, diags[j].vert, outline.nverts, outline.verts, bool intersect = IntersectSegContour(pt, corner, diags[j].vert, outline.nverts, outline.verts,
outline.verts, hole.verts); outline.verts, hole.verts);
for (int k = i; k < region.nholes && !intersect; k++) for (int k = i; k < region.nholes && !intersect; k++)
intersect |= intersectSegContour(pt, corner, -1, region.holes[k].contour.nverts, intersect |= IntersectSegContour(pt, corner, -1, region.holes[k].contour.nverts,
region.holes[k].contour.verts, outline.verts, hole.verts); region.holes[k].contour.verts, outline.verts, hole.verts);
if (!intersect) if (!intersect)
{ {
@ -750,11 +750,11 @@ namespace DotRecast.Recast
if (index == -1) if (index == -1)
{ {
ctx.warn("mergeHoles: Failed to find merge points for"); ctx.Warn("mergeHoles: Failed to find merge points for");
continue; continue;
} }
mergeContours(region.outline, hole, index, bestVertex); MergeContours(region.outline, hole, index, bestVertex);
} }
} }
@ -771,7 +771,7 @@ namespace DotRecast.Recast
/// See the #rcConfig documentation for more information on the configuration parameters. /// See the #rcConfig documentation for more information on the configuration parameters.
/// ///
/// @see rcAllocContourSet, rcCompactHeightfield, rcContourSet, rcConfig /// @see rcAllocContourSet, rcCompactHeightfield, rcContourSet, rcConfig
public static ContourSet buildContours(Telemetry ctx, CompactHeightfield chf, float maxError, int maxEdgeLen, public static ContourSet BuildContours(Telemetry ctx, CompactHeightfield chf, float maxError, int maxEdgeLen,
int buildFlags) int buildFlags)
{ {
int w = chf.width; int w = chf.width;
@ -779,7 +779,7 @@ namespace DotRecast.Recast
int borderSize = chf.borderSize; int borderSize = chf.borderSize;
ContourSet cset = new ContourSet(); ContourSet cset = new ContourSet();
ctx.startTimer("CONTOURS"); ctx.StartTimer("CONTOURS");
cset.bmin = chf.bmin; cset.bmin = chf.bmin;
cset.bmax = chf.bmax; cset.bmax = chf.bmax;
if (borderSize > 0) if (borderSize > 0)
@ -801,7 +801,7 @@ namespace DotRecast.Recast
int[] flags = new int[chf.spanCount]; int[] flags = new int[chf.spanCount];
ctx.startTimer("CONTOURS_TRACE"); ctx.StartTimer("CONTOURS_TRACE");
// Mark boundaries. // Mark boundaries.
for (int y = 0; y < h; ++y) for (int y = 0; y < h; ++y)
@ -839,7 +839,7 @@ namespace DotRecast.Recast
} }
} }
ctx.stopTimer("CONTOURS_TRACE"); ctx.StopTimer("CONTOURS_TRACE");
List<int> verts = new List<int>(256); List<int> verts = new List<int>(256);
List<int> simplified = new List<int>(64); List<int> simplified = new List<int>(64);
@ -865,14 +865,14 @@ namespace DotRecast.Recast
verts.Clear(); verts.Clear();
simplified.Clear(); simplified.Clear();
ctx.startTimer("CONTOURS_WALK"); ctx.StartTimer("CONTOURS_WALK");
walkContour(x, y, i, chf, flags, verts); WalkContour(x, y, i, chf, flags, verts);
ctx.stopTimer("CONTOURS_WALK"); ctx.StopTimer("CONTOURS_WALK");
ctx.startTimer("CONTOURS_SIMPLIFY"); ctx.StartTimer("CONTOURS_SIMPLIFY");
simplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags); SimplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags);
removeDegenerateSegments(simplified); RemoveDegenerateSegments(simplified);
ctx.stopTimer("CONTOURS_SIMPLIFY"); ctx.StopTimer("CONTOURS_SIMPLIFY");
// Store region->contour remap info. // Store region->contour remap info.
// Create contour. // Create contour.
@ -932,7 +932,7 @@ namespace DotRecast.Recast
{ {
Contour cont = cset.conts[i]; Contour cont = cset.conts[i];
// If the contour is wound backwards, it is a hole. // If the contour is wound backwards, it is a hole.
winding[i] = calcAreaOfPolygon2D(cont.verts, cont.nverts) < 0 ? -1 : 1; winding[i] = CalcAreaOfPolygon2D(cont.verts, cont.nverts) < 0 ? -1 : 1;
if (winding[i] < 0) if (winding[i] < 0)
nholes++; nholes++;
} }
@ -999,7 +999,7 @@ namespace DotRecast.Recast
if (reg.outline != null) if (reg.outline != null)
{ {
mergeRegionHoles(ctx, reg); MergeRegionHoles(ctx, reg);
} }
else else
{ {
@ -1013,7 +1013,7 @@ namespace DotRecast.Recast
} }
} }
ctx.stopTimer("CONTOURS"); ctx.StopTimer("CONTOURS");
return cset; return cset;
} }
} }

View File

@ -24,28 +24,28 @@ using static DotRecast.Recast.RecastVectors;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
public class RecastFilledVolumeRasterization public static class RecastFilledVolumeRasterization
{ {
private const float EPSILON = 0.00001f; private const float EPSILON = 0.00001f;
private static readonly int[] BOX_EDGES = new[] { 0, 1, 0, 2, 0, 4, 1, 3, 1, 5, 2, 3, 2, 6, 3, 7, 4, 5, 4, 6, 5, 7, 6, 7 }; private static readonly int[] BOX_EDGES = new[] { 0, 1, 0, 2, 0, 4, 1, 3, 1, 5, 2, 3, 2, 6, 3, 7, 4, 5, 4, 6, 5, 7, 6, 7 };
public static void rasterizeSphere(Heightfield hf, Vector3f center, float radius, int area, int flagMergeThr, Telemetry ctx) public static void RasterizeSphere(Heightfield hf, Vector3f center, float radius, int area, int flagMergeThr, Telemetry ctx)
{ {
ctx.startTimer("RASTERIZE_SPHERE"); ctx.StartTimer("RASTERIZE_SPHERE");
float[] bounds = float[] bounds =
{ {
center.x - radius, center.y - radius, center.z - radius, center.x + radius, center.y + radius, center.x - radius, center.y - radius, center.z - radius, center.x + radius, center.y + radius,
center.z + radius center.z + radius
}; };
rasterizationFilledShape(hf, bounds, area, flagMergeThr, RasterizationFilledShape(hf, bounds, area, flagMergeThr,
rectangle => intersectSphere(rectangle, center, radius * radius)); rectangle => IntersectSphere(rectangle, center, radius * radius));
ctx.stopTimer("RASTERIZE_SPHERE"); ctx.StopTimer("RASTERIZE_SPHERE");
} }
public static void rasterizeCapsule(Heightfield hf, Vector3f start, Vector3f end, float radius, int area, int flagMergeThr, public static void RasterizeCapsule(Heightfield hf, Vector3f start, Vector3f end, float radius, int area, int flagMergeThr,
Telemetry ctx) Telemetry ctx)
{ {
ctx.startTimer("RASTERIZE_CAPSULE"); ctx.StartTimer("RASTERIZE_CAPSULE");
float[] bounds = float[] bounds =
{ {
Math.Min(start.x, end.x) - radius, Math.Min(start.y, end.y) - radius, Math.Min(start.x, end.x) - radius, Math.Min(start.y, end.y) - radius,
@ -53,15 +53,15 @@ namespace DotRecast.Recast
Math.Max(start.z, end.z) + radius Math.Max(start.z, end.z) + radius
}; };
Vector3f axis = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); Vector3f axis = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
rasterizationFilledShape(hf, bounds, area, flagMergeThr, RasterizationFilledShape(hf, bounds, area, flagMergeThr,
rectangle => intersectCapsule(rectangle, start, end, axis, radius * radius)); rectangle => IntersectCapsule(rectangle, start, end, axis, radius * radius));
ctx.stopTimer("RASTERIZE_CAPSULE"); ctx.StopTimer("RASTERIZE_CAPSULE");
} }
public static void rasterizeCylinder(Heightfield hf, Vector3f start, Vector3f end, float radius, int area, int flagMergeThr, public static void RasterizeCylinder(Heightfield hf, Vector3f start, Vector3f end, float radius, int area, int flagMergeThr,
Telemetry ctx) Telemetry ctx)
{ {
ctx.startTimer("RASTERIZE_CYLINDER"); ctx.StartTimer("RASTERIZE_CYLINDER");
float[] bounds = float[] bounds =
{ {
Math.Min(start.x, end.x) - radius, Math.Min(start.y, end.y) - radius, Math.Min(start.x, end.x) - radius, Math.Min(start.y, end.y) - radius,
@ -69,24 +69,24 @@ namespace DotRecast.Recast
Math.Max(start.z, end.z) + radius Math.Max(start.z, end.z) + radius
}; };
Vector3f axis = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); Vector3f axis = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
rasterizationFilledShape(hf, bounds, area, flagMergeThr, RasterizationFilledShape(hf, bounds, area, flagMergeThr,
rectangle => intersectCylinder(rectangle, start, end, axis, radius * radius)); rectangle => IntersectCylinder(rectangle, start, end, axis, radius * radius));
ctx.stopTimer("RASTERIZE_CYLINDER"); ctx.StopTimer("RASTERIZE_CYLINDER");
} }
public static void rasterizeBox(Heightfield hf, Vector3f center, Vector3f[] halfEdges, int area, int flagMergeThr, public static void RasterizeBox(Heightfield hf, Vector3f center, Vector3f[] halfEdges, int area, int flagMergeThr,
Telemetry ctx) Telemetry ctx)
{ {
ctx.startTimer("RASTERIZE_BOX"); ctx.StartTimer("RASTERIZE_BOX");
Vector3f[] normals = Vector3f[] normals =
{ {
Vector3f.Of(halfEdges[0].x, halfEdges[0].y, halfEdges[0].z), Vector3f.Of(halfEdges[0].x, halfEdges[0].y, halfEdges[0].z),
Vector3f.Of(halfEdges[1].x, halfEdges[1].y, halfEdges[1].z), Vector3f.Of(halfEdges[1].x, halfEdges[1].y, halfEdges[1].z),
Vector3f.Of(halfEdges[2].x, halfEdges[2].y, halfEdges[2].z), Vector3f.Of(halfEdges[2].x, halfEdges[2].y, halfEdges[2].z),
}; };
normalize(ref normals[0]); Normalize(ref normals[0]);
normalize(ref normals[1]); Normalize(ref normals[1]);
normalize(ref normals[2]); Normalize(ref normals[2]);
float[] vertices = new float[8 * 3]; float[] vertices = new float[8 * 3];
float[] bounds = new float[] float[] bounds = new float[]
@ -122,14 +122,14 @@ namespace DotRecast.Recast
+ vertices[vi * 3 + 2] * planes[i][2]; + vertices[vi * 3 + 2] * planes[i][2];
} }
rasterizationFilledShape(hf, bounds, area, flagMergeThr, rectangle => intersectBox(rectangle, vertices, planes)); RasterizationFilledShape(hf, bounds, area, flagMergeThr, rectangle => IntersectBox(rectangle, vertices, planes));
ctx.stopTimer("RASTERIZE_BOX"); ctx.StopTimer("RASTERIZE_BOX");
} }
public static void rasterizeConvex(Heightfield hf, float[] vertices, int[] triangles, int area, int flagMergeThr, public static void RasterizeConvex(Heightfield hf, float[] vertices, int[] triangles, int area, int flagMergeThr,
Telemetry ctx) Telemetry ctx)
{ {
ctx.startTimer("RASTERIZE_CONVEX"); ctx.StartTimer("RASTERIZE_CONVEX");
float[] bounds = new float[] { vertices[0], vertices[1], vertices[2], vertices[0], vertices[1], vertices[2] }; float[] bounds = new float[] { vertices[0], vertices[1], vertices[2], vertices[0], vertices[1], vertices[2] };
for (int i = 0; i < vertices.Length; i += 3) for (int i = 0; i < vertices.Length; i += 3)
{ {
@ -153,9 +153,9 @@ namespace DotRecast.Recast
float[] ac = { vertices[c] - vertices[a], vertices[c + 1] - vertices[a + 1], vertices[c + 2] - vertices[a + 2] }; float[] ac = { vertices[c] - vertices[a], vertices[c + 1] - vertices[a + 1], vertices[c + 2] - vertices[a + 2] };
float[] bc = { vertices[c] - vertices[b], vertices[c + 1] - vertices[b + 1], vertices[c + 2] - vertices[b + 2] }; float[] bc = { vertices[c] - vertices[b], vertices[c + 1] - vertices[b + 1], vertices[c + 2] - vertices[b + 2] };
float[] ca = { vertices[a] - vertices[c], vertices[a + 1] - vertices[c + 1], vertices[a + 2] - vertices[c + 2] }; float[] ca = { vertices[a] - vertices[c], vertices[a + 1] - vertices[c + 1], vertices[a + 2] - vertices[c + 2] };
plane(planes, i, ab, ac, vertices, a); Plane(planes, i, ab, ac, vertices, a);
plane(planes, i + 1, planes[i], bc, vertices, b); Plane(planes, i + 1, planes[i], bc, vertices, b);
plane(planes, i + 2, planes[i], ca, vertices, c); Plane(planes, i + 2, planes[i], ca, vertices, c);
float s = 1.0f / (vertices[a] * planes[i + 1][0] + vertices[a + 1] * planes[i + 1][1] float s = 1.0f / (vertices[a] * planes[i + 1][0] + vertices[a + 1] * planes[i + 1][1]
+ vertices[a + 2] * planes[i + 1][2] - planes[i + 1][3]); + vertices[a + 2] * planes[i + 1][2] - planes[i + 1][3]);
@ -177,21 +177,21 @@ namespace DotRecast.Recast
triBounds[j][3] = Math.Max(Math.Max(vertices[a + 2], vertices[b + 2]), vertices[c + 2]); triBounds[j][3] = Math.Max(Math.Max(vertices[a + 2], vertices[b + 2]), vertices[c + 2]);
} }
rasterizationFilledShape(hf, bounds, area, flagMergeThr, RasterizationFilledShape(hf, bounds, area, flagMergeThr,
rectangle => intersectConvex(rectangle, triangles, vertices, planes, triBounds)); rectangle => IntersectConvex(rectangle, triangles, vertices, planes, triBounds));
ctx.stopTimer("RASTERIZE_CONVEX"); ctx.StopTimer("RASTERIZE_CONVEX");
} }
private static void plane(float[][] planes, int p, float[] v1, float[] v2, float[] vertices, int vert) private static void Plane(float[][] planes, int p, float[] v1, float[] v2, float[] vertices, int vert)
{ {
RecastVectors.cross(planes[p], v1, v2); RecastVectors.Cross(planes[p], v1, v2);
planes[p][3] = planes[p][0] * vertices[vert] + planes[p][1] * vertices[vert + 1] + planes[p][2] * vertices[vert + 2]; planes[p][3] = planes[p][0] * vertices[vert] + planes[p][1] * vertices[vert + 1] + planes[p][2] * vertices[vert + 2];
} }
private static void rasterizationFilledShape(Heightfield hf, float[] bounds, int area, int flagMergeThr, private static void RasterizationFilledShape(Heightfield hf, float[] bounds, int area, int flagMergeThr,
Func<float[], float[]> intersection) Func<float[], float[]> intersection)
{ {
if (!overlapBounds(hf.bmin, hf.bmax, bounds)) if (!OverlapBounds(hf.bmin, hf.bmax, bounds))
{ {
return; return;
} }
@ -229,16 +229,16 @@ namespace DotRecast.Recast
int smax = (int)Math.Ceiling((h[1] - hf.bmin.y) * ich); int smax = (int)Math.Ceiling((h[1] - hf.bmin.y) * ich);
if (smin != smax) if (smin != smax)
{ {
int ismin = clamp(smin, 0, SPAN_MAX_HEIGHT); int ismin = Clamp(smin, 0, SPAN_MAX_HEIGHT);
int ismax = clamp(smax, ismin + 1, SPAN_MAX_HEIGHT); int ismax = Clamp(smax, ismin + 1, SPAN_MAX_HEIGHT);
RecastRasterization.addSpan(hf, x, z, ismin, ismax, area, flagMergeThr); RecastRasterization.AddSpan(hf, x, z, ismin, ismax, area, flagMergeThr);
} }
} }
} }
} }
} }
private static float[] intersectSphere(float[] rectangle, Vector3f center, float radiusSqr) private static float[] IntersectSphere(float[] rectangle, Vector3f center, float radiusSqr)
{ {
float x = Math.Max(rectangle[0], Math.Min(center.x, rectangle[2])); float x = Math.Max(rectangle[0], Math.Min(center.x, rectangle[2]));
float y = rectangle[4]; float y = rectangle[4];
@ -248,8 +248,8 @@ namespace DotRecast.Recast
float my = y - center.y; float my = y - center.y;
float mz = z - center.z; float mz = z - center.z;
float b = my; // dot(m, d) d = (0, 1, 0) float b = my; // Dot(m, d) d = (0, 1, 0)
float c = lenSqr(mx, my, mz) - radiusSqr; float c = LenSqr(mx, my, mz) - radiusSqr;
if (c > 0.0f && b > 0.0f) if (c > 0.0f && b > 0.0f)
{ {
return null; return null;
@ -273,47 +273,47 @@ namespace DotRecast.Recast
return new float[] { y + tmin, y + tmax }; return new float[] { y + tmin, y + tmax };
} }
private static float[] intersectCapsule(float[] rectangle, Vector3f start, Vector3f end, Vector3f axis, float radiusSqr) private static float[] IntersectCapsule(float[] rectangle, Vector3f start, Vector3f end, Vector3f axis, float radiusSqr)
{ {
float[] s = mergeIntersections(intersectSphere(rectangle, start, radiusSqr), intersectSphere(rectangle, end, radiusSqr)); float[] s = MergeIntersections(IntersectSphere(rectangle, start, radiusSqr), IntersectSphere(rectangle, end, radiusSqr));
float axisLen2dSqr = axis.x * axis.x + axis.z * axis.z; float axisLen2dSqr = axis.x * axis.x + axis.z * axis.z;
if (axisLen2dSqr > EPSILON) if (axisLen2dSqr > EPSILON)
{ {
s = slabsCylinderIntersection(rectangle, start, end, axis, radiusSqr, s); s = SlabsCylinderIntersection(rectangle, start, end, axis, radiusSqr, s);
} }
return s; return s;
} }
private static float[] intersectCylinder(float[] rectangle, Vector3f start, Vector3f end, Vector3f axis, float radiusSqr) private static float[] IntersectCylinder(float[] rectangle, Vector3f start, Vector3f end, Vector3f axis, float radiusSqr)
{ {
float[] s = mergeIntersections( float[] s = MergeIntersections(
rayCylinderIntersection(Vector3f.Of( RayCylinderIntersection(Vector3f.Of(
clamp(start.x, rectangle[0], rectangle[2]), rectangle[4], Clamp(start.x, rectangle[0], rectangle[2]), rectangle[4],
clamp(start.z, rectangle[1], rectangle[3]) Clamp(start.z, rectangle[1], rectangle[3])
), start, axis, radiusSqr), ), start, axis, radiusSqr),
rayCylinderIntersection(Vector3f.Of( RayCylinderIntersection(Vector3f.Of(
clamp(end.x, rectangle[0], rectangle[2]), rectangle[4], Clamp(end.x, rectangle[0], rectangle[2]), rectangle[4],
clamp(end.z, rectangle[1], rectangle[3]) Clamp(end.z, rectangle[1], rectangle[3])
), start, axis, radiusSqr)); ), start, axis, radiusSqr));
float axisLen2dSqr = axis.x * axis.x + axis.z * axis.z; float axisLen2dSqr = axis.x * axis.x + axis.z * axis.z;
if (axisLen2dSqr > EPSILON) if (axisLen2dSqr > EPSILON)
{ {
s = slabsCylinderIntersection(rectangle, start, end, axis, radiusSqr, s); s = SlabsCylinderIntersection(rectangle, start, end, axis, radiusSqr, s);
} }
if (axis.y * axis.y > EPSILON) if (axis.y * axis.y > EPSILON)
{ {
float[][] rectangleOnStartPlane = ArrayUtils.Of<float>(4, 3); float[][] rectangleOnStartPlane = ArrayUtils.Of<float>(4, 3);
float[][] rectangleOnEndPlane = ArrayUtils.Of<float>(4, 3); float[][] rectangleOnEndPlane = ArrayUtils.Of<float>(4, 3);
float ds = dot(axis, start); float ds = Dot(axis, start);
float de = dot(axis, end); float de = Dot(axis, end);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
float x = rectangle[(i + 1) & 2]; float x = rectangle[(i + 1) & 2];
float z = rectangle[(i & 2) + 1]; float z = rectangle[(i & 2) + 1];
Vector3f a = Vector3f.Of(x, rectangle[4], z); Vector3f a = Vector3f.Of(x, rectangle[4], z);
float dotAxisA = dot(axis, a); float dotAxisA = Dot(axis, a);
float t = (ds - dotAxisA) / axis.y; float t = (ds - dotAxisA) / axis.y;
rectangleOnStartPlane[i][0] = x; rectangleOnStartPlane[i][0] = x;
rectangleOnStartPlane[i][1] = rectangle[4] + t; rectangleOnStartPlane[i][1] = rectangle[4] + t;
@ -326,15 +326,15 @@ namespace DotRecast.Recast
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
s = cylinderCapIntersection(start, radiusSqr, s, i, rectangleOnStartPlane); s = CylinderCapIntersection(start, radiusSqr, s, i, rectangleOnStartPlane);
s = cylinderCapIntersection(end, radiusSqr, s, i, rectangleOnEndPlane); s = CylinderCapIntersection(end, radiusSqr, s, i, rectangleOnEndPlane);
} }
} }
return s; return s;
} }
private static float[] cylinderCapIntersection(Vector3f start, float radiusSqr, float[] s, int i, float[][] rectangleOnPlane) private static float[] CylinderCapIntersection(Vector3f start, float radiusSqr, float[] s, int i, float[][] rectangleOnPlane)
{ {
int j = (i + 1) % 4; int j = (i + 1) % 4;
// Ray against sphere intersection // Ray against sphere intersection
@ -348,9 +348,9 @@ namespace DotRecast.Recast
rectangleOnPlane[j][1] - rectangleOnPlane[i][1], rectangleOnPlane[j][1] - rectangleOnPlane[i][1],
rectangleOnPlane[j][2] - rectangleOnPlane[i][2] rectangleOnPlane[j][2] - rectangleOnPlane[i][2]
); );
float dl = dot(d, d); float dl = Dot(d, d);
float b = dot(m, d) / dl; float b = Dot(m, d) / dl;
float c = (dot(m, m) - radiusSqr) / dl; float c = (Dot(m, m) - radiusSqr) / dl;
float discr = b * b - c; float discr = b * b - c;
if (discr > EPSILON) if (discr > EPSILON)
{ {
@ -364,83 +364,83 @@ namespace DotRecast.Recast
float y1 = rectangleOnPlane[i][1] + t1 * d.y; float y1 = rectangleOnPlane[i][1] + t1 * d.y;
float y2 = rectangleOnPlane[i][1] + t2 * d.y; float y2 = rectangleOnPlane[i][1] + t2 * d.y;
float[] y = { Math.Min(y1, y2), Math.Max(y1, y2) }; float[] y = { Math.Min(y1, y2), Math.Max(y1, y2) };
s = mergeIntersections(s, y); s = MergeIntersections(s, y);
} }
} }
return s; return s;
} }
private static float[] slabsCylinderIntersection(float[] rectangle, Vector3f start, Vector3f end, Vector3f axis, float radiusSqr, private static float[] SlabsCylinderIntersection(float[] rectangle, Vector3f start, Vector3f end, Vector3f axis, float radiusSqr,
float[] s) float[] s)
{ {
if (Math.Min(start.x, end.x) < rectangle[0]) if (Math.Min(start.x, end.x) < rectangle[0])
{ {
s = mergeIntersections(s, xSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[0])); s = MergeIntersections(s, XSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[0]));
} }
if (Math.Max(start.x, end.x) > rectangle[2]) if (Math.Max(start.x, end.x) > rectangle[2])
{ {
s = mergeIntersections(s, xSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[2])); s = MergeIntersections(s, XSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[2]));
} }
if (Math.Min(start.z, end.z) < rectangle[1]) if (Math.Min(start.z, end.z) < rectangle[1])
{ {
s = mergeIntersections(s, zSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[1])); s = MergeIntersections(s, ZSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[1]));
} }
if (Math.Max(start.z, end.z) > rectangle[3]) if (Math.Max(start.z, end.z) > rectangle[3])
{ {
s = mergeIntersections(s, zSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[3])); s = MergeIntersections(s, ZSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[3]));
} }
return s; return s;
} }
private static float[] xSlabCylinderIntersection(float[] rectangle, Vector3f start, Vector3f axis, float radiusSqr, float x) private static float[] XSlabCylinderIntersection(float[] rectangle, Vector3f start, Vector3f axis, float radiusSqr, float x)
{ {
return rayCylinderIntersection(xSlabRayIntersection(rectangle, start, axis, x), start, axis, radiusSqr); return RayCylinderIntersection(XSlabRayIntersection(rectangle, start, axis, x), start, axis, radiusSqr);
} }
private static Vector3f xSlabRayIntersection(float[] rectangle, Vector3f start, Vector3f direction, float x) private static Vector3f XSlabRayIntersection(float[] rectangle, Vector3f start, Vector3f direction, float x)
{ {
// 2d intersection of plane and segment // 2d intersection of plane and segment
float t = (x - start.x) / direction.x; float t = (x - start.x) / direction.x;
float z = clamp(start.z + t * direction.z, rectangle[1], rectangle[3]); float z = Clamp(start.z + t * direction.z, rectangle[1], rectangle[3]);
return Vector3f.Of(x, rectangle[4], z); return Vector3f.Of(x, rectangle[4], z);
} }
private static float[] zSlabCylinderIntersection(float[] rectangle, Vector3f start, Vector3f axis, float radiusSqr, float z) private static float[] ZSlabCylinderIntersection(float[] rectangle, Vector3f start, Vector3f axis, float radiusSqr, float z)
{ {
return rayCylinderIntersection(zSlabRayIntersection(rectangle, start, axis, z), start, axis, radiusSqr); return RayCylinderIntersection(ZSlabRayIntersection(rectangle, start, axis, z), start, axis, radiusSqr);
} }
private static Vector3f zSlabRayIntersection(float[] rectangle, Vector3f start, Vector3f direction, float z) private static Vector3f ZSlabRayIntersection(float[] rectangle, Vector3f start, Vector3f direction, float z)
{ {
// 2d intersection of plane and segment // 2d intersection of plane and segment
float t = (z - start.z) / direction.z; float t = (z - start.z) / direction.z;
float x = clamp(start.x + t * direction.x, rectangle[0], rectangle[2]); float x = Clamp(start.x + t * direction.x, rectangle[0], rectangle[2]);
return Vector3f.Of(x, rectangle[4], z); return Vector3f.Of(x, rectangle[4], z);
} }
// Based on Christer Ericsons's "Real-Time Collision Detection" // Based on Christer Ericsons's "Real-Time Collision Detection"
private static float[] rayCylinderIntersection(Vector3f point, Vector3f start, Vector3f axis, float radiusSqr) private static float[] RayCylinderIntersection(Vector3f point, Vector3f start, Vector3f axis, float radiusSqr)
{ {
Vector3f d = axis; Vector3f d = axis;
Vector3f m = Vector3f.Of(point.x - start.x, point.y - start.y, point.z - start.z); Vector3f m = Vector3f.Of(point.x - start.x, point.y - start.y, point.z - start.z);
// float[] n = { 0, 1, 0 }; // float[] n = { 0, 1, 0 };
float md = dot(m, d); float md = Dot(m, d);
// float nd = dot(n, d); // float nd = Dot(n, d);
float nd = axis.y; float nd = axis.y;
float dd = dot(d, d); float dd = Dot(d, d);
// float nn = dot(n, n); // float nn = Dot(n, n);
float nn = 1; float nn = 1;
// float mn = dot(m, n); // float mn = Dot(m, n);
float mn = m.y; float mn = m.y;
// float a = dd * nn - nd * nd; // float a = dd * nn - nd * nd;
float a = dd - nd * nd; float a = dd - nd * nd;
float k = dot(m, m) - radiusSqr; float k = Dot(m, m) - radiusSqr;
float c = dd * k - md * md; float c = dd * k - md * md;
if (Math.Abs(a) < EPSILON) if (Math.Abs(a) < EPSILON)
{ {
@ -508,7 +508,7 @@ namespace DotRecast.Recast
return new float[] { point.y + Math.Min(t1, t2), point.y + Math.Max(t1, t2) }; return new float[] { point.y + Math.Min(t1, t2), point.y + Math.Max(t1, t2) };
} }
private static float[] intersectBox(float[] rectangle, float[] vertices, float[][] planes) private static float[] IntersectBox(float[] rectangle, float[] vertices, float[][] planes)
{ {
float yMin = float.PositiveInfinity; float yMin = float.PositiveInfinity;
float yMax = float.NegativeInfinity; float yMax = float.NegativeInfinity;
@ -534,7 +534,7 @@ namespace DotRecast.Recast
{ {
if (Math.Abs(planes[j][1]) > EPSILON) if (Math.Abs(planes[j][1]) > EPSILON)
{ {
float dotNormalPoint = dot(planes[j], point); float dotNormalPoint = Dot(planes[j], point);
float t = (planes[j][3] - dotNormalPoint) / planes[j][1]; float t = (planes[j][3] - dotNormalPoint) / planes[j][1];
float y = point.y + t; float y = point.y + t;
bool valid = true; bool valid = true;
@ -573,14 +573,14 @@ namespace DotRecast.Recast
float dz = vertices[vj + 2] - z; float dz = vertices[vj + 2] - z;
if (Math.Abs(dx) > EPSILON) if (Math.Abs(dx) > EPSILON)
{ {
float? iy = xSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[0]); float? iy = XSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[0]);
if (iy != null) if (iy != null)
{ {
yMin = Math.Min(yMin, iy.Value); yMin = Math.Min(yMin, iy.Value);
yMax = Math.Max(yMax, iy.Value); yMax = Math.Max(yMax, iy.Value);
} }
iy = xSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[2]); iy = XSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[2]);
if (iy != null) if (iy != null)
{ {
yMin = Math.Min(yMin, iy.Value); yMin = Math.Min(yMin, iy.Value);
@ -590,14 +590,14 @@ namespace DotRecast.Recast
if (Math.Abs(dz) > EPSILON) if (Math.Abs(dz) > EPSILON)
{ {
float? iy = zSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[1]); float? iy = ZSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[1]);
if (iy != null) if (iy != null)
{ {
yMin = Math.Min(yMin, iy.Value); yMin = Math.Min(yMin, iy.Value);
yMax = Math.Max(yMax, iy.Value); yMax = Math.Max(yMax, iy.Value);
} }
iy = zSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[3]); iy = ZSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[3]);
if (iy != null) if (iy != null)
{ {
yMin = Math.Min(yMin, iy.Value); yMin = Math.Min(yMin, iy.Value);
@ -614,7 +614,7 @@ namespace DotRecast.Recast
return null; return null;
} }
private static float[] intersectConvex(float[] rectangle, int[] triangles, float[] verts, float[][] planes, private static float[] IntersectConvex(float[] rectangle, int[] triangles, float[] verts, float[][] planes,
float[][] triBounds) float[][] triBounds)
{ {
float imin = float.PositiveInfinity; float imin = float.PositiveInfinity;
@ -652,14 +652,14 @@ namespace DotRecast.Recast
float dz = verts[vj + 2] - z; float dz = verts[vj + 2] - z;
if (Math.Abs(dx) > EPSILON) if (Math.Abs(dx) > EPSILON)
{ {
float? iy = xSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[0]); float? iy = XSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[0]);
if (iy != null) if (iy != null)
{ {
imin = Math.Min(imin, iy.Value); imin = Math.Min(imin, iy.Value);
imax = Math.Max(imax, iy.Value); imax = Math.Max(imax, iy.Value);
} }
iy = xSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[2]); iy = XSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[2]);
if (iy != null) if (iy != null)
{ {
imin = Math.Min(imin, iy.Value); imin = Math.Min(imin, iy.Value);
@ -669,14 +669,14 @@ namespace DotRecast.Recast
if (Math.Abs(dz) > EPSILON) if (Math.Abs(dz) > EPSILON)
{ {
float? iy = zSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[1]); float? iy = ZSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[1]);
if (iy != null) if (iy != null)
{ {
imin = Math.Min(imin, iy.Value); imin = Math.Min(imin, iy.Value);
imax = Math.Max(imax, iy.Value); imax = Math.Max(imax, iy.Value);
} }
iy = zSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[3]); iy = ZSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[3]);
if (iy != null) if (iy != null)
{ {
imin = Math.Min(imin, iy.Value); imin = Math.Min(imin, iy.Value);
@ -691,7 +691,7 @@ namespace DotRecast.Recast
{ {
point.x = ((i & 1) == 0) ? rectangle[0] : rectangle[2]; point.x = ((i & 1) == 0) ? rectangle[0] : rectangle[2];
point.z = ((i & 2) == 0) ? rectangle[1] : rectangle[3]; point.z = ((i & 2) == 0) ? rectangle[1] : rectangle[3];
float? y = rayTriangleIntersection(point, tri, planes); float? y = RayTriangleIntersection(point, tri, planes);
if (y != null) if (y != null)
{ {
imin = Math.Min(imin, y.Value); imin = Math.Min(imin, y.Value);
@ -708,7 +708,7 @@ namespace DotRecast.Recast
return null; return null;
} }
private static float? xSlabSegmentIntersection(float[] rectangle, float x, float y, float z, float dx, float dy, float dz, private static float? XSlabSegmentIntersection(float[] rectangle, float x, float y, float z, float dx, float dy, float dz,
float slabX) float slabX)
{ {
float x2 = x + dx; float x2 = x + dx;
@ -725,7 +725,7 @@ namespace DotRecast.Recast
return null; return null;
} }
private static float? zSlabSegmentIntersection(float[] rectangle, float x, float y, float z, float dx, float dy, float dz, private static float? ZSlabSegmentIntersection(float[] rectangle, float x, float y, float z, float dx, float dy, float dz,
float slabZ) float slabZ)
{ {
float z2 = z + dz; float z2 = z + dz;
@ -742,17 +742,17 @@ namespace DotRecast.Recast
return null; return null;
} }
private static float? rayTriangleIntersection(Vector3f point, int plane, float[][] planes) private static float? RayTriangleIntersection(Vector3f point, int plane, float[][] planes)
{ {
float t = (planes[plane][3] - dot(planes[plane], point)) / planes[plane][1]; float t = (planes[plane][3] - Dot(planes[plane], point)) / planes[plane][1];
float[] s = { point.x, point.y + t, point.z }; float[] s = { point.x, point.y + t, point.z };
float u = dot(s, planes[plane + 1]) - planes[plane + 1][3]; float u = Dot(s, planes[plane + 1]) - planes[plane + 1][3];
if (u < 0.0f || u > 1.0f) if (u < 0.0f || u > 1.0f)
{ {
return null; return null;
} }
float v = dot(s, planes[plane + 2]) - planes[plane + 2][3]; float v = Dot(s, planes[plane + 2]) - planes[plane + 2][3];
if (v < 0.0f) if (v < 0.0f)
{ {
return null; return null;
@ -767,7 +767,7 @@ namespace DotRecast.Recast
return s[1]; return s[1];
} }
private static float[] mergeIntersections(float[] s1, float[] s2) private static float[] MergeIntersections(float[] s1, float[] s2)
{ {
if (s1 == null) if (s1 == null)
{ {
@ -782,12 +782,12 @@ namespace DotRecast.Recast
return new float[] { Math.Min(s1[0], s2[0]), Math.Max(s1[1], s2[1]) }; return new float[] { Math.Min(s1[0], s2[0]), Math.Max(s1[1], s2[1]) };
} }
private static float lenSqr(float dx, float dy, float dz) private static float LenSqr(float dx, float dy, float dz)
{ {
return dx * dx + dy * dy + dz * dz; return dx * dx + dy * dy + dz * dz;
} }
private static bool overlapBounds(Vector3f amin, Vector3f amax, float[] bounds) private static bool OverlapBounds(Vector3f amin, Vector3f amax, float[] bounds)
{ {
bool overlap = true; bool overlap = true;
overlap = (amin.x > bounds[3] || amax.x < bounds[0]) ? false : overlap; overlap = (amin.x > bounds[3] || amax.x < bounds[0]) ? false : overlap;

View File

@ -31,15 +31,15 @@ namespace DotRecast.Recast
/// Allows the formation of walkable regions that will flow over low lying /// Allows the formation of walkable regions that will flow over low lying
/// objects such as curbs, and up structures such as stairways. /// objects such as curbs, and up structures such as stairways.
/// ///
/// Two neighboring spans are walkable if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) < waklableClimb</tt> /// Two neighboring spans are walkable if: <tt>RcAbs(currentSpan.smax - neighborSpan.smax) < waklableClimb</tt>
/// ///
/// @warning Will override the effect of #rcFilterLedgeSpans. So if both filters are used, call /// @warning Will override the effect of #rcFilterLedgeSpans. So if both filters are used, call
/// #rcFilterLedgeSpans after calling this filter. /// #rcFilterLedgeSpans after calling this filter.
/// ///
/// @see rcHeightfield, rcConfig /// @see rcHeightfield, rcConfig
public static void filterLowHangingWalkableObstacles(Telemetry ctx, int walkableClimb, Heightfield solid) public static void FilterLowHangingWalkableObstacles(Telemetry ctx, int walkableClimb, Heightfield solid)
{ {
ctx.startTimer("FILTER_LOW_OBSTACLES"); ctx.StartTimer("FILTER_LOW_OBSTACLES");
int w = solid.width; int w = solid.width;
int h = solid.height; int h = solid.height;
@ -71,7 +71,7 @@ namespace DotRecast.Recast
} }
} }
ctx.stopTimer("FILTER_LOW_OBSTACLES"); ctx.StopTimer("FILTER_LOW_OBSTACLES");
} }
/// @par /// @par
@ -81,12 +81,12 @@ namespace DotRecast.Recast
/// This method removes the impact of the overestimation of conservative voxelization /// This method removes the impact of the overestimation of conservative voxelization
/// so the resulting mesh will not have regions hanging in the air over ledges. /// so the resulting mesh will not have regions hanging in the air over ledges.
/// ///
/// A span is a ledge if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt> /// A span is a ledge if: <tt>RcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt>
/// ///
/// @see rcHeightfield, rcConfig /// @see rcHeightfield, rcConfig
public static void filterLedgeSpans(Telemetry ctx, int walkableHeight, int walkableClimb, Heightfield solid) public static void FilterLedgeSpans(Telemetry ctx, int walkableHeight, int walkableClimb, Heightfield solid)
{ {
ctx.startTimer("FILTER_LEDGE"); ctx.StartTimer("FILTER_LEDGE");
int w = solid.width; int w = solid.width;
int h = solid.height; int h = solid.height;
@ -168,7 +168,7 @@ namespace DotRecast.Recast
} }
} }
ctx.stopTimer("FILTER_LEDGE"); ctx.StopTimer("FILTER_LEDGE");
} }
/// @par /// @par
@ -177,9 +177,9 @@ namespace DotRecast.Recast
/// maximum to the next higher span's minimum. (Same grid column.) /// maximum to the next higher span's minimum. (Same grid column.)
/// ///
/// @see rcHeightfield, rcConfig /// @see rcHeightfield, rcConfig
public static void filterWalkableLowHeightSpans(Telemetry ctx, int walkableHeight, Heightfield solid) public static void FilterWalkableLowHeightSpans(Telemetry ctx, int walkableHeight, Heightfield solid)
{ {
ctx.startTimer("FILTER_WALKABLE"); ctx.StartTimer("FILTER_WALKABLE");
int w = solid.width; int w = solid.width;
int h = solid.height; int h = solid.height;
@ -200,7 +200,7 @@ namespace DotRecast.Recast
} }
} }
ctx.stopTimer("FILTER_WALKABLE"); ctx.StopTimer("FILTER_WALKABLE");
} }
} }
} }

View File

@ -53,7 +53,7 @@ namespace DotRecast.Recast
} }
}; };
private static void addUnique(List<int> a, int v) private static void AddUnique(List<int> a, int v)
{ {
if (!a.Contains(v)) if (!a.Contains(v))
{ {
@ -61,19 +61,19 @@ namespace DotRecast.Recast
} }
} }
private static bool contains(List<int> a, int v) private static bool Contains(List<int> a, int v)
{ {
return a.Contains(v); return a.Contains(v);
} }
private static bool overlapRange(int amin, int amax, int bmin, int bmax) private static bool OverlapRange(int amin, int amax, int bmin, int bmax)
{ {
return (amin > bmax || amax < bmin) ? false : true; return (amin > bmax || amax < bmin) ? false : true;
} }
public static HeightfieldLayerSet buildHeightfieldLayers(Telemetry ctx, CompactHeightfield chf, int walkableHeight) public static HeightfieldLayerSet BuildHeightfieldLayers(Telemetry ctx, CompactHeightfield chf, int walkableHeight)
{ {
ctx.startTimer("RC_TIMER_BUILD_LAYERS"); ctx.StartTimer("RC_TIMER_BUILD_LAYERS");
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
int borderSize = chf.borderSize; int borderSize = chf.borderSize;
@ -234,7 +234,7 @@ namespace DotRecast.Recast
int ai = chf.cells[ax + ay * w].index + GetCon(s, dir); int ai = chf.cells[ax + ay * w].index + GetCon(s, dir);
int rai = srcReg[ai]; int rai = srcReg[ai];
if (rai != 0xff && rai != ri) if (rai != 0xff && rai != ri)
addUnique(regs[ri].neis, rai); AddUnique(regs[ri].neis, rai);
} }
} }
} }
@ -248,8 +248,8 @@ namespace DotRecast.Recast
{ {
LayerRegion ri = regs[lregs[i]]; LayerRegion ri = regs[lregs[i]];
LayerRegion rj = regs[lregs[j]]; LayerRegion rj = regs[lregs[j]];
addUnique(ri.layers, lregs[j]); AddUnique(ri.layers, lregs[j]);
addUnique(rj.layers, lregs[i]); AddUnique(rj.layers, lregs[i]);
} }
} }
} }
@ -288,7 +288,7 @@ namespace DotRecast.Recast
if (regn.layerId != 0xff) if (regn.layerId != 0xff)
continue; continue;
// Skip if the neighbour is overlapping root region. // Skip if the neighbour is overlapping root region.
if (contains(root.layers, nei)) if (Contains(root.layers, nei))
continue; continue;
// Skip if the height range would become too large. // Skip if the height range would become too large.
int ymin = Math.Min(root.ymin, regn.ymin); int ymin = Math.Min(root.ymin, regn.ymin);
@ -303,7 +303,7 @@ namespace DotRecast.Recast
regn.layerId = layerId; regn.layerId = layerId;
// Merge current layers to root. // Merge current layers to root.
foreach (int layer in regn.layers) foreach (int layer in regn.layers)
addUnique(root.layers, layer); AddUnique(root.layers, layer);
root.ymin = Math.Min(root.ymin, regn.ymin); root.ymin = Math.Min(root.ymin, regn.ymin);
root.ymax = Math.Max(root.ymax, regn.ymax); root.ymax = Math.Max(root.ymax, regn.ymax);
} }
@ -336,7 +336,7 @@ namespace DotRecast.Recast
continue; continue;
// Skip if the regions are not close to each other. // Skip if the regions are not close to each other.
if (!overlapRange(ri.ymin, ri.ymax + mergeHeight, rj.ymin, rj.ymax + mergeHeight)) if (!OverlapRange(ri.ymin, ri.ymax + mergeHeight, rj.ymin, rj.ymax + mergeHeight))
continue; continue;
// Skip if the height range would become too large. // Skip if the height range would become too large.
int ymin = Math.Min(ri.ymin, rj.ymin); int ymin = Math.Min(ri.ymin, rj.ymin);
@ -355,7 +355,7 @@ namespace DotRecast.Recast
continue; continue;
// Check if region 'k' is overlapping region 'ri' // Check if region 'k' is overlapping region 'ri'
// Index to 'regs' is the same as region id. // Index to 'regs' is the same as region id.
if (contains(ri.layers, k)) if (Contains(ri.layers, k))
{ {
overlap = true; overlap = true;
break; break;
@ -386,7 +386,7 @@ namespace DotRecast.Recast
rj.layerId = newId; rj.layerId = newId;
// Add overlaid layers from 'rj' to 'ri'. // Add overlaid layers from 'rj' to 'ri'.
foreach (int layer in rj.layers) foreach (int layer in rj.layers)
addUnique(ri.layers, layer); AddUnique(ri.layers, layer);
// Update height bounds. // Update height bounds.
ri.ymin = Math.Min(ri.ymin, rj.ymin); ri.ymin = Math.Min(ri.ymin, rj.ymin);
ri.ymax = Math.Max(ri.ymax, rj.ymax); ri.ymax = Math.Max(ri.ymax, rj.ymax);
@ -417,12 +417,12 @@ namespace DotRecast.Recast
// No layers, return empty. // No layers, return empty.
if (layerId == 0) if (layerId == 0)
{ {
// ctx.stopTimer(RC_TIMER_BUILD_LAYERS); // ctx.StopTimer(RC_TIMER_BUILD_LAYERS);
return null; return null;
} }
// Create layers. // Create layers.
// rcAssert(lset.layers == 0); // RcAssert(lset.layers == 0);
int lw = w - borderSize * 2; int lw = w - borderSize * 2;
int lh = h - borderSize * 2; int lh = h - borderSize * 2;
@ -560,7 +560,7 @@ namespace DotRecast.Recast
layer.miny = layer.maxy = 0; layer.miny = layer.maxy = 0;
} }
// ctx->stopTimer(RC_TIMER_BUILD_LAYERS); // ctx->StopTimer(RC_TIMER_BUILD_LAYERS);
return lset; return lset;
} }
} }

View File

@ -36,7 +36,7 @@ namespace DotRecast.Recast
public int[] poly = new int[2]; public int[] poly = new int[2];
} }
private static void buildMeshAdjacency(int[] polys, int npolys, int nverts, int vertsPerPoly) private static void BuildMeshAdjacency(int[] polys, int npolys, int nverts, int vertsPerPoly)
{ {
// Based on code by Eric Lengyel from: // Based on code by Eric Lengyel from:
// http://www.terathon.com/code/edges.php // http://www.terathon.com/code/edges.php
@ -121,7 +121,7 @@ namespace DotRecast.Recast
} }
} }
private static int computeVertexHash(int x, int y, int z) private static int ComputeVertexHash(int x, int y, int z)
{ {
uint h1 = 0x8da6b343; // Large multiplicative constants; uint h1 = 0x8da6b343; // Large multiplicative constants;
uint h2 = 0xd8163841; // here arbitrarily chosen primes uint h2 = 0xd8163841; // here arbitrarily chosen primes
@ -131,9 +131,9 @@ namespace DotRecast.Recast
return (int)(n & (VERTEX_BUCKET_COUNT - 1)); return (int)(n & (VERTEX_BUCKET_COUNT - 1));
} }
private static int[] addVertex(int x, int y, int z, int[] verts, int[] firstVert, int[] nextVert, int nv) private static int[] AddVertex(int x, int y, int z, int[] verts, int[] firstVert, int[] nextVert, int nv)
{ {
int bucket = computeVertexHash(x, 0, z); int bucket = ComputeVertexHash(x, 0, z);
int i = firstVert[bucket]; int i = firstVert[bucket];
while (i != -1) while (i != -1)
@ -157,17 +157,17 @@ namespace DotRecast.Recast
return new int[] { i, nv }; return new int[] { i, nv };
} }
public static int prev(int i, int n) public static int Prev(int i, int n)
{ {
return i - 1 >= 0 ? i - 1 : n - 1; return i - 1 >= 0 ? i - 1 : n - 1;
} }
public static int next(int i, int n) public static int Next(int i, int n)
{ {
return i + 1 < n ? i + 1 : 0; return i + 1 < n ? i + 1 : 0;
} }
private static int area2(int[] verts, int a, int b, int c) private static int Area2(int[] verts, int a, int b, int c)
{ {
return (verts[b + 0] - verts[a + 0]) * (verts[c + 2] - verts[a + 2]) return (verts[b + 0] - verts[a + 0]) * (verts[c + 2] - verts[a + 2])
- (verts[c + 0] - verts[a + 0]) * (verts[b + 2] - verts[a + 2]); - (verts[c + 0] - verts[a + 0]) * (verts[b + 2] - verts[a + 2]);
@ -175,39 +175,39 @@ namespace DotRecast.Recast
// Returns true iff c is strictly to the left of the directed // Returns true iff c is strictly to the left of the directed
// line through a to b. // line through a to b.
public static bool left(int[] verts, int a, int b, int c) public static bool Left(int[] verts, int a, int b, int c)
{ {
return area2(verts, a, b, c) < 0; return Area2(verts, a, b, c) < 0;
} }
public static bool leftOn(int[] verts, int a, int b, int c) public static bool LeftOn(int[] verts, int a, int b, int c)
{ {
return area2(verts, a, b, c) <= 0; return Area2(verts, a, b, c) <= 0;
} }
private static bool collinear(int[] verts, int a, int b, int c) private static bool Collinear(int[] verts, int a, int b, int c)
{ {
return area2(verts, a, b, c) == 0; return Area2(verts, a, b, c) == 0;
} }
// Returns true iff ab properly intersects cd: they share // Returns true iff ab properly intersects cd: they share
// a point interior to both segments. The properness of the // a point interior to both segments. The properness of the
// intersection is ensured by using strict leftness. // intersection is ensured by using strict leftness.
private static bool intersectProp(int[] verts, int a, int b, int c, int d) private static bool IntersectProp(int[] verts, int a, int b, int c, int d)
{ {
// Eliminate improper cases. // Eliminate improper cases.
if (collinear(verts, a, b, c) || collinear(verts, a, b, d) || collinear(verts, c, d, a) if (Collinear(verts, a, b, c) || Collinear(verts, a, b, d) || Collinear(verts, c, d, a)
|| collinear(verts, c, d, b)) || Collinear(verts, c, d, b))
return false; return false;
return (left(verts, a, b, c) ^ left(verts, a, b, d)) && (left(verts, c, d, a) ^ left(verts, c, d, b)); return (Left(verts, a, b, c) ^ Left(verts, a, b, d)) && (Left(verts, c, d, a) ^ Left(verts, c, d, b));
} }
// Returns T iff (a,b,c) are collinear and point c lies // Returns T iff (a,b,c) are collinear and point c lies
// on the closed segement ab. // on the closed segement ab.
private static bool between(int[] verts, int a, int b, int c) private static bool Between(int[] verts, int a, int b, int c)
{ {
if (!collinear(verts, a, b, c)) if (!Collinear(verts, a, b, c))
return false; return false;
// If ab not vertical, check betweenness on x; else on y. // If ab not vertical, check betweenness on x; else on y.
if (verts[a + 0] != verts[b + 0]) if (verts[a + 0] != verts[b + 0])
@ -219,25 +219,25 @@ namespace DotRecast.Recast
} }
// Returns true iff segments ab and cd intersect, properly or improperly. // Returns true iff segments ab and cd intersect, properly or improperly.
public static bool intersect(int[] verts, int a, int b, int c, int d) public static bool Intersect(int[] verts, int a, int b, int c, int d)
{ {
if (intersectProp(verts, a, b, c, d)) if (IntersectProp(verts, a, b, c, d))
return true; return true;
else if (between(verts, a, b, c) || between(verts, a, b, d) || between(verts, c, d, a) else if (Between(verts, a, b, c) || Between(verts, a, b, d) || Between(verts, c, d, a)
|| between(verts, c, d, b)) || Between(verts, c, d, b))
return true; return true;
else else
return false; return false;
} }
public static bool vequal(int[] verts, int a, int b) public static bool Vequal(int[] verts, int a, int b)
{ {
return verts[a + 0] == verts[b + 0] && verts[a + 2] == verts[b + 2]; return verts[a + 0] == verts[b + 0] && verts[a + 2] == verts[b + 2];
} }
// Returns T iff (v_i, v_j) is a proper internal *or* external // Returns T iff (v_i, v_j) is a proper internal *or* external
// diagonal of P, *ignoring edges incident to v_i and v_j*. // diagonal of P, *ignoring edges incident to v_i and v_j*.
private static bool diagonalie(int i, int j, int n, int[] verts, int[] indices) private static bool Diagonalie(int i, int j, int n, int[] verts, int[] indices)
{ {
int d0 = (indices[i] & 0x0fffffff) * 4; int d0 = (indices[i] & 0x0fffffff) * 4;
int d1 = (indices[j] & 0x0fffffff) * 4; int d1 = (indices[j] & 0x0fffffff) * 4;
@ -245,17 +245,17 @@ namespace DotRecast.Recast
// For each edge (k,k+1) of P // For each edge (k,k+1) of P
for (int k = 0; k < n; k++) for (int k = 0; k < n; k++)
{ {
int k1 = next(k, n); int k1 = Next(k, n);
// Skip edges incident to i or j // Skip edges incident to i or j
if (!((k == i) || (k1 == i) || (k == j) || (k1 == j))) if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
{ {
int p0 = (indices[k] & 0x0fffffff) * 4; int p0 = (indices[k] & 0x0fffffff) * 4;
int p1 = (indices[k1] & 0x0fffffff) * 4; int p1 = (indices[k1] & 0x0fffffff) * 4;
if (vequal(verts, d0, p0) || vequal(verts, d1, p0) || vequal(verts, d0, p1) || vequal(verts, d1, p1)) if (Vequal(verts, d0, p0) || Vequal(verts, d1, p0) || Vequal(verts, d0, p1) || Vequal(verts, d1, p1))
continue; continue;
if (intersect(verts, d0, d1, p0, p1)) if (Intersect(verts, d0, d1, p0, p1))
return false; return false;
} }
} }
@ -265,31 +265,31 @@ namespace DotRecast.Recast
// Returns true iff the diagonal (i,j) is strictly internal to the // Returns true iff the diagonal (i,j) is strictly internal to the
// polygon P in the neighborhood of the i endpoint. // polygon P in the neighborhood of the i endpoint.
private static bool inCone(int i, int j, int n, int[] verts, int[] indices) private static bool InCone(int i, int j, int n, int[] verts, int[] indices)
{ {
int pi = (indices[i] & 0x0fffffff) * 4; int pi = (indices[i] & 0x0fffffff) * 4;
int pj = (indices[j] & 0x0fffffff) * 4; int pj = (indices[j] & 0x0fffffff) * 4;
int pi1 = (indices[next(i, n)] & 0x0fffffff) * 4; int pi1 = (indices[Next(i, n)] & 0x0fffffff) * 4;
int pin1 = (indices[prev(i, n)] & 0x0fffffff) * 4; int pin1 = (indices[Prev(i, n)] & 0x0fffffff) * 4;
// If P[i] is a convex vertex [ i+1 left or on (i-1,i) ]. // If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
if (leftOn(verts, pin1, pi, pi1)) if (LeftOn(verts, pin1, pi, pi1))
{ {
return left(verts, pi, pj, pin1) && left(verts, pj, pi, pi1); return Left(verts, pi, pj, pin1) && Left(verts, pj, pi, pi1);
} }
// Assume (i-1,i,i+1) not collinear. // Assume (i-1,i,i+1) not collinear.
// else P[i] is reflex. // else P[i] is reflex.
return !(leftOn(verts, pi, pj, pi1) && leftOn(verts, pj, pi, pin1)); return !(LeftOn(verts, pi, pj, pi1) && LeftOn(verts, pj, pi, pin1));
} }
// Returns T iff (v_i, v_j) is a proper internal // Returns T iff (v_i, v_j) is a proper internal
// diagonal of P. // diagonal of P.
private static bool diagonal(int i, int j, int n, int[] verts, int[] indices) private static bool Diagonal(int i, int j, int n, int[] verts, int[] indices)
{ {
return inCone(i, j, n, verts, indices) && diagonalie(i, j, n, verts, indices); return InCone(i, j, n, verts, indices) && Diagonalie(i, j, n, verts, indices);
} }
private static bool diagonalieLoose(int i, int j, int n, int[] verts, int[] indices) private static bool DiagonalieLoose(int i, int j, int n, int[] verts, int[] indices)
{ {
int d0 = (indices[i] & 0x0fffffff) * 4; int d0 = (indices[i] & 0x0fffffff) * 4;
int d1 = (indices[j] & 0x0fffffff) * 4; int d1 = (indices[j] & 0x0fffffff) * 4;
@ -297,17 +297,17 @@ namespace DotRecast.Recast
// For each edge (k,k+1) of P // For each edge (k,k+1) of P
for (int k = 0; k < n; k++) for (int k = 0; k < n; k++)
{ {
int k1 = next(k, n); int k1 = Next(k, n);
// Skip edges incident to i or j // Skip edges incident to i or j
if (!((k == i) || (k1 == i) || (k == j) || (k1 == j))) if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
{ {
int p0 = (indices[k] & 0x0fffffff) * 4; int p0 = (indices[k] & 0x0fffffff) * 4;
int p1 = (indices[k1] & 0x0fffffff) * 4; int p1 = (indices[k1] & 0x0fffffff) * 4;
if (vequal(verts, d0, p0) || vequal(verts, d1, p0) || vequal(verts, d0, p1) || vequal(verts, d1, p1)) if (Vequal(verts, d0, p0) || Vequal(verts, d1, p0) || Vequal(verts, d0, p1) || Vequal(verts, d1, p1))
continue; continue;
if (intersectProp(verts, d0, d1, p0, p1)) if (IntersectProp(verts, d0, d1, p0, p1))
return false; return false;
} }
} }
@ -315,36 +315,36 @@ namespace DotRecast.Recast
return true; return true;
} }
private static bool inConeLoose(int i, int j, int n, int[] verts, int[] indices) private static bool InConeLoose(int i, int j, int n, int[] verts, int[] indices)
{ {
int pi = (indices[i] & 0x0fffffff) * 4; int pi = (indices[i] & 0x0fffffff) * 4;
int pj = (indices[j] & 0x0fffffff) * 4; int pj = (indices[j] & 0x0fffffff) * 4;
int pi1 = (indices[next(i, n)] & 0x0fffffff) * 4; int pi1 = (indices[Next(i, n)] & 0x0fffffff) * 4;
int pin1 = (indices[prev(i, n)] & 0x0fffffff) * 4; int pin1 = (indices[Prev(i, n)] & 0x0fffffff) * 4;
// If P[i] is a convex vertex [ i+1 left or on (i-1,i) ]. // If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
if (leftOn(verts, pin1, pi, pi1)) if (LeftOn(verts, pin1, pi, pi1))
return leftOn(verts, pi, pj, pin1) && leftOn(verts, pj, pi, pi1); return LeftOn(verts, pi, pj, pin1) && LeftOn(verts, pj, pi, pi1);
// Assume (i-1,i,i+1) not collinear. // Assume (i-1,i,i+1) not collinear.
// else P[i] is reflex. // else P[i] is reflex.
return !(leftOn(verts, pi, pj, pi1) && leftOn(verts, pj, pi, pin1)); return !(LeftOn(verts, pi, pj, pi1) && LeftOn(verts, pj, pi, pin1));
} }
private static bool diagonalLoose(int i, int j, int n, int[] verts, int[] indices) private static bool DiagonalLoose(int i, int j, int n, int[] verts, int[] indices)
{ {
return inConeLoose(i, j, n, verts, indices) && diagonalieLoose(i, j, n, verts, indices); return InConeLoose(i, j, n, verts, indices) && DiagonalieLoose(i, j, n, verts, indices);
} }
private static int triangulate(int n, int[] verts, int[] indices, int[] tris) private static int Triangulate(int n, int[] verts, int[] indices, int[] tris)
{ {
int ntris = 0; int ntris = 0;
// The last bit of the index is used to indicate if the vertex can be removed. // The last bit of the index is used to indicate if the vertex can be removed.
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
{ {
int i1 = next(i, n); int i1 = Next(i, n);
int i2 = next(i1, n); int i2 = Next(i1, n);
if (diagonal(i, i2, n, verts, indices)) if (Diagonal(i, i2, n, verts, indices))
{ {
indices[i1] |= int.MinValue; // TODO : 체크 필요 indices[i1] |= int.MinValue; // TODO : 체크 필요
} }
@ -356,11 +356,11 @@ namespace DotRecast.Recast
int mini = -1; int mini = -1;
for (int minIdx = 0; minIdx < n; minIdx++) for (int minIdx = 0; minIdx < n; minIdx++)
{ {
int nextIdx1 = next(minIdx, n); int nextIdx1 = Next(minIdx, n);
if ((indices[nextIdx1] & 0x80000000) != 0) if ((indices[nextIdx1] & 0x80000000) != 0)
{ {
int p0 = (indices[minIdx] & 0x0fffffff) * 4; int p0 = (indices[minIdx] & 0x0fffffff) * 4;
int p2 = (indices[next(nextIdx1, n)] & 0x0fffffff) * 4; int p2 = (indices[Next(nextIdx1, n)] & 0x0fffffff) * 4;
int dx = verts[p2 + 0] - verts[p0 + 0]; int dx = verts[p2 + 0] - verts[p0 + 0];
int dy = verts[p2 + 2] - verts[p0 + 2]; int dy = verts[p2 + 2] - verts[p0 + 2];
@ -388,12 +388,12 @@ namespace DotRecast.Recast
mini = -1; mini = -1;
for (int minIdx = 0; minIdx < n; minIdx++) for (int minIdx = 0; minIdx < n; minIdx++)
{ {
int nextIdx1 = next(minIdx, n); int nextIdx1 = Next(minIdx, n);
int nextIdx2 = next(nextIdx1, n); int nextIdx2 = Next(nextIdx1, n);
if (diagonalLoose(minIdx, nextIdx2, n, verts, indices)) if (DiagonalLoose(minIdx, nextIdx2, n, verts, indices))
{ {
int p0 = (indices[minIdx] & 0x0fffffff) * 4; int p0 = (indices[minIdx] & 0x0fffffff) * 4;
int p2 = (indices[next(nextIdx2, n)] & 0x0fffffff) * 4; int p2 = (indices[Next(nextIdx2, n)] & 0x0fffffff) * 4;
int dx = verts[p2 + 0] - verts[p0 + 0]; int dx = verts[p2 + 0] - verts[p0 + 0];
int dy = verts[p2 + 2] - verts[p0 + 2]; int dy = verts[p2 + 2] - verts[p0 + 2];
int len = dx * dx + dy * dy; int len = dx * dx + dy * dy;
@ -415,8 +415,8 @@ namespace DotRecast.Recast
} }
int i = mini; int i = mini;
int i1 = next(i, n); int i1 = Next(i, n);
int i2 = next(i1, n); int i2 = Next(i1, n);
tris[ntris * 3] = indices[i] & 0x0fffffff; tris[ntris * 3] = indices[i] & 0x0fffffff;
tris[ntris * 3 + 1] = indices[i1] & 0x0fffffff; tris[ntris * 3 + 1] = indices[i1] & 0x0fffffff;
@ -430,14 +430,14 @@ namespace DotRecast.Recast
if (i1 >= n) if (i1 >= n)
i1 = 0; i1 = 0;
i = prev(i1, n); i = Prev(i1, n);
// Update diagonal flags. // Update diagonal flags.
if (diagonal(prev(i, n), i1, n, verts, indices)) if (Diagonal(Prev(i, n), i1, n, verts, indices))
indices[i] |= int.MinValue; indices[i] |= int.MinValue;
else else
indices[i] &= 0x0fffffff; indices[i] &= 0x0fffffff;
if (diagonal(i, next(i1, n), n, verts, indices)) if (Diagonal(i, Next(i1, n), n, verts, indices))
indices[i1] |= int.MinValue; indices[i1] |= int.MinValue;
else else
indices[i1] &= 0x0fffffff; indices[i1] &= 0x0fffffff;
@ -452,7 +452,7 @@ namespace DotRecast.Recast
return ntris; return ntris;
} }
private static int countPolyVerts(int[] p, int j, int nvp) private static int CountPolyVerts(int[] p, int j, int nvp)
{ {
for (int i = 0; i < nvp; ++i) for (int i = 0; i < nvp; ++i)
if (p[i + j] == RC_MESH_NULL_IDX) if (p[i + j] == RC_MESH_NULL_IDX)
@ -460,18 +460,18 @@ namespace DotRecast.Recast
return nvp; return nvp;
} }
private static bool uleft(int[] verts, int a, int b, int c) private static bool Uleft(int[] verts, int a, int b, int c)
{ {
return (verts[b + 0] - verts[a + 0]) * (verts[c + 2] - verts[a + 2]) return (verts[b + 0] - verts[a + 0]) * (verts[c + 2] - verts[a + 2])
- (verts[c + 0] - verts[a + 0]) * (verts[b + 2] - verts[a + 2]) < 0; - (verts[c + 0] - verts[a + 0]) * (verts[b + 2] - verts[a + 2]) < 0;
} }
private static int[] getPolyMergeValue(int[] polys, int pa, int pb, int[] verts, int nvp) private static int[] GetPolyMergeValue(int[] polys, int pa, int pb, int[] verts, int nvp)
{ {
int ea = -1; int ea = -1;
int eb = -1; int eb = -1;
int na = countPolyVerts(polys, pa, nvp); int na = CountPolyVerts(polys, pa, nvp);
int nb = countPolyVerts(polys, pb, nvp); int nb = CountPolyVerts(polys, pb, nvp);
// If the merged polygon would be too big, do not merge. // If the merged polygon would be too big, do not merge.
if (na + nb - 2 > nvp) if (na + nb - 2 > nvp)
@ -520,13 +520,13 @@ namespace DotRecast.Recast
va = polys[pa + (ea + na - 1) % na]; va = polys[pa + (ea + na - 1) % na];
vb = polys[pa + ea]; vb = polys[pa + ea];
vc = polys[pb + (eb + 2) % nb]; vc = polys[pb + (eb + 2) % nb];
if (!uleft(verts, va * 3, vb * 3, vc * 3)) if (!Uleft(verts, va * 3, vb * 3, vc * 3))
return new int[] { -1, ea, eb }; return new int[] { -1, ea, eb };
va = polys[pb + (eb + nb - 1) % nb]; va = polys[pb + (eb + nb - 1) % nb];
vb = polys[pb + eb]; vb = polys[pb + eb];
vc = polys[pa + (ea + 2) % na]; vc = polys[pa + (ea + 2) % na];
if (!uleft(verts, va * 3, vb * 3, vc * 3)) if (!Uleft(verts, va * 3, vb * 3, vc * 3))
return new int[] { -1, ea, eb }; return new int[] { -1, ea, eb };
va = polys[pa + ea]; va = polys[pa + ea];
@ -538,10 +538,10 @@ namespace DotRecast.Recast
return new int[] { dx * dx + dy * dy, ea, eb }; return new int[] { dx * dx + dy * dy, ea, eb };
} }
private static void mergePolyVerts(int[] polys, int pa, int pb, int ea, int eb, int tmp, int nvp) private static void MergePolyVerts(int[] polys, int pa, int pb, int ea, int eb, int tmp, int nvp)
{ {
int na = countPolyVerts(polys, pa, nvp); int na = CountPolyVerts(polys, pa, nvp);
int nb = countPolyVerts(polys, pb, nvp); int nb = CountPolyVerts(polys, pb, nvp);
// Merge polygons. // Merge polygons.
Array.Fill(polys, RC_MESH_NULL_IDX, tmp, (tmp + nvp) - (tmp)); Array.Fill(polys, RC_MESH_NULL_IDX, tmp, (tmp + nvp) - (tmp));
@ -563,7 +563,7 @@ namespace DotRecast.Recast
Array.Copy(polys, tmp, polys, pa, nvp); Array.Copy(polys, tmp, polys, pa, nvp);
} }
private static int pushFront(int v, int[] arr, int an) private static int PushFront(int v, int[] arr, int an)
{ {
an++; an++;
for (int i = an - 1; i > 0; --i) for (int i = an - 1; i > 0; --i)
@ -572,14 +572,14 @@ namespace DotRecast.Recast
return an; return an;
} }
private static int pushBack(int v, int[] arr, int an) private static int PushBack(int v, int[] arr, int an)
{ {
arr[an] = v; arr[an] = v;
an++; an++;
return an; return an;
} }
private static bool canRemoveVertex(Telemetry ctx, PolyMesh mesh, int rem) private static bool CanRemoveVertex(Telemetry ctx, PolyMesh mesh, int rem)
{ {
int nvp = mesh.nvp; int nvp = mesh.nvp;
@ -589,7 +589,7 @@ namespace DotRecast.Recast
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
{ {
int p = i * nvp * 2; int p = i * nvp * 2;
int nv = countPolyVerts(mesh.polys, p, nvp); int nv = CountPolyVerts(mesh.polys, p, nvp);
int numRemoved = 0; int numRemoved = 0;
int numVerts = 0; int numVerts = 0;
for (int j = 0; j < nv; ++j) for (int j = 0; j < nv; ++j)
@ -624,7 +624,7 @@ namespace DotRecast.Recast
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
{ {
int p = i * nvp * 2; int p = i * nvp * 2;
int nv = countPolyVerts(mesh.polys, p, nvp); int nv = CountPolyVerts(mesh.polys, p, nvp);
// Collect edges which touches the removed vertex. // Collect edges which touches the removed vertex.
for (int j = 0, k = nv - 1; j < nv; k = j++) for (int j = 0, k = nv - 1; j < nv; k = j++)
@ -682,7 +682,7 @@ namespace DotRecast.Recast
return true; return true;
} }
private static void removeVertex(Telemetry ctx, PolyMesh mesh, int rem, int maxTris) private static void RemoveVertex(Telemetry ctx, PolyMesh mesh, int rem, int maxTris)
{ {
int nvp = mesh.nvp; int nvp = mesh.nvp;
@ -691,7 +691,7 @@ namespace DotRecast.Recast
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
{ {
int p = i * nvp * 2; int p = i * nvp * 2;
int nv = countPolyVerts(mesh.polys, p, nvp); int nv = CountPolyVerts(mesh.polys, p, nvp);
for (int j = 0; j < nv; ++j) for (int j = 0; j < nv; ++j)
{ {
if (mesh.polys[p + j] == rem) if (mesh.polys[p + j] == rem)
@ -714,7 +714,7 @@ namespace DotRecast.Recast
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
{ {
int p = i * nvp * 2; int p = i * nvp * 2;
int nv = countPolyVerts(mesh.polys, p, nvp); int nv = CountPolyVerts(mesh.polys, p, nvp);
bool hasRem = false; bool hasRem = false;
for (int j = 0; j < nv; ++j) for (int j = 0; j < nv; ++j)
if (mesh.polys[p + j] == rem) if (mesh.polys[p + j] == rem)
@ -764,7 +764,7 @@ namespace DotRecast.Recast
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
{ {
int p = i * nvp * 2; int p = i * nvp * 2;
int nv = countPolyVerts(mesh.polys, p, nvp); int nv = CountPolyVerts(mesh.polys, p, nvp);
for (int j = 0; j < nv; ++j) for (int j = 0; j < nv; ++j)
if (mesh.polys[p + j] > rem) if (mesh.polys[p + j] > rem)
mesh.polys[p + j]--; mesh.polys[p + j]--;
@ -783,9 +783,9 @@ namespace DotRecast.Recast
// Start with one vertex, keep appending connected // Start with one vertex, keep appending connected
// segments to the start and end of the hole. // segments to the start and end of the hole.
nhole = pushBack(edges[0], hole, nhole); nhole = PushBack(edges[0], hole, nhole);
nhreg = pushBack(edges[2], hreg, nhreg); nhreg = PushBack(edges[2], hreg, nhreg);
nharea = pushBack(edges[3], harea, nharea); nharea = PushBack(edges[3], harea, nharea);
while (nedges != 0) while (nedges != 0)
{ {
@ -801,17 +801,17 @@ namespace DotRecast.Recast
if (hole[0] == eb) if (hole[0] == eb)
{ {
// The segment matches the beginning of the hole boundary. // The segment matches the beginning of the hole boundary.
nhole = pushFront(ea, hole, nhole); nhole = PushFront(ea, hole, nhole);
nhreg = pushFront(r, hreg, nhreg); nhreg = PushFront(r, hreg, nhreg);
nharea = pushFront(a, harea, nharea); nharea = PushFront(a, harea, nharea);
add = true; add = true;
} }
else if (hole[nhole - 1] == ea) else if (hole[nhole - 1] == ea)
{ {
// The segment matches the end of the hole boundary. // The segment matches the end of the hole boundary.
nhole = pushBack(eb, hole, nhole); nhole = PushBack(eb, hole, nhole);
nhreg = pushBack(r, hreg, nhreg); nhreg = PushBack(r, hreg, nhreg);
nharea = pushBack(a, harea, nharea); nharea = PushBack(a, harea, nharea);
add = true; add = true;
} }
@ -850,11 +850,11 @@ namespace DotRecast.Recast
} }
// Triangulate the hole. // Triangulate the hole.
int ntris = triangulate(nhole, tverts, thole, tris); int ntris = Triangulate(nhole, tverts, thole, tris);
if (ntris < 0) if (ntris < 0)
{ {
ntris = -ntris; ntris = -ntris;
ctx.warn("removeVertex: triangulate() returned bad results."); ctx.Warn("removeVertex: Triangulate() returned bad results.");
} }
// Merge the hole triangles back to polygons. // Merge the hole triangles back to polygons.
@ -906,7 +906,7 @@ namespace DotRecast.Recast
for (int k = j + 1; k < npolys; ++k) for (int k = j + 1; k < npolys; ++k)
{ {
int pk = k * nvp; int pk = k * nvp;
int[] veaeb = getPolyMergeValue(polys, pj, pk, mesh.verts, nvp); int[] veaeb = GetPolyMergeValue(polys, pj, pk, mesh.verts, nvp);
int v = veaeb[0]; int v = veaeb[0];
int ea = veaeb[1]; int ea = veaeb[1];
int eb = veaeb[2]; int eb = veaeb[2];
@ -926,7 +926,7 @@ namespace DotRecast.Recast
// Found best, merge. // Found best, merge.
int pa = bestPa * nvp; int pa = bestPa * nvp;
int pb = bestPb * nvp; int pb = bestPb * nvp;
mergePolyVerts(polys, pa, pb, bestEa, bestEb, tmpPoly, nvp); MergePolyVerts(polys, pa, pb, bestEa, bestEb, tmpPoly, nvp);
if (pregs[bestPa] != pregs[bestPb]) if (pregs[bestPa] != pregs[bestPb])
pregs[bestPa] = RC_MULTIPLE_REGS; pregs[bestPa] = RC_MULTIPLE_REGS;
int last = (npolys - 1) * nvp; int last = (npolys - 1) * nvp;
@ -972,9 +972,9 @@ namespace DotRecast.Recast
/// limit must be retricted to <= #DT_VERTS_PER_POLYGON. /// limit must be retricted to <= #DT_VERTS_PER_POLYGON.
/// ///
/// @see rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig /// @see rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig
public static PolyMesh buildPolyMesh(Telemetry ctx, ContourSet cset, int nvp) public static PolyMesh BuildPolyMesh(Telemetry ctx, ContourSet cset, int nvp)
{ {
ctx.startTimer("POLYMESH"); ctx.StartTimer("POLYMESH");
PolyMesh mesh = new PolyMesh(); PolyMesh mesh = new PolyMesh();
mesh.bmin = cset.bmin; mesh.bmin = cset.bmin;
mesh.bmax = cset.bmax; mesh.bmax = cset.bmax;
@ -1037,11 +1037,11 @@ namespace DotRecast.Recast
// Triangulate contour // Triangulate contour
for (int j = 0; j < cont.nverts; ++j) for (int j = 0; j < cont.nverts; ++j)
indices[j] = j; indices[j] = j;
int ntris = triangulate(cont.nverts, cont.verts, indices, tris); int ntris = Triangulate(cont.nverts, cont.verts, indices, tris);
if (ntris <= 0) if (ntris <= 0)
{ {
// Bad triangulation, should not happen. // Bad triangulation, should not happen.
ctx.warn("buildPolyMesh: Bad triangulation Contour " + i + "."); ctx.Warn("buildPolyMesh: Bad triangulation Contour " + i + ".");
ntris = -ntris; ntris = -ntris;
} }
@ -1049,7 +1049,7 @@ namespace DotRecast.Recast
for (int j = 0; j < cont.nverts; ++j) for (int j = 0; j < cont.nverts; ++j)
{ {
int v = j * 4; int v = j * 4;
int[] inv = addVertex(cont.verts[v + 0], cont.verts[v + 1], cont.verts[v + 2], mesh.verts, firstVert, int[] inv = AddVertex(cont.verts[v + 0], cont.verts[v + 1], cont.verts[v + 2], mesh.verts, firstVert,
nextVert, mesh.nverts); nextVert, mesh.nverts);
indices[j] = inv[0]; indices[j] = inv[0];
mesh.nverts = inv[1]; mesh.nverts = inv[1];
@ -1093,7 +1093,7 @@ namespace DotRecast.Recast
for (int k = j + 1; k < npolys; ++k) for (int k = j + 1; k < npolys; ++k)
{ {
int pk = k * nvp; int pk = k * nvp;
int[] veaeb = getPolyMergeValue(polys, pj, pk, mesh.verts, nvp); int[] veaeb = GetPolyMergeValue(polys, pj, pk, mesh.verts, nvp);
int v = veaeb[0]; int v = veaeb[0];
int ea = veaeb[1]; int ea = veaeb[1];
int eb = veaeb[2]; int eb = veaeb[2];
@ -1113,7 +1113,7 @@ namespace DotRecast.Recast
// Found best, merge. // Found best, merge.
int pa = bestPa * nvp; int pa = bestPa * nvp;
int pb = bestPb * nvp; int pb = bestPb * nvp;
mergePolyVerts(polys, pa, pb, bestEa, bestEb, tmpPoly, nvp); MergePolyVerts(polys, pa, pb, bestEa, bestEb, tmpPoly, nvp);
int lastPoly = (npolys - 1) * nvp; int lastPoly = (npolys - 1) * nvp;
if (pb != lastPoly) if (pb != lastPoly)
{ {
@ -1153,11 +1153,11 @@ namespace DotRecast.Recast
{ {
if (vflags[i] != 0) if (vflags[i] != 0)
{ {
if (!canRemoveVertex(ctx, mesh, i)) if (!CanRemoveVertex(ctx, mesh, i))
continue; continue;
removeVertex(ctx, mesh, i, maxTris); RemoveVertex(ctx, mesh, i, maxTris);
// Remove vertex // Remove vertex
// Note: mesh.nverts is already decremented inside removeVertex()! // Note: mesh.nverts is already decremented inside RemoveVertex()!
// Fixup vertex flags // Fixup vertex flags
for (int j = i; j < mesh.nverts; ++j) for (int j = i; j < mesh.nverts; ++j)
vflags[j] = vflags[j + 1]; vflags[j] = vflags[j + 1];
@ -1166,7 +1166,7 @@ namespace DotRecast.Recast
} }
// Calculate adjacency. // Calculate adjacency.
buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, nvp); BuildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, nvp);
// Find portal edges // Find portal edges
if (mesh.borderSize > 0) if (mesh.borderSize > 0)
@ -1216,17 +1216,17 @@ namespace DotRecast.Recast
+ " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted."); + " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted.");
} }
ctx.stopTimer("POLYMESH"); ctx.StopTimer("POLYMESH");
return mesh; return mesh;
} }
/// @see rcAllocPolyMesh, rcPolyMesh /// @see rcAllocPolyMesh, rcPolyMesh
public static PolyMesh mergePolyMeshes(Telemetry ctx, PolyMesh[] meshes, int nmeshes) public static PolyMesh MergePolyMeshes(Telemetry ctx, PolyMesh[] meshes, int nmeshes)
{ {
if (nmeshes == 0 || meshes == null) if (nmeshes == 0 || meshes == null)
return null; return null;
ctx.startTimer("MERGE_POLYMESH"); ctx.StartTimer("MERGE_POLYMESH");
PolyMesh mesh = new PolyMesh(); PolyMesh mesh = new PolyMesh();
mesh.nvp = meshes[0].nvp; mesh.nvp = meshes[0].nvp;
mesh.cs = meshes[0].cs; mesh.cs = meshes[0].cs;
@ -1239,8 +1239,8 @@ namespace DotRecast.Recast
int maxVertsPerMesh = 0; int maxVertsPerMesh = 0;
for (int i = 0; i < nmeshes; ++i) for (int i = 0; i < nmeshes; ++i)
{ {
RecastVectors.min(ref mesh.bmin, meshes[i].bmin); RecastVectors.Min(ref mesh.bmin, meshes[i].bmin);
RecastVectors.max(ref mesh.bmax, meshes[i].bmax); RecastVectors.Max(ref mesh.bmax, meshes[i].bmax);
maxVertsPerMesh = Math.Max(maxVertsPerMesh, meshes[i].nverts); maxVertsPerMesh = Math.Max(maxVertsPerMesh, meshes[i].nverts);
maxVerts += meshes[i].nverts; maxVerts += meshes[i].nverts;
maxPolys += meshes[i].npolys; maxPolys += meshes[i].npolys;
@ -1280,7 +1280,7 @@ namespace DotRecast.Recast
for (int j = 0; j < pmesh.nverts; ++j) for (int j = 0; j < pmesh.nverts; ++j)
{ {
int v = j * 3; int v = j * 3;
int[] inv = addVertex(pmesh.verts[v + 0] + ox, pmesh.verts[v + 1], pmesh.verts[v + 2] + oz, mesh.verts, int[] inv = AddVertex(pmesh.verts[v + 0] + ox, pmesh.verts[v + 1], pmesh.verts[v + 2] + oz, mesh.verts,
firstVert, nextVert, mesh.nverts); firstVert, nextVert, mesh.nverts);
vremap[j] = inv[0]; vremap[j] = inv[0];
@ -1335,7 +1335,7 @@ namespace DotRecast.Recast
} }
// Calculate adjacency. // Calculate adjacency.
buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, mesh.nvp); BuildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, mesh.nvp);
if (mesh.nverts > MAX_MESH_VERTS_POLY) if (mesh.nverts > MAX_MESH_VERTS_POLY)
{ {
throw new Exception("rcBuildPolyMesh: The resulting mesh has too many vertices " + mesh.nverts throw new Exception("rcBuildPolyMesh: The resulting mesh has too many vertices " + mesh.nverts
@ -1348,12 +1348,12 @@ namespace DotRecast.Recast
+ " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted."); + " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted.");
} }
ctx.stopTimer("MERGE_POLYMESH"); ctx.StopTimer("MERGE_POLYMESH");
return mesh; return mesh;
} }
public static PolyMesh copyPolyMesh(Telemetry ctx, PolyMesh src) public static PolyMesh CopyPolyMesh(Telemetry ctx, PolyMesh src)
{ {
PolyMesh dst = new PolyMesh(); PolyMesh dst = new PolyMesh();

View File

@ -46,37 +46,37 @@ namespace DotRecast.Recast
public int[] data; public int[] data;
} }
private static float vdot2(float[] a, float[] b) private static float Vdot2(float[] a, float[] b)
{ {
return a[0] * b[0] + a[2] * b[2]; return a[0] * b[0] + a[2] * b[2];
} }
private static float vdot2(Vector3f a, Vector3f b) private static float Vdot2(Vector3f a, Vector3f b)
{ {
return a.x * b.x + a.z * b.z; return a.x * b.x + a.z * b.z;
} }
private static float vdistSq2(float[] verts, int p, int q) private static float VdistSq2(float[] verts, int p, int q)
{ {
float dx = verts[q + 0] - verts[p + 0]; float dx = verts[q + 0] - verts[p + 0];
float dy = verts[q + 2] - verts[p + 2]; float dy = verts[q + 2] - verts[p + 2];
return dx * dx + dy * dy; return dx * dx + dy * dy;
} }
private static float vdist2(float[] verts, int p, int q) private static float Vdist2(float[] verts, int p, int q)
{ {
return (float)Math.Sqrt(vdistSq2(verts, p, q)); return (float)Math.Sqrt(VdistSq2(verts, p, q));
} }
private static float vdistSq2(float[] p, float[] q) private static float VdistSq2(float[] p, float[] q)
{ {
float dx = q[0] - p[0]; float dx = q[0] - p[0];
float dy = q[2] - p[2]; float dy = q[2] - p[2];
return dx * dx + dy * dy; return dx * dx + dy * dy;
} }
private static float vdistSq2(float[] p, Vector3f q) private static float VdistSq2(float[] p, Vector3f q)
{ {
float dx = q.x - p[0]; float dx = q.x - p[0];
float dy = q.z - p[2]; float dy = q.z - p[2];
@ -84,7 +84,7 @@ namespace DotRecast.Recast
} }
private static float vdistSq2(Vector3f p, Vector3f q) private static float VdistSq2(Vector3f p, Vector3f q)
{ {
float dx = q.x - p.x; float dx = q.x - p.x;
float dy = q.z - p.z; float dy = q.z - p.z;
@ -92,30 +92,30 @@ namespace DotRecast.Recast
} }
private static float vdist2(float[] p, float[] q) private static float Vdist2(float[] p, float[] q)
{ {
return (float)Math.Sqrt(vdistSq2(p, q)); return (float)Math.Sqrt(VdistSq2(p, q));
} }
private static float vdist2(Vector3f p, Vector3f q) private static float Vdist2(Vector3f p, Vector3f q)
{ {
return (float)Math.Sqrt(vdistSq2(p, q)); return (float)Math.Sqrt(VdistSq2(p, q));
} }
private static float vdist2(float[] p, Vector3f q) private static float Vdist2(float[] p, Vector3f q)
{ {
return (float)Math.Sqrt(vdistSq2(p, q)); return (float)Math.Sqrt(VdistSq2(p, q));
} }
private static float vdistSq2(float[] p, float[] verts, int q) private static float VdistSq2(float[] p, float[] verts, int q)
{ {
float dx = verts[q + 0] - p[0]; float dx = verts[q + 0] - p[0];
float dy = verts[q + 2] - p[2]; float dy = verts[q + 2] - p[2];
return dx * dx + dy * dy; return dx * dx + dy * dy;
} }
private static float vdistSq2(Vector3f p, float[] verts, int q) private static float VdistSq2(Vector3f p, float[] verts, int q)
{ {
float dx = verts[q + 0] - p.x; float dx = verts[q + 0] - p.x;
float dy = verts[q + 2] - p.z; float dy = verts[q + 2] - p.z;
@ -123,18 +123,18 @@ namespace DotRecast.Recast
} }
private static float vdist2(float[] p, float[] verts, int q) private static float Vdist2(float[] p, float[] verts, int q)
{ {
return (float)Math.Sqrt(vdistSq2(p, verts, q)); return (float)Math.Sqrt(VdistSq2(p, verts, q));
} }
private static float vdist2(Vector3f p, float[] verts, int q) private static float Vdist2(Vector3f p, float[] verts, int q)
{ {
return (float)Math.Sqrt(vdistSq2(p, verts, q)); return (float)Math.Sqrt(VdistSq2(p, verts, q));
} }
private static float vcross2(float[] verts, int p1, int p2, int p3) private static float Vcross2(float[] verts, int p1, int p2, int p3)
{ {
float u1 = verts[p2 + 0] - verts[p1 + 0]; float u1 = verts[p2 + 0] - verts[p1 + 0];
float v1 = verts[p2 + 2] - verts[p1 + 2]; float v1 = verts[p2 + 2] - verts[p1 + 2];
@ -143,7 +143,7 @@ namespace DotRecast.Recast
return u1 * v2 - v1 * u2; return u1 * v2 - v1 * u2;
} }
private static float vcross2(float[] p1, float[] p2, float[] p3) private static float Vcross2(float[] p1, float[] p2, float[] p3)
{ {
float u1 = p2[0] - p1[0]; float u1 = p2[0] - p1[0];
float v1 = p2[2] - p1[2]; float v1 = p2[2] - p1[2];
@ -152,7 +152,7 @@ namespace DotRecast.Recast
return u1 * v2 - v1 * u2; return u1 * v2 - v1 * u2;
} }
private static float vcross2(Vector3f p1, Vector3f p2, Vector3f p3) private static float Vcross2(Vector3f p1, Vector3f p2, Vector3f p3)
{ {
float u1 = p2.x - p1.x; float u1 = p2.x - p1.x;
float v1 = p2.z - p1.z; float v1 = p2.z - p1.z;
@ -162,49 +162,49 @@ namespace DotRecast.Recast
} }
private static bool circumCircle(float[] verts, int p1, int p2, int p3, ref Vector3f c, AtomicFloat r) private static bool CircumCircle(float[] verts, int p1, int p2, int p3, ref Vector3f c, AtomicFloat r)
{ {
float EPS = 1e-6f; float EPS = 1e-6f;
// Calculate the circle relative to p1, to avoid some precision issues. // Calculate the circle relative to p1, to avoid some precision issues.
Vector3f v1 = new Vector3f(); Vector3f v1 = new Vector3f();
Vector3f v2 = new Vector3f(); Vector3f v2 = new Vector3f();
Vector3f v3 = new Vector3f(); Vector3f v3 = new Vector3f();
RecastVectors.sub(ref v2, verts, p2, p1); RecastVectors.Sub(ref v2, verts, p2, p1);
RecastVectors.sub(ref v3, verts, p3, p1); RecastVectors.Sub(ref v3, verts, p3, p1);
float cp = vcross2(v1, v2, v3); float cp = Vcross2(v1, v2, v3);
if (Math.Abs(cp) > EPS) if (Math.Abs(cp) > EPS)
{ {
float v1Sq = vdot2(v1, v1); float v1Sq = Vdot2(v1, v1);
float v2Sq = vdot2(v2, v2); float v2Sq = Vdot2(v2, v2);
float v3Sq = vdot2(v3, v3); float v3Sq = Vdot2(v3, v3);
c.x = (v1Sq * (v2.z - v3.z) + v2Sq * (v3.z - v1.z) + v3Sq * (v1.z - v2.z)) / (2 * cp); c.x = (v1Sq * (v2.z - v3.z) + v2Sq * (v3.z - v1.z) + v3Sq * (v1.z - v2.z)) / (2 * cp);
c.y = 0; c.y = 0;
c.z = (v1Sq * (v3.x - v2.x) + v2Sq * (v1.x - v3.x) + v3Sq * (v2.x - v1.x)) / (2 * cp); c.z = (v1Sq * (v3.x - v2.x) + v2Sq * (v1.x - v3.x) + v3Sq * (v2.x - v1.x)) / (2 * cp);
r.Exchange(vdist2(c, v1)); r.Exchange(Vdist2(c, v1));
RecastVectors.add(ref c, c, verts, p1); RecastVectors.Add(ref c, c, verts, p1);
return true; return true;
} }
RecastVectors.copy(ref c, verts, p1); RecastVectors.Copy(ref c, verts, p1);
r.Exchange(0f); r.Exchange(0f);
return false; return false;
} }
private static float distPtTri(Vector3f p, float[] verts, int a, int b, int c) private static float DistPtTri(Vector3f p, float[] verts, int a, int b, int c)
{ {
Vector3f v0 = new Vector3f(); Vector3f v0 = new Vector3f();
Vector3f v1 = new Vector3f(); Vector3f v1 = new Vector3f();
Vector3f v2 = new Vector3f(); Vector3f v2 = new Vector3f();
RecastVectors.sub(ref v0, verts, c, a); RecastVectors.Sub(ref v0, verts, c, a);
RecastVectors.sub(ref v1, verts, b, a); RecastVectors.Sub(ref v1, verts, b, a);
RecastVectors.sub(ref v2, p, verts, a); RecastVectors.Sub(ref v2, p, verts, a);
float dot00 = vdot2(v0, v0); float dot00 = Vdot2(v0, v0);
float dot01 = vdot2(v0, v1); float dot01 = Vdot2(v0, v1);
float dot02 = vdot2(v0, v2); float dot02 = Vdot2(v0, v2);
float dot11 = vdot2(v1, v1); float dot11 = Vdot2(v1, v1);
float dot12 = vdot2(v1, v2); float dot12 = Vdot2(v1, v2);
// Compute barycentric coordinates // Compute barycentric coordinates
float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
@ -222,7 +222,7 @@ namespace DotRecast.Recast
return float.MaxValue; return float.MaxValue;
} }
private static float distancePtSeg(float[] verts, int pt, int p, int q) private static float DistancePtSeg(float[] verts, int pt, int p, int q)
{ {
float pqx = verts[q + 0] - verts[p + 0]; float pqx = verts[q + 0] - verts[p + 0];
float pqy = verts[q + 1] - verts[p + 1]; float pqy = verts[q + 1] - verts[p + 1];
@ -253,7 +253,7 @@ namespace DotRecast.Recast
return dx * dx + dy * dy + dz * dz; return dx * dx + dy * dy + dz * dz;
} }
private static float distancePtSeg2d(Vector3f verts, float[] poly, int p, int q) private static float DistancePtSeg2d(Vector3f verts, float[] poly, int p, int q)
{ {
float pqx = poly[q + 0] - poly[p + 0]; float pqx = poly[q + 0] - poly[p + 0];
float pqz = poly[q + 2] - poly[p + 2]; float pqz = poly[q + 2] - poly[p + 2];
@ -281,7 +281,7 @@ namespace DotRecast.Recast
return dx * dx + dz * dz; return dx * dx + dz * dz;
} }
private static float distancePtSeg2d(float[] verts, int pt, float[] poly, int p, int q) private static float DistancePtSeg2d(float[] verts, int pt, float[] poly, int p, int q)
{ {
float pqx = poly[q + 0] - poly[p + 0]; float pqx = poly[q + 0] - poly[p + 0];
float pqz = poly[q + 2] - poly[p + 2]; float pqz = poly[q + 2] - poly[p + 2];
@ -309,7 +309,7 @@ namespace DotRecast.Recast
return dx * dx + dz * dz; return dx * dx + dz * dz;
} }
private static float distToTriMesh(Vector3f p, float[] verts, int nverts, List<int> tris, int ntris) private static float DistToTriMesh(Vector3f p, float[] verts, int nverts, List<int> tris, int ntris)
{ {
float dmin = float.MaxValue; float dmin = float.MaxValue;
for (int i = 0; i < ntris; ++i) for (int i = 0; i < ntris; ++i)
@ -317,7 +317,7 @@ namespace DotRecast.Recast
int va = tris[i * 4 + 0] * 3; int va = tris[i * 4 + 0] * 3;
int vb = tris[i * 4 + 1] * 3; int vb = tris[i * 4 + 1] * 3;
int vc = tris[i * 4 + 2] * 3; int vc = tris[i * 4 + 2] * 3;
float d = distPtTri(p, verts, va, vb, vc); float d = DistPtTri(p, verts, va, vb, vc);
if (d < dmin) if (d < dmin)
{ {
dmin = d; dmin = d;
@ -332,7 +332,7 @@ namespace DotRecast.Recast
return dmin; return dmin;
} }
private static float distToPoly(int nvert, float[] verts, Vector3f p) private static float DistToPoly(int nvert, float[] verts, Vector3f p)
{ {
float dmin = float.MaxValue; float dmin = float.MaxValue;
int i, j; int i, j;
@ -347,19 +347,19 @@ namespace DotRecast.Recast
c = !c; c = !c;
} }
dmin = Math.Min(dmin, distancePtSeg2d(p, verts, vj, vi)); dmin = Math.Min(dmin, DistancePtSeg2d(p, verts, vj, vi));
} }
return c ? -dmin : dmin; return c ? -dmin : dmin;
} }
private static int getHeight(float fx, float fy, float fz, float cs, float ics, float ch, int radius, private static int GetHeight(float fx, float fy, float fz, float cs, float ics, float ch, int radius,
HeightPatch hp) HeightPatch hp)
{ {
int ix = (int)Math.Floor(fx * ics + 0.01f); int ix = (int)Math.Floor(fx * ics + 0.01f);
int iz = (int)Math.Floor(fz * ics + 0.01f); int iz = (int)Math.Floor(fz * ics + 0.01f);
ix = clamp(ix - hp.xmin, 0, hp.width - 1); ix = Clamp(ix - hp.xmin, 0, hp.width - 1);
iz = clamp(iz - hp.ymin, 0, hp.height - 1); iz = Clamp(iz - hp.ymin, 0, hp.height - 1);
int h = hp.data[ix + iz * hp.width]; int h = hp.data[ix + iz * hp.width];
if (h == RC_UNSET_HEIGHT) if (h == RC_UNSET_HEIGHT)
{ {
@ -436,7 +436,7 @@ namespace DotRecast.Recast
return h; return h;
} }
private static int findEdge(List<int> edges, int s, int t) private static int FindEdge(List<int> edges, int s, int t)
{ {
for (int i = 0; i < edges.Count / 4; i++) for (int i = 0; i < edges.Count / 4; i++)
{ {
@ -450,7 +450,7 @@ namespace DotRecast.Recast
return EV_UNDEF; return EV_UNDEF;
} }
private static void addEdge(Telemetry ctx, List<int> edges, int maxEdges, int s, int t, int l, int r) private static void AddEdge(Telemetry ctx, List<int> edges, int maxEdges, int s, int t, int l, int r)
{ {
if (edges.Count / 4 >= maxEdges) if (edges.Count / 4 >= maxEdges)
{ {
@ -458,7 +458,7 @@ namespace DotRecast.Recast
} }
// Add edge if not already in the triangulation. // Add edge if not already in the triangulation.
int e = findEdge(edges, s, t); int e = FindEdge(edges, s, t);
if (e == EV_UNDEF) if (e == EV_UNDEF)
{ {
edges.Add(s); edges.Add(s);
@ -468,7 +468,7 @@ namespace DotRecast.Recast
} }
} }
private static void updateLeftFace(List<int> edges, int e, int s, int t, int f) private static void UpdateLeftFace(List<int> edges, int e, int s, int t, int f)
{ {
if (edges[e + 0] == s && edges[e + 1] == t && edges[e + 2] == EV_UNDEF) if (edges[e + 0] == s && edges[e + 1] == t && edges[e + 2] == EV_UNDEF)
{ {
@ -480,13 +480,13 @@ namespace DotRecast.Recast
} }
} }
private static bool overlapSegSeg2d(float[] verts, int a, int b, int c, int d) private static bool OverlapSegSeg2d(float[] verts, int a, int b, int c, int d)
{ {
float a1 = vcross2(verts, a, b, d); float a1 = Vcross2(verts, a, b, d);
float a2 = vcross2(verts, a, b, c); float a2 = Vcross2(verts, a, b, c);
if (a1 * a2 < 0.0f) if (a1 * a2 < 0.0f)
{ {
float a3 = vcross2(verts, c, d, a); float a3 = Vcross2(verts, c, d, a);
float a4 = a3 + a2 - a1; float a4 = a3 + a2 - a1;
if (a3 * a4 < 0.0f) if (a3 * a4 < 0.0f)
{ {
@ -497,7 +497,7 @@ namespace DotRecast.Recast
return false; return false;
} }
private static bool overlapEdges(float[] pts, List<int> edges, int s1, int t1) private static bool OverlapEdges(float[] pts, List<int> edges, int s1, int t1)
{ {
for (int i = 0; i < edges.Count / 4; ++i) for (int i = 0; i < edges.Count / 4; ++i)
{ {
@ -509,7 +509,7 @@ namespace DotRecast.Recast
continue; continue;
} }
if (overlapSegSeg2d(pts, s0 * 3, t0 * 3, s1 * 3, t1 * 3)) if (OverlapSegSeg2d(pts, s0 * 3, t0 * 3, s1 * 3, t1 * 3))
{ {
return true; return true;
} }
@ -518,7 +518,7 @@ namespace DotRecast.Recast
return false; return false;
} }
static int completeFacet(Telemetry ctx, float[] pts, int npts, List<int> edges, int maxEdges, int nfaces, int e) static int CompleteFacet(Telemetry ctx, float[] pts, int npts, List<int> edges, int maxEdges, int nfaces, int e)
{ {
float EPS = 1e-5f; float EPS = 1e-5f;
@ -553,17 +553,17 @@ namespace DotRecast.Recast
continue; continue;
} }
if (vcross2(pts, s * 3, t * 3, u * 3) > EPS) if (Vcross2(pts, s * 3, t * 3, u * 3) > EPS)
{ {
if (r.Get() < 0) if (r.Get() < 0)
{ {
// The circle is not updated yet, do it now. // The circle is not updated yet, do it now.
pt = u; pt = u;
circumCircle(pts, s * 3, t * 3, u * 3, ref c, r); CircumCircle(pts, s * 3, t * 3, u * 3, ref c, r);
continue; continue;
} }
float d = vdist2(c, pts, u * 3); float d = Vdist2(c, pts, u * 3);
float tol = 0.001f; float tol = 0.001f;
if (d > r.Get() * (1 + tol)) if (d > r.Get() * (1 + tol))
{ {
@ -574,25 +574,25 @@ namespace DotRecast.Recast
{ {
// Inside safe circumcircle, update circle. // Inside safe circumcircle, update circle.
pt = u; pt = u;
circumCircle(pts, s * 3, t * 3, u * 3, ref c, r); CircumCircle(pts, s * 3, t * 3, u * 3, ref c, r);
} }
else else
{ {
// Inside epsilon circum circle, do extra tests to make sure the edge is valid. // Inside epsilon circum circle, do extra tests to make sure the edge is valid.
// s-u and t-u cannot overlap with s-pt nor t-pt if they exists. // s-u and t-u cannot overlap with s-pt nor t-pt if they exists.
if (overlapEdges(pts, edges, s, u)) if (OverlapEdges(pts, edges, s, u))
{ {
continue; continue;
} }
if (overlapEdges(pts, edges, t, u)) if (OverlapEdges(pts, edges, t, u))
{ {
continue; continue;
} }
// Edge is valid. // Edge is valid.
pt = u; pt = u;
circumCircle(pts, s * 3, t * 3, u * 3, ref c, r); CircumCircle(pts, s * 3, t * 3, u * 3, ref c, r);
} }
} }
} }
@ -601,48 +601,48 @@ namespace DotRecast.Recast
if (pt < npts) if (pt < npts)
{ {
// Update face information of edge being completed. // Update face information of edge being completed.
updateLeftFace(edges, e * 4, s, t, nfaces); UpdateLeftFace(edges, e * 4, s, t, nfaces);
// Add new edge or update face info of old edge. // Add new edge or update face info of old edge.
e = findEdge(edges, pt, s); e = FindEdge(edges, pt, s);
if (e == EV_UNDEF) if (e == EV_UNDEF)
{ {
addEdge(ctx, edges, maxEdges, pt, s, nfaces, EV_UNDEF); AddEdge(ctx, edges, maxEdges, pt, s, nfaces, EV_UNDEF);
} }
else else
{ {
updateLeftFace(edges, e * 4, pt, s, nfaces); UpdateLeftFace(edges, e * 4, pt, s, nfaces);
} }
// Add new edge or update face info of old edge. // Add new edge or update face info of old edge.
e = findEdge(edges, t, pt); e = FindEdge(edges, t, pt);
if (e == EV_UNDEF) if (e == EV_UNDEF)
{ {
addEdge(ctx, edges, maxEdges, t, pt, nfaces, EV_UNDEF); AddEdge(ctx, edges, maxEdges, t, pt, nfaces, EV_UNDEF);
} }
else else
{ {
updateLeftFace(edges, e * 4, t, pt, nfaces); UpdateLeftFace(edges, e * 4, t, pt, nfaces);
} }
nfaces++; nfaces++;
} }
else else
{ {
updateLeftFace(edges, e * 4, s, t, EV_HULL); UpdateLeftFace(edges, e * 4, s, t, EV_HULL);
} }
return nfaces; return nfaces;
} }
private static void delaunayHull(Telemetry ctx, int npts, float[] pts, int nhull, int[] hull, List<int> tris) private static void DelaunayHull(Telemetry ctx, int npts, float[] pts, int nhull, int[] hull, List<int> tris)
{ {
int nfaces = 0; int nfaces = 0;
int maxEdges = npts * 10; int maxEdges = npts * 10;
List<int> edges = new List<int>(64); List<int> edges = new List<int>(64);
for (int i = 0, j = nhull - 1; i < nhull; j = i++) for (int i = 0, j = nhull - 1; i < nhull; j = i++)
{ {
addEdge(ctx, edges, maxEdges, hull[j], hull[i], EV_HULL, EV_UNDEF); AddEdge(ctx, edges, maxEdges, hull[j], hull[i], EV_HULL, EV_UNDEF);
} }
int currentEdge = 0; int currentEdge = 0;
@ -650,12 +650,12 @@ namespace DotRecast.Recast
{ {
if (edges[currentEdge * 4 + 2] == EV_UNDEF) if (edges[currentEdge * 4 + 2] == EV_UNDEF)
{ {
nfaces = completeFacet(ctx, pts, npts, edges, maxEdges, nfaces, currentEdge); nfaces = CompleteFacet(ctx, pts, npts, edges, maxEdges, nfaces, currentEdge);
} }
if (edges[currentEdge * 4 + 3] == EV_UNDEF) if (edges[currentEdge * 4 + 3] == EV_UNDEF)
{ {
nfaces = completeFacet(ctx, pts, npts, edges, maxEdges, nfaces, currentEdge); nfaces = CompleteFacet(ctx, pts, npts, edges, maxEdges, nfaces, currentEdge);
} }
currentEdge++; currentEdge++;
@ -716,7 +716,7 @@ namespace DotRecast.Recast
if (tris[t + 0] == -1 || tris[t + 1] == -1 || tris[t + 2] == -1) if (tris[t + 0] == -1 || tris[t + 1] == -1 || tris[t + 2] == -1)
{ {
Console.Error.WriteLine("Dangling! " + tris[t] + " " + tris[t + 1] + " " + tris[t + 2]); Console.Error.WriteLine("Dangling! " + tris[t] + " " + tris[t + 1] + " " + tris[t + 2]);
// ctx.log(RC_LOG_WARNING, "delaunayHull: Removing dangling face %d [%d,%d,%d].", i, t.x,t.y,t.z); // ctx.Log(RC_LOG_WARNING, "delaunayHull: Removing dangling face %d [%d,%d,%d].", i, t.x,t.y,t.z);
tris[t + 0] = tris[tris.Count - 4]; tris[t + 0] = tris[tris.Count - 4];
tris[t + 1] = tris[tris.Count - 3]; tris[t + 1] = tris[tris.Count - 3];
tris[t + 2] = tris[tris.Count - 2]; tris[t + 2] = tris[tris.Count - 2];
@ -731,7 +731,7 @@ namespace DotRecast.Recast
} }
// Calculate minimum extend of the polygon. // Calculate minimum extend of the polygon.
private static float polyMinExtent(float[] verts, int nverts) private static float PolyMinExtent(float[] verts, int nverts)
{ {
float minDist = float.MaxValue; float minDist = float.MaxValue;
for (int i = 0; i < nverts; i++) for (int i = 0; i < nverts; i++)
@ -747,7 +747,7 @@ namespace DotRecast.Recast
continue; continue;
} }
float d = distancePtSeg2d(verts, j * 3, verts, p1, p2); float d = DistancePtSeg2d(verts, j * 3, verts, p1, p2);
maxEdgeDist = Math.Max(maxEdgeDist, d); maxEdgeDist = Math.Max(maxEdgeDist, d);
} }
@ -757,7 +757,7 @@ namespace DotRecast.Recast
return (float)Math.Sqrt(minDist); return (float)Math.Sqrt(minDist);
} }
private static void triangulateHull(int nverts, float[] verts, int nhull, int[] hull, int nin, List<int> tris) private static void TriangulateHull(int nverts, float[] verts, int nhull, int[] hull, int nin, List<int> tris)
{ {
int start = 0, left = 1, right = nhull - 1; int start = 0, left = 1, right = nhull - 1;
@ -772,12 +772,12 @@ namespace DotRecast.Recast
} }
// segments on edges // segments on edges
int pi = RecastMesh.prev(i, nhull); int pi = RecastMesh.Prev(i, nhull);
int ni = RecastMesh.next(i, nhull); int ni = RecastMesh.Next(i, nhull);
int pv = hull[pi] * 3; int pv = hull[pi] * 3;
int cv = hull[i] * 3; int cv = hull[i] * 3;
int nv = hull[ni] * 3; int nv = hull[ni] * 3;
float d = vdist2(verts, pv, cv) + vdist2(verts, cv, nv) + vdist2(verts, nv, pv); float d = Vdist2(verts, pv, cv) + Vdist2(verts, cv, nv) + Vdist2(verts, nv, pv);
if (d < dmin) if (d < dmin)
{ {
start = i; start = i;
@ -797,18 +797,18 @@ namespace DotRecast.Recast
// depending on which triangle has shorter perimeter. // depending on which triangle has shorter perimeter.
// This heuristic was chose emprically, since it seems // This heuristic was chose emprically, since it seems
// handle tesselated straight edges well. // handle tesselated straight edges well.
while (RecastMesh.next(left, nhull) != right) while (RecastMesh.Next(left, nhull) != right)
{ {
// Check to see if se should advance left or right. // Check to see if se should advance left or right.
int nleft = RecastMesh.next(left, nhull); int nleft = RecastMesh.Next(left, nhull);
int nright = RecastMesh.prev(right, nhull); int nright = RecastMesh.Prev(right, nhull);
int cvleft = hull[left] * 3; int cvleft = hull[left] * 3;
int nvleft = hull[nleft] * 3; int nvleft = hull[nleft] * 3;
int cvright = hull[right] * 3; int cvright = hull[right] * 3;
int nvright = hull[nright] * 3; int nvright = hull[nright] * 3;
float dleft = vdist2(verts, cvleft, nvleft) + vdist2(verts, nvleft, cvright); float dleft = Vdist2(verts, cvleft, nvleft) + Vdist2(verts, nvleft, cvright);
float dright = vdist2(verts, cvright, nvright) + vdist2(verts, cvleft, nvright); float dright = Vdist2(verts, cvright, nvright) + Vdist2(verts, cvleft, nvright);
if (dleft < dright) if (dleft < dright)
{ {
@ -829,17 +829,17 @@ namespace DotRecast.Recast
} }
} }
private static float getJitterX(int i) private static float GetJitterX(int i)
{ {
return (((i * 0x8da6b343) & 0xffff) / 65535.0f * 2.0f) - 1.0f; return (((i * 0x8da6b343) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
} }
private static float getJitterY(int i) private static float GetJitterY(int i)
{ {
return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f; return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
} }
static int buildPolyDetail(Telemetry ctx, float[] @in, int nin, float sampleDist, float sampleMaxError, static int BuildPolyDetail(Telemetry ctx, float[] @in, int nin, float sampleDist, float sampleMaxError,
int heightSearchRadius, CompactHeightfield chf, HeightPatch hp, float[] verts, List<int> tris) int heightSearchRadius, CompactHeightfield chf, HeightPatch hp, float[] verts, List<int> tris)
{ {
List<int> samples = new List<int>(512); List<int> samples = new List<int>(512);
@ -853,7 +853,7 @@ namespace DotRecast.Recast
for (int i = 0; i < nin; ++i) for (int i = 0; i < nin; ++i)
{ {
RecastVectors.copy(verts, i * 3, @in, i * 3); RecastVectors.Copy(verts, i * 3, @in, i * 3);
} }
tris.Clear(); tris.Clear();
@ -862,7 +862,7 @@ namespace DotRecast.Recast
float ics = 1.0f / cs; float ics = 1.0f / cs;
// Calculate minimum extents of the polygon based on input data. // Calculate minimum extents of the polygon based on input data.
float minExtent = polyMinExtent(verts, nverts); float minExtent = PolyMinExtent(verts, nverts);
// Tessellate outlines. // Tessellate outlines.
// This is done in separate pass in order to ensure // This is done in separate pass in order to ensure
@ -920,7 +920,7 @@ namespace DotRecast.Recast
edge[pos + 0] = @in[vj + 0] + dx * u; edge[pos + 0] = @in[vj + 0] + dx * u;
edge[pos + 1] = @in[vj + 1] + dy * u; edge[pos + 1] = @in[vj + 1] + dy * u;
edge[pos + 2] = @in[vj + 2] + dz * u; edge[pos + 2] = @in[vj + 2] + dz * u;
edge[pos + 1] = getHeight(edge[pos + 0], edge[pos + 1], edge[pos + 2], cs, ics, chf.ch, edge[pos + 1] = GetHeight(edge[pos + 0], edge[pos + 1], edge[pos + 2], cs, ics, chf.ch,
heightSearchRadius, hp) * chf.ch; heightSearchRadius, hp) * chf.ch;
} }
@ -940,7 +940,7 @@ namespace DotRecast.Recast
int maxi = -1; int maxi = -1;
for (int m = a + 1; m < b; ++m) for (int m = a + 1; m < b; ++m)
{ {
float dev = distancePtSeg(edge, m * 3, va, vb); float dev = DistancePtSeg(edge, m * 3, va, vb);
if (dev > maxd) if (dev > maxd)
{ {
maxd = dev; maxd = dev;
@ -972,7 +972,7 @@ namespace DotRecast.Recast
{ {
for (int k = nidx - 2; k > 0; --k) for (int k = nidx - 2; k > 0; --k)
{ {
RecastVectors.copy(verts, nverts * 3, edge, idx[k] * 3); RecastVectors.Copy(verts, nverts * 3, edge, idx[k] * 3);
hull[nhull++] = nverts; hull[nhull++] = nverts;
nverts++; nverts++;
} }
@ -981,7 +981,7 @@ namespace DotRecast.Recast
{ {
for (int k = 1; k < nidx - 1; ++k) for (int k = 1; k < nidx - 1; ++k)
{ {
RecastVectors.copy(verts, nverts * 3, edge, idx[k] * 3); RecastVectors.Copy(verts, nverts * 3, edge, idx[k] * 3);
hull[nhull++] = nverts; hull[nhull++] = nverts;
nverts++; nverts++;
} }
@ -992,7 +992,7 @@ namespace DotRecast.Recast
// If the polygon minimum extent is small (sliver or small triangle), do not try to add internal points. // If the polygon minimum extent is small (sliver or small triangle), do not try to add internal points.
if (minExtent < sampleDist * 2) if (minExtent < sampleDist * 2)
{ {
triangulateHull(nverts, verts, nhull, hull, nin, tris); TriangulateHull(nverts, verts, nhull, hull, nin, tris);
return nverts; return nverts;
} }
@ -1000,7 +1000,7 @@ namespace DotRecast.Recast
// We're using the triangulateHull instead of delaunayHull as it tends to // We're using the triangulateHull instead of delaunayHull as it tends to
// create a bit better triangulation for long thin triangles when there // create a bit better triangulation for long thin triangles when there
// are no internal points. // are no internal points.
triangulateHull(nverts, verts, nhull, hull, nin, tris); TriangulateHull(nverts, verts, nhull, hull, nin, tris);
if (tris.Count == 0) if (tris.Count == 0)
{ {
@ -1013,12 +1013,12 @@ namespace DotRecast.Recast
// Create sample locations in a grid. // Create sample locations in a grid.
Vector3f bmin = new Vector3f(); Vector3f bmin = new Vector3f();
Vector3f bmax = new Vector3f(); Vector3f bmax = new Vector3f();
RecastVectors.copy(ref bmin, @in, 0); RecastVectors.Copy(ref bmin, @in, 0);
RecastVectors.copy(ref bmax, @in, 0); RecastVectors.Copy(ref bmax, @in, 0);
for (int i = 1; i < nin; ++i) for (int i = 1; i < nin; ++i)
{ {
RecastVectors.min(ref bmin, @in, i * 3); RecastVectors.Min(ref bmin, @in, i * 3);
RecastVectors.max(ref bmax, @in, i * 3); RecastVectors.Max(ref bmax, @in, i * 3);
} }
int x0 = (int)Math.Floor(bmin.x / sampleDist); int x0 = (int)Math.Floor(bmin.x / sampleDist);
@ -1035,13 +1035,13 @@ namespace DotRecast.Recast
pt.y = (bmax.y + bmin.y) * 0.5f; pt.y = (bmax.y + bmin.y) * 0.5f;
pt.z = z * sampleDist; pt.z = z * sampleDist;
// Make sure the samples are not too close to the edges. // Make sure the samples are not too close to the edges.
if (distToPoly(nin, @in, pt) > -sampleDist / 2) if (DistToPoly(nin, @in, pt) > -sampleDist / 2)
{ {
continue; continue;
} }
samples.Add(x); samples.Add(x);
samples.Add(getHeight(pt.x, pt.y, pt.z, cs, ics, chf.ch, heightSearchRadius, hp)); samples.Add(GetHeight(pt.x, pt.y, pt.z, cs, ics, chf.ch, heightSearchRadius, hp));
samples.Add(z); samples.Add(z);
samples.Add(0); // Not added samples.Add(0); // Not added
} }
@ -1073,10 +1073,10 @@ namespace DotRecast.Recast
Vector3f pt = new Vector3f(); Vector3f pt = new Vector3f();
// The sample location is jittered to get rid of some bad triangulations // The sample location is jittered to get rid of some bad triangulations
// which are cause by symmetrical data from the grid structure. // which are cause by symmetrical data from the grid structure.
pt.x = samples[s + 0] * sampleDist + getJitterX(i) * cs * 0.1f; pt.x = samples[s + 0] * sampleDist + GetJitterX(i) * cs * 0.1f;
pt.y = samples[s + 1] * chf.ch; pt.y = samples[s + 1] * chf.ch;
pt.z = samples[s + 2] * sampleDist + getJitterY(i) * cs * 0.1f; pt.z = samples[s + 2] * sampleDist + GetJitterY(i) * cs * 0.1f;
float d = distToTriMesh(pt, verts, nverts, tris, tris.Count / 4); float d = DistToTriMesh(pt, verts, nverts, tris, tris.Count / 4);
if (d < 0) if (d < 0)
{ {
continue; // did not hit the mesh. continue; // did not hit the mesh.
@ -1099,12 +1099,12 @@ namespace DotRecast.Recast
// Mark sample as added. // Mark sample as added.
samples[besti * 4 + 3] = 1; samples[besti * 4 + 3] = 1;
// Add the new sample point. // Add the new sample point.
RecastVectors.copy(verts, nverts * 3, bestpt, 0); RecastVectors.Copy(verts, nverts * 3, bestpt, 0);
nverts++; nverts++;
// Create new triangulation. // Create new triangulation.
// TODO: Incremental add instead of full rebuild. // TODO: Incremental add instead of full rebuild.
delaunayHull(ctx, nverts, verts, nhull, hull, tris); DelaunayHull(ctx, nverts, verts, nhull, hull, tris);
} }
} }
@ -1121,7 +1121,7 @@ namespace DotRecast.Recast
return nverts; return nverts;
} }
static void seedArrayWithPolyCenter(Telemetry ctx, CompactHeightfield chf, int[] meshpoly, int poly, int npoly, static void SeedArrayWithPolyCenter(Telemetry ctx, CompactHeightfield chf, int[] meshpoly, int poly, int npoly,
int[] verts, int bs, HeightPatch hp, List<int> array) int[] verts, int bs, HeightPatch hp, List<int> array)
{ {
// Note: Reads to the compact heightfield are offset by border size (bs) // Note: Reads to the compact heightfield are offset by border size (bs)
@ -1186,7 +1186,7 @@ namespace DotRecast.Recast
{ {
if (array.Count < 3) if (array.Count < 3)
{ {
ctx.warn("Walk towards polygon center failed to reach center"); ctx.Warn("Walk towards polygon center failed to reach center");
break; break;
} }
@ -1211,11 +1211,11 @@ namespace DotRecast.Recast
int directDir; int directDir;
if (cx == pcx) if (cx == pcx)
{ {
directDir = rcGetDirForOffset(0, pcy > cy ? 1 : -1); directDir = RcGetDirForOffset(0, pcy > cy ? 1 : -1);
} }
else else
{ {
directDir = rcGetDirForOffset(pcx > cx ? 1 : -1, 0); directDir = RcGetDirForOffset(pcx > cx ? 1 : -1, 0);
} }
// Push the direct dir last so we start with this on next iteration // Push the direct dir last so we start with this on next iteration
@ -1272,14 +1272,14 @@ namespace DotRecast.Recast
const int RETRACT_SIZE = 256; const int RETRACT_SIZE = 256;
static void push3(List<int> queue, int v1, int v2, int v3) static void Push3(List<int> queue, int v1, int v2, int v3)
{ {
queue.Add(v1); queue.Add(v1);
queue.Add(v2); queue.Add(v2);
queue.Add(v3); queue.Add(v3);
} }
static void getHeightData(Telemetry ctx, CompactHeightfield chf, int[] meshpolys, int poly, int npoly, int[] verts, static void GetHeightData(Telemetry ctx, CompactHeightfield chf, int[] meshpolys, int poly, int npoly, int[] verts,
int bs, HeightPatch hp, int region) int bs, HeightPatch hp, int region)
{ {
// Note: Reads to the compact heightfield are offset by border size (bs) // Note: Reads to the compact heightfield are offset by border size (bs)
@ -1333,7 +1333,7 @@ namespace DotRecast.Recast
if (border) if (border)
{ {
push3(queue, x, y, i); Push3(queue, x, y, i);
} }
break; break;
@ -1348,7 +1348,7 @@ namespace DotRecast.Recast
// then use the center as the seed point. // then use the center as the seed point.
if (empty) if (empty)
{ {
seedArrayWithPolyCenter(ctx, chf, meshpolys, poly, npoly, verts, bs, hp, queue); SeedArrayWithPolyCenter(ctx, chf, meshpolys, poly, npoly, verts, bs, hp, queue);
} }
int head = 0; int head = 0;
@ -1395,20 +1395,20 @@ namespace DotRecast.Recast
CompactSpan @as = chf.spans[ai]; CompactSpan @as = chf.spans[ai];
hp.data[hx + hy * hp.width] = @as.y; hp.data[hx + hy * hp.width] = @as.y;
push3(queue, ax, ay, ai); Push3(queue, ax, ay, ai);
} }
} }
} }
static int getEdgeFlags(float[] verts, int va, int vb, float[] vpoly, int npoly) static int GetEdgeFlags(float[] verts, int va, int vb, float[] vpoly, int npoly)
{ {
// The flag returned by this function matches getDetailTriEdgeFlags in Detour. // The flag returned by this function matches getDetailTriEdgeFlags in Detour.
// Figure out if edge (va,vb) is part of the polygon boundary. // Figure out if edge (va,vb) is part of the polygon boundary.
float thrSqr = 0.001f * 0.001f; float thrSqr = 0.001f * 0.001f;
for (int i = 0, j = npoly - 1; i < npoly; j = i++) for (int i = 0, j = npoly - 1; i < npoly; j = i++)
{ {
if (distancePtSeg2d(verts, va, vpoly, j * 3, i * 3) < thrSqr if (DistancePtSeg2d(verts, va, vpoly, j * 3, i * 3) < thrSqr
&& distancePtSeg2d(verts, vb, vpoly, j * 3, i * 3) < thrSqr) && DistancePtSeg2d(verts, vb, vpoly, j * 3, i * 3) < thrSqr)
{ {
return 1; return 1;
} }
@ -1417,12 +1417,12 @@ namespace DotRecast.Recast
return 0; return 0;
} }
static int getTriFlags(float[] verts, int va, int vb, int vc, float[] vpoly, int npoly) static int GetTriFlags(float[] verts, int va, int vb, int vc, float[] vpoly, int npoly)
{ {
int flags = 0; int flags = 0;
flags |= getEdgeFlags(verts, va, vb, vpoly, npoly) << 0; flags |= GetEdgeFlags(verts, va, vb, vpoly, npoly) << 0;
flags |= getEdgeFlags(verts, vb, vc, vpoly, npoly) << 2; flags |= GetEdgeFlags(verts, vb, vc, vpoly, npoly) << 2;
flags |= getEdgeFlags(verts, vc, va, vpoly, npoly) << 4; flags |= GetEdgeFlags(verts, vc, va, vpoly, npoly) << 4;
return flags; return flags;
} }
@ -1431,10 +1431,10 @@ namespace DotRecast.Recast
/// See the #rcConfig documentation for more information on the configuration parameters. /// See the #rcConfig documentation for more information on the configuration parameters.
/// ///
/// @see rcAllocPolyMeshDetail, rcPolyMesh, rcCompactHeightfield, rcPolyMeshDetail, rcConfig /// @see rcAllocPolyMeshDetail, rcPolyMesh, rcCompactHeightfield, rcPolyMeshDetail, rcConfig
public static PolyMeshDetail buildPolyMeshDetail(Telemetry ctx, PolyMesh mesh, CompactHeightfield chf, public static PolyMeshDetail BuildPolyMeshDetail(Telemetry ctx, PolyMesh mesh, CompactHeightfield chf,
float sampleDist, float sampleMaxError) float sampleDist, float sampleMaxError)
{ {
ctx.startTimer("POLYMESHDETAIL"); ctx.StartTimer("POLYMESHDETAIL");
if (mesh.nverts == 0 || mesh.npolys == 0) if (mesh.nverts == 0 || mesh.npolys == 0)
{ {
return null; return null;
@ -1533,10 +1533,10 @@ namespace DotRecast.Recast
hp.ymin = bounds[i * 4 + 2]; hp.ymin = bounds[i * 4 + 2];
hp.width = bounds[i * 4 + 1] - bounds[i * 4 + 0]; hp.width = bounds[i * 4 + 1] - bounds[i * 4 + 0];
hp.height = bounds[i * 4 + 3] - bounds[i * 4 + 2]; hp.height = bounds[i * 4 + 3] - bounds[i * 4 + 2];
getHeightData(ctx, chf, mesh.polys, p, npoly, mesh.verts, borderSize, hp, mesh.regs[i]); GetHeightData(ctx, chf, mesh.polys, p, npoly, mesh.verts, borderSize, hp, mesh.regs[i]);
// Build detail mesh. // Build detail mesh.
int nverts = buildPolyDetail(ctx, poly, npoly, sampleDist, sampleMaxError, heightSearchRadius, chf, hp, int nverts = BuildPolyDetail(ctx, poly, npoly, sampleDist, sampleMaxError, heightSearchRadius, chf, hp,
verts, tris); verts, tris);
// Move detail verts to world space. // Move detail verts to world space.
@ -1612,22 +1612,22 @@ namespace DotRecast.Recast
dmesh.tris[dmesh.ntris * 4 + 0] = tris[t + 0]; dmesh.tris[dmesh.ntris * 4 + 0] = tris[t + 0];
dmesh.tris[dmesh.ntris * 4 + 1] = tris[t + 1]; dmesh.tris[dmesh.ntris * 4 + 1] = tris[t + 1];
dmesh.tris[dmesh.ntris * 4 + 2] = tris[t + 2]; dmesh.tris[dmesh.ntris * 4 + 2] = tris[t + 2];
dmesh.tris[dmesh.ntris * 4 + 3] = getTriFlags(verts, tris[t + 0] * 3, tris[t + 1] * 3, dmesh.tris[dmesh.ntris * 4 + 3] = GetTriFlags(verts, tris[t + 0] * 3, tris[t + 1] * 3,
tris[t + 2] * 3, poly, npoly); tris[t + 2] * 3, poly, npoly);
dmesh.ntris++; dmesh.ntris++;
} }
} }
ctx.stopTimer("POLYMESHDETAIL"); ctx.StopTimer("POLYMESHDETAIL");
return dmesh; return dmesh;
} }
/// @see rcAllocPolyMeshDetail, rcPolyMeshDetail /// @see rcAllocPolyMeshDetail, rcPolyMeshDetail
PolyMeshDetail mergePolyMeshDetails(Telemetry ctx, PolyMeshDetail[] meshes, int nmeshes) PolyMeshDetail MergePolyMeshDetails(Telemetry ctx, PolyMeshDetail[] meshes, int nmeshes)
{ {
PolyMeshDetail mesh = new PolyMeshDetail(); PolyMeshDetail mesh = new PolyMeshDetail();
ctx.startTimer("MERGE_POLYMESHDETAIL"); ctx.StartTimer("MERGE_POLYMESHDETAIL");
int maxVerts = 0; int maxVerts = 0;
int maxTris = 0; int maxTris = 0;
@ -1674,7 +1674,7 @@ namespace DotRecast.Recast
for (int k = 0; k < dm.nverts; ++k) for (int k = 0; k < dm.nverts; ++k)
{ {
RecastVectors.copy(mesh.verts, mesh.nverts * 3, dm.verts, k * 3); RecastVectors.Copy(mesh.verts, mesh.nverts * 3, dm.verts, k * 3);
mesh.nverts++; mesh.nverts++;
} }
@ -1688,7 +1688,7 @@ namespace DotRecast.Recast
} }
} }
ctx.stopTimer("MERGE_POLYMESHDETAIL"); ctx.StopTimer("MERGE_POLYMESHDETAIL");
return mesh; return mesh;
} }
} }

View File

@ -41,7 +41,7 @@ namespace DotRecast.Recast
* Max axis extents of bounding box B * Max axis extents of bounding box B
* @returns true if the two bounding boxes overlap. False otherwise * @returns true if the two bounding boxes overlap. False otherwise
*/ */
private static bool overlapBounds(float[] amin, float[] amax, float[] bmin, float[] bmax) private static bool OverlapBounds(float[] amin, float[] amax, float[] bmin, float[] bmax)
{ {
bool overlap = true; bool overlap = true;
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap; overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
@ -50,7 +50,7 @@ namespace DotRecast.Recast
return overlap; return overlap;
} }
private static bool overlapBounds(Vector3f amin, Vector3f amax, Vector3f bmin, Vector3f bmax) private static bool OverlapBounds(Vector3f amin, Vector3f amax, Vector3f bmin, Vector3f bmax)
{ {
bool overlap = true; bool overlap = true;
overlap = (amin.x > bmax.x || amax.x < bmin.x) ? false : overlap; overlap = (amin.x > bmax.x || amax.x < bmin.x) ? false : overlap;
@ -81,7 +81,7 @@ namespace DotRecast.Recast
* The merge theshold. [Limit: >= 0] [Units: vx] * The merge theshold. [Limit: >= 0] [Units: vx]
* @see Heightfield, Span. * @see Heightfield, Span.
*/ */
public static void addSpan(Heightfield heightfield, int x, int y, int spanMin, int spanMax, int areaId, public static void AddSpan(Heightfield heightfield, int x, int y, int spanMin, int spanMax, int areaId,
int flagMergeThreshold) int flagMergeThreshold)
{ {
int idx = x + y * heightfield.width; int idx = x + y * heightfield.width;
@ -170,7 +170,7 @@ namespace DotRecast.Recast
* The separating axis * The separating axis
* @return The number of resulting polygon 1 and polygon 2 vertices * @return The number of resulting polygon 1 and polygon 2 vertices
*/ */
private static int[] dividePoly(float[] inVerts, int inVertsOffset, int inVertsCount, int outVerts1, int outVerts2, float axisOffset, private static int[] DividePoly(float[] inVerts, int inVertsOffset, int inVertsCount, int outVerts1, int outVerts2, float axisOffset,
int axis) int axis)
{ {
float[] d = new float[12]; float[] d = new float[12];
@ -191,19 +191,19 @@ namespace DotRecast.Recast
+ (inVerts[inVertsOffset + i * 3 + 1] - inVerts[inVertsOffset + j * 3 + 1]) * s; + (inVerts[inVertsOffset + i * 3 + 1] - inVerts[inVertsOffset + j * 3 + 1]) * s;
inVerts[outVerts1 + m * 3 + 2] = inVerts[inVertsOffset + j * 3 + 2] inVerts[outVerts1 + m * 3 + 2] = inVerts[inVertsOffset + j * 3 + 2]
+ (inVerts[inVertsOffset + i * 3 + 2] - inVerts[inVertsOffset + j * 3 + 2]) * s; + (inVerts[inVertsOffset + i * 3 + 2] - inVerts[inVertsOffset + j * 3 + 2]) * s;
RecastVectors.copy(inVerts, outVerts2 + n * 3, inVerts, outVerts1 + m * 3); RecastVectors.Copy(inVerts, outVerts2 + n * 3, inVerts, outVerts1 + m * 3);
m++; m++;
n++; n++;
// add the i'th point to the right polygon. Do NOT add points that are on the dividing line // add the i'th point to the right polygon. Do NOT add points that are on the dividing line
// since these were already added above // since these were already added above
if (d[i] > 0) if (d[i] > 0)
{ {
RecastVectors.copy(inVerts, outVerts1 + m * 3, inVerts, inVertsOffset + i * 3); RecastVectors.Copy(inVerts, outVerts1 + m * 3, inVerts, inVertsOffset + i * 3);
m++; m++;
} }
else if (d[i] < 0) else if (d[i] < 0)
{ {
RecastVectors.copy(inVerts, outVerts2 + n * 3, inVerts, inVertsOffset + i * 3); RecastVectors.Copy(inVerts, outVerts2 + n * 3, inVerts, inVertsOffset + i * 3);
n++; n++;
} }
} }
@ -212,13 +212,13 @@ namespace DotRecast.Recast
// add the i'th point to the right polygon. Addition is done even for points on the dividing line // add the i'th point to the right polygon. Addition is done even for points on the dividing line
if (d[i] >= 0) if (d[i] >= 0)
{ {
RecastVectors.copy(inVerts, outVerts1 + m * 3, inVerts, inVertsOffset + i * 3); RecastVectors.Copy(inVerts, outVerts1 + m * 3, inVerts, inVertsOffset + i * 3);
m++; m++;
if (d[i] != 0) if (d[i] != 0)
continue; continue;
} }
RecastVectors.copy(inVerts, outVerts2 + n * 3, inVerts, inVertsOffset + i * 3); RecastVectors.Copy(inVerts, outVerts2 + n * 3, inVerts, inVertsOffset + i * 3);
n++; n++;
} }
} }
@ -255,7 +255,7 @@ namespace DotRecast.Recast
* @param flagMergeThreshold * @param flagMergeThreshold
* The threshold in which area flags will be merged * The threshold in which area flags will be merged
*/ */
private static void rasterizeTri(float[] verts, int v0, int v1, int v2, int area, Heightfield hf, Vector3f hfBBMin, private static void RasterizeTri(float[] verts, int v0, int v1, int v2, int area, Heightfield hf, Vector3f hfBBMin,
Vector3f hfBBMax, float cellSize, float inverseCellSize, float inverseCellHeight, int flagMergeThreshold) Vector3f hfBBMax, float cellSize, float inverseCellSize, float inverseCellHeight, int flagMergeThreshold)
{ {
Vector3f tmin = new Vector3f(); Vector3f tmin = new Vector3f();
@ -263,15 +263,15 @@ namespace DotRecast.Recast
float by = hfBBMax.y - hfBBMin.y; float by = hfBBMax.y - hfBBMin.y;
// Calculate the bounding box of the triangle. // Calculate the bounding box of the triangle.
RecastVectors.copy(ref tmin, verts, v0 * 3); RecastVectors.Copy(ref tmin, verts, v0 * 3);
RecastVectors.copy(ref tmax, verts, v0 * 3); RecastVectors.Copy(ref tmax, verts, v0 * 3);
RecastVectors.min(ref tmin, verts, v1 * 3); RecastVectors.Min(ref tmin, verts, v1 * 3);
RecastVectors.min(ref tmin, verts, v2 * 3); RecastVectors.Min(ref tmin, verts, v2 * 3);
RecastVectors.max(ref tmax, verts, v1 * 3); RecastVectors.Max(ref tmax, verts, v1 * 3);
RecastVectors.max(ref tmax, verts, v2 * 3); RecastVectors.Max(ref tmax, verts, v2 * 3);
// If the triangle does not touch the bbox of the heightfield, skip the triagle. // If the triangle does not touch the bbox of the heightfield, skip the triagle.
if (!overlapBounds(hfBBMin, hfBBMax, tmin, tmax)) if (!OverlapBounds(hfBBMin, hfBBMax, tmin, tmax))
return; return;
// Calculate the footprint of the triangle on the grid's y-axis // Calculate the footprint of the triangle on the grid's y-axis
@ -281,8 +281,8 @@ namespace DotRecast.Recast
int w = hf.width; int w = hf.width;
int h = hf.height; int h = hf.height;
// use -1 rather than 0 to cut the polygon properly at the start of the tile // use -1 rather than 0 to cut the polygon properly at the start of the tile
z0 = clamp(z0, -1, h - 1); z0 = Clamp(z0, -1, h - 1);
z1 = clamp(z1, 0, h - 1); z1 = Clamp(z1, 0, h - 1);
// Clip the triangle into all grid cells it touches. // Clip the triangle into all grid cells it touches.
float[] buf = new float[7 * 3 * 4]; float[] buf = new float[7 * 3 * 4];
@ -291,16 +291,16 @@ namespace DotRecast.Recast
int p1 = inRow + 7 * 3; int p1 = inRow + 7 * 3;
int p2 = p1 + 7 * 3; int p2 = p1 + 7 * 3;
RecastVectors.copy(buf, 0, verts, v0 * 3); RecastVectors.Copy(buf, 0, verts, v0 * 3);
RecastVectors.copy(buf, 3, verts, v1 * 3); RecastVectors.Copy(buf, 3, verts, v1 * 3);
RecastVectors.copy(buf, 6, verts, v2 * 3); RecastVectors.Copy(buf, 6, verts, v2 * 3);
int nvRow, nvIn = 3; int nvRow, nvIn = 3;
for (int z = z0; z <= z1; ++z) for (int z = z0; z <= z1; ++z)
{ {
// Clip polygon to row. Store the remaining polygon as well // Clip polygon to row. Store the remaining polygon as well
float cellZ = hfBBMin.z + z * cellSize; float cellZ = hfBBMin.z + z * cellSize;
int[] nvrowin = dividePoly(buf, @in, nvIn, inRow, p1, cellZ + cellSize, 2); int[] nvrowin = DividePoly(buf, @in, nvIn, inRow, p1, cellZ + cellSize, 2);
nvRow = nvrowin[0]; nvRow = nvrowin[0];
nvIn = nvrowin[1]; nvIn = nvrowin[1];
{ {
@ -332,15 +332,15 @@ namespace DotRecast.Recast
continue; continue;
} }
x0 = clamp(x0, -1, w - 1); x0 = Clamp(x0, -1, w - 1);
x1 = clamp(x1, 0, w - 1); x1 = Clamp(x1, 0, w - 1);
int nv, nv2 = nvRow; int nv, nv2 = nvRow;
for (int x = x0; x <= x1; ++x) for (int x = x0; x <= x1; ++x)
{ {
// Clip polygon to column. store the remaining polygon as well // Clip polygon to column. store the remaining polygon as well
float cx = hfBBMin.x + x * cellSize; float cx = hfBBMin.x + x * cellSize;
int[] nvnv2 = dividePoly(buf, inRow, nv2, p1, p2, cx + cellSize, 0); int[] nvnv2 = DividePoly(buf, inRow, nv2, p1, p2, cx + cellSize, 0);
nv = nvnv2[0]; nv = nvnv2[0];
nv2 = nvnv2[1]; nv2 = nvnv2[1];
{ {
@ -378,10 +378,10 @@ namespace DotRecast.Recast
spanMax = by; spanMax = by;
// Snap the span to the heightfield height grid. // Snap the span to the heightfield height grid.
int spanMinCellIndex = clamp((int)Math.Floor(spanMin * inverseCellHeight), 0, SPAN_MAX_HEIGHT); int spanMinCellIndex = Clamp((int)Math.Floor(spanMin * inverseCellHeight), 0, SPAN_MAX_HEIGHT);
int spanMaxCellIndex = clamp((int)Math.Ceiling(spanMax * inverseCellHeight), spanMinCellIndex + 1, SPAN_MAX_HEIGHT); int spanMaxCellIndex = Clamp((int)Math.Ceiling(spanMax * inverseCellHeight), spanMinCellIndex + 1, SPAN_MAX_HEIGHT);
addSpan(hf, x, z, spanMinCellIndex, spanMaxCellIndex, area, flagMergeThreshold); AddSpan(hf, x, z, spanMinCellIndex, spanMaxCellIndex, area, flagMergeThreshold);
} }
} }
} }
@ -407,17 +407,17 @@ namespace DotRecast.Recast
* The distance where the walkable flag is favored over the non-walkable flag. [Limit: >= 0] [Units: vx] * The distance where the walkable flag is favored over the non-walkable flag. [Limit: >= 0] [Units: vx]
* @see Heightfield * @see Heightfield
*/ */
public static void rasterizeTriangle(Heightfield heightfield, float[] verts, int v0, int v1, int v2, int area, public static void RasterizeTriangle(Heightfield heightfield, float[] verts, int v0, int v1, int v2, int area,
int flagMergeThreshold, Telemetry ctx) int flagMergeThreshold, Telemetry ctx)
{ {
ctx.startTimer("RASTERIZE_TRIANGLES"); ctx.StartTimer("RASTERIZE_TRIANGLES");
float inverseCellSize = 1.0f / heightfield.cs; float inverseCellSize = 1.0f / heightfield.cs;
float inverseCellHeight = 1.0f / heightfield.ch; float inverseCellHeight = 1.0f / heightfield.ch;
rasterizeTri(verts, v0, v1, v2, area, heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize, RasterizeTri(verts, v0, v1, v2, area, heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize,
inverseCellHeight, flagMergeThreshold); inverseCellHeight, flagMergeThreshold);
ctx.stopTimer("RASTERIZE_TRIANGLES"); ctx.StopTimer("RASTERIZE_TRIANGLES");
} }
/** /**
@ -438,10 +438,10 @@ namespace DotRecast.Recast
* The distance where the walkable flag is favored over the non-walkable flag. [Limit: >= 0] [Units: vx] * The distance where the walkable flag is favored over the non-walkable flag. [Limit: >= 0] [Units: vx]
* @see Heightfield * @see Heightfield
*/ */
public static void rasterizeTriangles(Heightfield heightfield, float[] verts, int[] tris, int[] areaIds, int numTris, public static void RasterizeTriangles(Heightfield heightfield, float[] verts, int[] tris, int[] areaIds, int numTris,
int flagMergeThreshold, Telemetry ctx) int flagMergeThreshold, Telemetry ctx)
{ {
ctx.startTimer("RASTERIZE_TRIANGLES"); ctx.StartTimer("RASTERIZE_TRIANGLES");
float inverseCellSize = 1.0f / heightfield.cs; float inverseCellSize = 1.0f / heightfield.cs;
float inverseCellHeight = 1.0f / heightfield.ch; float inverseCellHeight = 1.0f / heightfield.ch;
@ -450,11 +450,11 @@ namespace DotRecast.Recast
int v0 = tris[triIndex * 3 + 0]; int v0 = tris[triIndex * 3 + 0];
int v1 = tris[triIndex * 3 + 1]; int v1 = tris[triIndex * 3 + 1];
int v2 = tris[triIndex * 3 + 2]; int v2 = tris[triIndex * 3 + 2];
rasterizeTri(verts, v0, v1, v2, areaIds[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, RasterizeTri(verts, v0, v1, v2, areaIds[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs,
inverseCellSize, inverseCellHeight, flagMergeThreshold); inverseCellSize, inverseCellHeight, flagMergeThreshold);
} }
ctx.stopTimer("RASTERIZE_TRIANGLES"); ctx.StopTimer("RASTERIZE_TRIANGLES");
} }
/** /**
@ -475,10 +475,10 @@ namespace DotRecast.Recast
* The distance where the walkable flag is favored over the non-walkable flag. [Limit: >= 0] [Units: vx] * The distance where the walkable flag is favored over the non-walkable flag. [Limit: >= 0] [Units: vx]
* @see Heightfield * @see Heightfield
*/ */
public static void rasterizeTriangles(Heightfield heightfield, float[] verts, int[] areaIds, int numTris, public static void RasterizeTriangles(Heightfield heightfield, float[] verts, int[] areaIds, int numTris,
int flagMergeThreshold, Telemetry ctx) int flagMergeThreshold, Telemetry ctx)
{ {
ctx.startTimer("RASTERIZE_TRIANGLES"); ctx.StartTimer("RASTERIZE_TRIANGLES");
float inverseCellSize = 1.0f / heightfield.cs; float inverseCellSize = 1.0f / heightfield.cs;
float inverseCellHeight = 1.0f / heightfield.ch; float inverseCellHeight = 1.0f / heightfield.ch;
@ -487,11 +487,11 @@ namespace DotRecast.Recast
int v0 = (triIndex * 3 + 0); int v0 = (triIndex * 3 + 0);
int v1 = (triIndex * 3 + 1); int v1 = (triIndex * 3 + 1);
int v2 = (triIndex * 3 + 2); int v2 = (triIndex * 3 + 2);
rasterizeTri(verts, v0, v1, v2, areaIds[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, RasterizeTri(verts, v0, v1, v2, areaIds[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs,
inverseCellSize, inverseCellHeight, flagMergeThreshold); inverseCellSize, inverseCellHeight, flagMergeThreshold);
} }
ctx.stopTimer("RASTERIZE_TRIANGLES"); ctx.StopTimer("RASTERIZE_TRIANGLES");
} }
} }
} }

View File

@ -38,7 +38,7 @@ namespace DotRecast.Recast
public int nei; // neighbour id public int nei; // neighbour id
} }
public static int calculateDistanceField(CompactHeightfield chf, int[] src) public static int CalculateDistanceField(CompactHeightfield chf, int[] src)
{ {
int maxDist; int maxDist;
int w = chf.width; int w = chf.width;
@ -219,7 +219,7 @@ namespace DotRecast.Recast
return maxDist; return maxDist;
} }
private static int[] boxBlur(CompactHeightfield chf, int thr, int[] src) private static int[] BoxBlur(CompactHeightfield chf, int thr, int[] src)
{ {
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
@ -280,7 +280,7 @@ namespace DotRecast.Recast
return dst; return dst;
} }
private static bool floodRegion(int x, int y, int i, int level, int r, CompactHeightfield chf, int[] srcReg, private static bool FloodRegion(int x, int y, int i, int level, int r, CompactHeightfield chf, int[] srcReg,
int[] srcDist, List<int> stack) int[] srcDist, List<int> stack)
{ {
int w = chf.width; int w = chf.width;
@ -398,7 +398,7 @@ namespace DotRecast.Recast
return count > 0; return count > 0;
} }
private static int[] expandRegions(int maxIter, int level, CompactHeightfield chf, int[] srcReg, int[] srcDist, private static int[] ExpandRegions(int maxIter, int level, CompactHeightfield chf, int[] srcReg, int[] srcDist,
List<int> stack, bool fillStack) List<int> stack, bool fillStack)
{ {
int w = chf.width; int w = chf.width;
@ -524,7 +524,7 @@ namespace DotRecast.Recast
return srcReg; return srcReg;
} }
private static void sortCellsByLevel(int startLevel, CompactHeightfield chf, int[] srcReg, int nbStacks, private static void SortCellsByLevel(int startLevel, CompactHeightfield chf, int[] srcReg, int nbStacks,
List<List<int>> stacks, int loglevelsPerStack) // the levels per stack (2 in our case) as a bit shift List<List<int>> stacks, int loglevelsPerStack) // the levels per stack (2 in our case) as a bit shift
{ {
int w = chf.width; int w = chf.width;
@ -569,7 +569,7 @@ namespace DotRecast.Recast
} }
} }
private static void appendStacks(List<int> srcStack, List<int> dstStack, int[] srcReg) private static void AppendStacks(List<int> srcStack, List<int> dstStack, int[] srcReg)
{ {
for (int j = 0; j < srcStack.Count; j += 3) for (int j = 0; j < srcStack.Count; j += 3)
{ {
@ -607,7 +607,7 @@ namespace DotRecast.Recast
} }
} }
private static void removeAdjacentNeighbours(Region reg) private static void RemoveAdjacentNeighbours(Region reg)
{ {
// Remove adjacent duplicates. // Remove adjacent duplicates.
for (int i = 0; i < reg.connections.Count && reg.connections.Count > 1;) for (int i = 0; i < reg.connections.Count && reg.connections.Count > 1;)
@ -624,7 +624,7 @@ namespace DotRecast.Recast
} }
} }
private static void replaceNeighbour(Region reg, int oldId, int newId) private static void ReplaceNeighbour(Region reg, int oldId, int newId)
{ {
bool neiChanged = false; bool neiChanged = false;
for (int i = 0; i < reg.connections.Count; ++i) for (int i = 0; i < reg.connections.Count; ++i)
@ -646,11 +646,11 @@ namespace DotRecast.Recast
if (neiChanged) if (neiChanged)
{ {
removeAdjacentNeighbours(reg); RemoveAdjacentNeighbours(reg);
} }
} }
private static bool canMergeWithRegion(Region rega, Region regb) private static bool CanMergeWithRegion(Region rega, Region regb)
{ {
if (rega.areaType != regb.areaType) if (rega.areaType != regb.areaType)
{ {
@ -682,7 +682,7 @@ namespace DotRecast.Recast
return true; return true;
} }
private static void addUniqueFloorRegion(Region reg, int n) private static void AddUniqueFloorRegion(Region reg, int n)
{ {
if (!reg.floors.Contains(n)) if (!reg.floors.Contains(n))
{ {
@ -690,7 +690,7 @@ namespace DotRecast.Recast
} }
} }
private static bool mergeRegions(Region rega, Region regb) private static bool MergeRegions(Region rega, Region regb)
{ {
int aid = rega.id; int aid = rega.id;
int bid = regb.id; int bid = regb.id;
@ -743,11 +743,11 @@ namespace DotRecast.Recast
rega.connections.Add(bcon[(insb + 1 + i) % ni]); rega.connections.Add(bcon[(insb + 1 + i) % ni]);
} }
removeAdjacentNeighbours(rega); RemoveAdjacentNeighbours(rega);
for (int j = 0; j < regb.floors.Count; ++j) for (int j = 0; j < regb.floors.Count; ++j)
{ {
addUniqueFloorRegion(rega, regb.floors[j]); AddUniqueFloorRegion(rega, regb.floors[j]);
} }
rega.spanCount += regb.spanCount; rega.spanCount += regb.spanCount;
@ -757,14 +757,14 @@ namespace DotRecast.Recast
return true; return true;
} }
private static bool isRegionConnectedToBorder(Region reg) private static bool IsRegionConnectedToBorder(Region reg)
{ {
// Region is connected to border if // Region is connected to border if
// one of the neighbours is null id. // one of the neighbours is null id.
return reg.connections.Contains(0); return reg.connections.Contains(0);
} }
private static bool isSolidEdge(CompactHeightfield chf, int[] srcReg, int x, int y, int i, int dir) private static bool IsSolidEdge(CompactHeightfield chf, int[] srcReg, int x, int y, int i, int dir)
{ {
CompactSpan s = chf.spans[i]; CompactSpan s = chf.spans[i];
int r = 0; int r = 0;
@ -784,7 +784,7 @@ namespace DotRecast.Recast
return true; return true;
} }
private static void walkContour(int x, int y, int i, int dir, CompactHeightfield chf, int[] srcReg, private static void WalkContour(int x, int y, int i, int dir, CompactHeightfield chf, int[] srcReg,
List<int> cont) List<int> cont)
{ {
int startDir = dir; int startDir = dir;
@ -807,7 +807,7 @@ namespace DotRecast.Recast
{ {
CompactSpan s = chf.spans[i]; CompactSpan s = chf.spans[i];
if (isSolidEdge(chf, srcReg, x, y, i, dir)) if (IsSolidEdge(chf, srcReg, x, y, i, dir))
{ {
// Choose the edge corner // Choose the edge corner
int r = 0; int r = 0;
@ -874,7 +874,7 @@ namespace DotRecast.Recast
} }
} }
private static int mergeAndFilterRegions(Telemetry ctx, int minRegionArea, int mergeRegionSize, int maxRegionId, private static int MergeAndFilterRegions(Telemetry ctx, int minRegionArea, int mergeRegionSize, int maxRegionId,
CompactHeightfield chf, int[] srcReg, List<int> overlaps) CompactHeightfield chf, int[] srcReg, List<int> overlaps)
{ {
int w = chf.width; int w = chf.width;
@ -925,7 +925,7 @@ namespace DotRecast.Recast
reg.overlap = true; reg.overlap = true;
} }
addUniqueFloorRegion(reg, floorId); AddUniqueFloorRegion(reg, floorId);
} }
// Have found contour // Have found contour
@ -940,7 +940,7 @@ namespace DotRecast.Recast
int ndir = -1; int ndir = -1;
for (int dir = 0; dir < 4; ++dir) for (int dir = 0; dir < 4; ++dir)
{ {
if (isSolidEdge(chf, srcReg, x, y, i, dir)) if (IsSolidEdge(chf, srcReg, x, y, i, dir))
{ {
ndir = dir; ndir = dir;
break; break;
@ -951,7 +951,7 @@ namespace DotRecast.Recast
{ {
// The cell is at border. // The cell is at border.
// Walk around the contour to find all the neighbours. // Walk around the contour to find all the neighbours.
walkContour(x, y, i, ndir, chf, srcReg, reg.connections); WalkContour(x, y, i, ndir, chf, srcReg, reg.connections);
} }
} }
} }
@ -1063,7 +1063,7 @@ namespace DotRecast.Recast
} }
// Check to see if the region should be merged. // Check to see if the region should be merged.
if (reg.spanCount > mergeRegionSize && isRegionConnectedToBorder(reg)) if (reg.spanCount > mergeRegionSize && IsRegionConnectedToBorder(reg))
{ {
continue; continue;
} }
@ -1086,7 +1086,7 @@ namespace DotRecast.Recast
continue; continue;
} }
if (mreg.spanCount < smallest && canMergeWithRegion(reg, mreg) && canMergeWithRegion(mreg, reg)) if (mreg.spanCount < smallest && CanMergeWithRegion(reg, mreg) && CanMergeWithRegion(mreg, reg))
{ {
smallest = mreg.spanCount; smallest = mreg.spanCount;
mergeId = mreg.id; mergeId = mreg.id;
@ -1100,7 +1100,7 @@ namespace DotRecast.Recast
Region target = regions[mergeId]; Region target = regions[mergeId];
// Merge neighbours. // Merge neighbours.
if (mergeRegions(target, reg)) if (MergeRegions(target, reg))
{ {
// Fixup regions pointing to current region. // Fixup regions pointing to current region.
for (int j = 0; j < nreg; ++j) for (int j = 0; j < nreg; ++j)
@ -1119,7 +1119,7 @@ namespace DotRecast.Recast
// Replace the current region with the new one if the // Replace the current region with the new one if the
// current regions is neighbour. // current regions is neighbour.
replaceNeighbour(regions[j], oldId, mergeId); ReplaceNeighbour(regions[j], oldId, mergeId);
} }
mergeCount++; mergeCount++;
@ -1188,7 +1188,7 @@ namespace DotRecast.Recast
return maxRegionId; return maxRegionId;
} }
private static void addUniqueConnection(Region reg, int n) private static void AddUniqueConnection(Region reg, int n)
{ {
if (!reg.connections.Contains(n)) if (!reg.connections.Contains(n))
{ {
@ -1196,7 +1196,7 @@ namespace DotRecast.Recast
} }
} }
private static int mergeAndFilterLayerRegions(Telemetry ctx, int minRegionArea, int maxRegionId, private static int MergeAndFilterLayerRegions(Telemetry ctx, int minRegionArea, int maxRegionId,
CompactHeightfield chf, int[] srcReg, List<int> overlaps) CompactHeightfield chf, int[] srcReg, List<int> overlaps)
{ {
int w = chf.width; int w = chf.width;
@ -1250,7 +1250,7 @@ namespace DotRecast.Recast
int rai = srcReg[ai]; int rai = srcReg[ai];
if (rai > 0 && rai < nreg && rai != ri) if (rai > 0 && rai < nreg && rai != ri)
{ {
addUniqueConnection(reg, rai); AddUniqueConnection(reg, rai);
} }
if ((rai & RC_BORDER_REG) != 0) if ((rai & RC_BORDER_REG) != 0)
@ -1270,8 +1270,8 @@ namespace DotRecast.Recast
{ {
Region ri = regions[lregs[i]]; Region ri = regions[lregs[i]];
Region rj = regions[lregs[j]]; Region rj = regions[lregs[j]];
addUniqueFloorRegion(ri, lregs[j]); AddUniqueFloorRegion(ri, lregs[j]);
addUniqueFloorRegion(rj, lregs[i]); AddUniqueFloorRegion(rj, lregs[i]);
} }
} }
} }
@ -1351,7 +1351,7 @@ namespace DotRecast.Recast
// Merge current layers to root. // Merge current layers to root.
for (int k = 0; k < regn.floors.Count; ++k) for (int k = 0; k < regn.floors.Count; ++k)
{ {
addUniqueFloorRegion(root, regn.floors[k]); AddUniqueFloorRegion(root, regn.floors[k]);
} }
root.ymin = Math.Min(root.ymin, regn.ymin); root.ymin = Math.Min(root.ymin, regn.ymin);
@ -1442,31 +1442,31 @@ namespace DotRecast.Recast
/// and rcCompactHeightfield::dist fields. /// and rcCompactHeightfield::dist fields.
/// ///
/// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone /// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone
public static void buildDistanceField(Telemetry ctx, CompactHeightfield chf) public static void BuildDistanceField(Telemetry ctx, CompactHeightfield chf)
{ {
ctx.startTimer("DISTANCEFIELD"); ctx.StartTimer("DISTANCEFIELD");
int[] src = new int[chf.spanCount]; int[] src = new int[chf.spanCount];
ctx.startTimer("DISTANCEFIELD_DIST"); ctx.StartTimer("DISTANCEFIELD_DIST");
int maxDist = calculateDistanceField(chf, src); int maxDist = CalculateDistanceField(chf, src);
chf.maxDistance = maxDist; chf.maxDistance = maxDist;
ctx.stopTimer("DISTANCEFIELD_DIST"); ctx.StopTimer("DISTANCEFIELD_DIST");
ctx.startTimer("DISTANCEFIELD_BLUR"); ctx.StartTimer("DISTANCEFIELD_BLUR");
// Blur // Blur
src = boxBlur(chf, 1, src); src = BoxBlur(chf, 1, src);
// Store distance. // Store distance.
chf.dist = src; chf.dist = src;
ctx.stopTimer("DISTANCEFIELD_BLUR"); ctx.StopTimer("DISTANCEFIELD_BLUR");
ctx.stopTimer("DISTANCEFIELD"); ctx.StopTimer("DISTANCEFIELD");
} }
private static void paintRectRegion(int minx, int maxx, int miny, int maxy, int regId, CompactHeightfield chf, private static void PaintRectRegion(int minx, int maxx, int miny, int maxy, int regId, CompactHeightfield chf,
int[] srcReg) int[] srcReg)
{ {
int w = chf.width; int w = chf.width;
@ -1505,10 +1505,10 @@ namespace DotRecast.Recast
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions. /// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
/// ///
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig /// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
public static void buildRegionsMonotone(Telemetry ctx, CompactHeightfield chf, int minRegionArea, public static void BuildRegionsMonotone(Telemetry ctx, CompactHeightfield chf, int minRegionArea,
int mergeRegionArea) int mergeRegionArea)
{ {
ctx.startTimer("REGIONS"); ctx.StartTimer("REGIONS");
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
@ -1531,13 +1531,13 @@ namespace DotRecast.Recast
int bw = Math.Min(w, borderSize); int bw = Math.Min(w, borderSize);
int bh = Math.Min(h, borderSize); int bh = Math.Min(h, borderSize);
// Paint regions // Paint regions
paintRectRegion(0, bw, 0, h, id | RC_BORDER_REG, chf, srcReg); PaintRectRegion(0, bw, 0, h, id | RC_BORDER_REG, chf, srcReg);
id++; id++;
paintRectRegion(w - bw, w, 0, h, id | RC_BORDER_REG, chf, srcReg); PaintRectRegion(w - bw, w, 0, h, id | RC_BORDER_REG, chf, srcReg);
id++; id++;
paintRectRegion(0, w, 0, bh, id | RC_BORDER_REG, chf, srcReg); PaintRectRegion(0, w, 0, bh, id | RC_BORDER_REG, chf, srcReg);
id++; id++;
paintRectRegion(0, w, h - bh, h, id | RC_BORDER_REG, chf, srcReg); PaintRectRegion(0, w, h - bh, h, id | RC_BORDER_REG, chf, srcReg);
id++; id++;
} }
@ -1650,15 +1650,15 @@ namespace DotRecast.Recast
} }
} }
ctx.startTimer("REGIONS_FILTER"); ctx.StartTimer("REGIONS_FILTER");
// Merge regions and filter out small regions. // Merge regions and filter out small regions.
List<int> overlaps = new List<int>(); List<int> overlaps = new List<int>();
chf.maxRegions = mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, id, chf, srcReg, overlaps); chf.maxRegions = MergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, id, chf, srcReg, overlaps);
// Monotone partitioning does not generate overlapping regions. // Monotone partitioning does not generate overlapping regions.
ctx.stopTimer("REGIONS_FILTER"); ctx.StopTimer("REGIONS_FILTER");
// Store the result out. // Store the result out.
for (int i = 0; i < chf.spanCount; ++i) for (int i = 0; i < chf.spanCount; ++i)
@ -1666,7 +1666,7 @@ namespace DotRecast.Recast
chf.spans[i].reg = srcReg[i]; chf.spans[i].reg = srcReg[i];
} }
ctx.stopTimer("REGIONS"); ctx.StopTimer("REGIONS");
} }
/// @par /// @par
@ -1688,16 +1688,16 @@ namespace DotRecast.Recast
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions. /// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
/// ///
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig /// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
public static void buildRegions(Telemetry ctx, CompactHeightfield chf, int minRegionArea, public static void BuildRegions(Telemetry ctx, CompactHeightfield chf, int minRegionArea,
int mergeRegionArea) int mergeRegionArea)
{ {
ctx.startTimer("REGIONS"); ctx.StartTimer("REGIONS");
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
int borderSize = chf.borderSize; int borderSize = chf.borderSize;
ctx.startTimer("REGIONS_WATERSHED"); ctx.StartTimer("REGIONS_WATERSHED");
int LOG_NB_STACKS = 3; int LOG_NB_STACKS = 3;
int NB_STACKS = 1 << LOG_NB_STACKS; int NB_STACKS = 1 << LOG_NB_STACKS;
@ -1727,13 +1727,13 @@ namespace DotRecast.Recast
int bw = Math.Min(w, borderSize); int bw = Math.Min(w, borderSize);
int bh = Math.Min(h, borderSize); int bh = Math.Min(h, borderSize);
// Paint regions // Paint regions
paintRectRegion(0, bw, 0, h, regionId | RC_BORDER_REG, chf, srcReg); PaintRectRegion(0, bw, 0, h, regionId | RC_BORDER_REG, chf, srcReg);
regionId++; regionId++;
paintRectRegion(w - bw, w, 0, h, regionId | RC_BORDER_REG, chf, srcReg); PaintRectRegion(w - bw, w, 0, h, regionId | RC_BORDER_REG, chf, srcReg);
regionId++; regionId++;
paintRectRegion(0, w, 0, bh, regionId | RC_BORDER_REG, chf, srcReg); PaintRectRegion(0, w, 0, bh, regionId | RC_BORDER_REG, chf, srcReg);
regionId++; regionId++;
paintRectRegion(0, w, h - bh, h, regionId | RC_BORDER_REG, chf, srcReg); PaintRectRegion(0, w, h - bh, h, regionId | RC_BORDER_REG, chf, srcReg);
regionId++; regionId++;
} }
@ -1745,27 +1745,27 @@ namespace DotRecast.Recast
level = level >= 2 ? level - 2 : 0; level = level >= 2 ? level - 2 : 0;
sId = (sId + 1) & (NB_STACKS - 1); sId = (sId + 1) & (NB_STACKS - 1);
// ctx->startTimer(RC_TIMER_DIVIDE_TO_LEVELS); // ctx->StartTimer(RC_TIMER_DIVIDE_TO_LEVELS);
if (sId == 0) if (sId == 0)
{ {
sortCellsByLevel(level, chf, srcReg, NB_STACKS, lvlStacks, 1); SortCellsByLevel(level, chf, srcReg, NB_STACKS, lvlStacks, 1);
} }
else else
{ {
appendStacks(lvlStacks[sId - 1], lvlStacks[sId], srcReg); // copy left overs from last level AppendStacks(lvlStacks[sId - 1], lvlStacks[sId], srcReg); // copy left overs from last level
} }
// ctx->stopTimer(RC_TIMER_DIVIDE_TO_LEVELS); // ctx->StopTimer(RC_TIMER_DIVIDE_TO_LEVELS);
ctx.startTimer("REGIONS_EXPAND"); ctx.StartTimer("REGIONS_EXPAND");
// Expand current regions until no empty connected cells found. // Expand current regions until no empty connected cells found.
expandRegions(expandIters, level, chf, srcReg, srcDist, lvlStacks[sId], false); ExpandRegions(expandIters, level, chf, srcReg, srcDist, lvlStacks[sId], false);
ctx.stopTimer("REGIONS_EXPAND"); ctx.StopTimer("REGIONS_EXPAND");
ctx.startTimer("REGIONS_FLOOD"); ctx.StartTimer("REGIONS_FLOOD");
// Mark new regions with IDs. // Mark new regions with IDs.
for (int j = 0; j < lvlStacks[sId].Count; j += 3) for (int j = 0; j < lvlStacks[sId].Count; j += 3)
@ -1775,34 +1775,34 @@ namespace DotRecast.Recast
int i = lvlStacks[sId][j + 2]; int i = lvlStacks[sId][j + 2];
if (i >= 0 && srcReg[i] == 0) if (i >= 0 && srcReg[i] == 0)
{ {
if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack)) if (FloodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
{ {
regionId++; regionId++;
} }
} }
} }
ctx.stopTimer("REGIONS_FLOOD"); ctx.StopTimer("REGIONS_FLOOD");
} }
// Expand current regions until no empty connected cells found. // Expand current regions until no empty connected cells found.
expandRegions(expandIters * 8, 0, chf, srcReg, srcDist, stack, true); ExpandRegions(expandIters * 8, 0, chf, srcReg, srcDist, stack, true);
ctx.stopTimer("REGIONS_WATERSHED"); ctx.StopTimer("REGIONS_WATERSHED");
ctx.startTimer("REGIONS_FILTER"); ctx.StartTimer("REGIONS_FILTER");
// Merge regions and filter out smalle regions. // Merge regions and filter out smalle regions.
List<int> overlaps = new List<int>(); List<int> overlaps = new List<int>();
chf.maxRegions = mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, regionId, chf, srcReg, overlaps); chf.maxRegions = MergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, regionId, chf, srcReg, overlaps);
// If overlapping regions were found during merging, split those regions. // If overlapping regions were found during merging, split those regions.
if (overlaps.Count > 0) if (overlaps.Count > 0)
{ {
ctx.warn("rcBuildRegions: " + overlaps.Count + " overlapping regions."); ctx.Warn("rcBuildRegions: " + overlaps.Count + " overlapping regions.");
} }
ctx.stopTimer("REGIONS_FILTER"); ctx.StopTimer("REGIONS_FILTER");
// Write the result out. // Write the result out.
for (int i = 0; i < chf.spanCount; ++i) for (int i = 0; i < chf.spanCount; ++i)
@ -1810,12 +1810,12 @@ namespace DotRecast.Recast
chf.spans[i].reg = srcReg[i]; chf.spans[i].reg = srcReg[i];
} }
ctx.stopTimer("REGIONS"); ctx.StopTimer("REGIONS");
} }
public static void buildLayerRegions(Telemetry ctx, CompactHeightfield chf, int minRegionArea) public static void BuildLayerRegions(Telemetry ctx, CompactHeightfield chf, int minRegionArea)
{ {
ctx.startTimer("REGIONS"); ctx.StartTimer("REGIONS");
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
@ -1837,13 +1837,13 @@ namespace DotRecast.Recast
int bw = Math.Min(w, borderSize); int bw = Math.Min(w, borderSize);
int bh = Math.Min(h, borderSize); int bh = Math.Min(h, borderSize);
// Paint regions // Paint regions
paintRectRegion(0, bw, 0, h, id | RC_BORDER_REG, chf, srcReg); PaintRectRegion(0, bw, 0, h, id | RC_BORDER_REG, chf, srcReg);
id++; id++;
paintRectRegion(w - bw, w, 0, h, id | RC_BORDER_REG, chf, srcReg); PaintRectRegion(w - bw, w, 0, h, id | RC_BORDER_REG, chf, srcReg);
id++; id++;
paintRectRegion(0, w, 0, bh, id | RC_BORDER_REG, chf, srcReg); PaintRectRegion(0, w, 0, bh, id | RC_BORDER_REG, chf, srcReg);
id++; id++;
paintRectRegion(0, w, h - bh, h, id | RC_BORDER_REG, chf, srcReg); PaintRectRegion(0, w, h - bh, h, id | RC_BORDER_REG, chf, srcReg);
id++; id++;
} }
@ -1956,13 +1956,13 @@ namespace DotRecast.Recast
} }
} }
ctx.startTimer("REGIONS_FILTER"); ctx.StartTimer("REGIONS_FILTER");
// Merge monotone regions to layers and remove small regions. // Merge monotone regions to layers and remove small regions.
List<int> overlaps = new List<int>(); List<int> overlaps = new List<int>();
chf.maxRegions = mergeAndFilterLayerRegions(ctx, minRegionArea, id, chf, srcReg, overlaps); chf.maxRegions = MergeAndFilterLayerRegions(ctx, minRegionArea, id, chf, srcReg, overlaps);
ctx.stopTimer("REGIONS_FILTER"); ctx.StopTimer("REGIONS_FILTER");
// Store the result out. // Store the result out.
for (int i = 0; i < chf.spanCount; ++i) for (int i = 0; i < chf.spanCount; ++i)
@ -1970,7 +1970,7 @@ namespace DotRecast.Recast
chf.spans[i].reg = srcReg[i]; chf.spans[i].reg = srcReg[i];
} }
ctx.stopTimer("REGIONS"); ctx.StopTimer("REGIONS");
} }
} }
} }

View File

@ -25,61 +25,61 @@ namespace DotRecast.Recast
{ {
public static class RecastVectors public static class RecastVectors
{ {
public static void min(ref Vector3f a, float[] b, int i) public static void Min(ref Vector3f a, float[] b, int i)
{ {
a.x = Math.Min(a.x, b[i + 0]); a.x = Math.Min(a.x, b[i + 0]);
a.y = Math.Min(a.y, b[i + 1]); a.y = Math.Min(a.y, b[i + 1]);
a.z = Math.Min(a.z, b[i + 2]); a.z = Math.Min(a.z, b[i + 2]);
} }
public static void min(ref Vector3f a, Vector3f b) public static void Min(ref Vector3f a, Vector3f b)
{ {
a.x = Math.Min(a.x, b.x); a.x = Math.Min(a.x, b.x);
a.y = Math.Min(a.y, b.y); a.y = Math.Min(a.y, b.y);
a.z = Math.Min(a.z, b.z); a.z = Math.Min(a.z, b.z);
} }
public static void max(ref Vector3f a, float[] b, int i) public static void Max(ref Vector3f a, float[] b, int i)
{ {
a.x = Math.Max(a.x, b[i + 0]); a.x = Math.Max(a.x, b[i + 0]);
a.y = Math.Max(a.y, b[i + 1]); a.y = Math.Max(a.y, b[i + 1]);
a.z = Math.Max(a.z, b[i + 2]); a.z = Math.Max(a.z, b[i + 2]);
} }
public static void max(ref Vector3f a, Vector3f b) public static void Max(ref Vector3f a, Vector3f b)
{ {
a.x = Math.Max(a.x, b.x); a.x = Math.Max(a.x, b.x);
a.y = Math.Max(a.y, b.y); a.y = Math.Max(a.y, b.y);
a.z = Math.Max(a.z, b.z); a.z = Math.Max(a.z, b.z);
} }
public static void copy(ref Vector3f @out, float[] @in, int i) public static void Copy(ref Vector3f @out, float[] @in, int i)
{ {
copy(ref @out, 0, @in, i); Copy(ref @out, 0, @in, i);
} }
public static void copy(float[] @out, int n, float[] @in, int m) public static void Copy(float[] @out, int n, float[] @in, int m)
{ {
@out[n] = @in[m]; @out[n] = @in[m];
@out[n + 1] = @in[m + 1]; @out[n + 1] = @in[m + 1];
@out[n + 2] = @in[m + 2]; @out[n + 2] = @in[m + 2];
} }
public static void copy(float[] @out, int n, Vector3f @in, int m) public static void Copy(float[] @out, int n, Vector3f @in, int m)
{ {
@out[n] = @in[m]; @out[n] = @in[m];
@out[n + 1] = @in[m + 1]; @out[n + 1] = @in[m + 1];
@out[n + 2] = @in[m + 2]; @out[n + 2] = @in[m + 2];
} }
public static void copy(ref Vector3f @out, int n, float[] @in, int m) public static void Copy(ref Vector3f @out, int n, float[] @in, int m)
{ {
@out[n] = @in[m]; @out[n] = @in[m];
@out[n + 1] = @in[m + 1]; @out[n + 1] = @in[m + 1];
@out[n + 2] = @in[m + 2]; @out[n + 2] = @in[m + 2];
} }
public static void add(ref Vector3f e0, Vector3f a, float[] verts, int i) public static void Add(ref Vector3f e0, Vector3f a, float[] verts, int i)
{ {
e0.x = a.x + verts[i]; e0.x = a.x + verts[i];
e0.y = a.y + verts[i + 1]; e0.y = a.y + verts[i + 1];
@ -87,7 +87,7 @@ namespace DotRecast.Recast
} }
public static void sub(ref Vector3f e0, float[] verts, int i, int j) public static void Sub(ref Vector3f e0, float[] verts, int i, int j)
{ {
e0.x = verts[i] - verts[j]; e0.x = verts[i] - verts[j];
e0.y = verts[i + 1] - verts[j + 1]; e0.y = verts[i + 1] - verts[j + 1];
@ -95,7 +95,7 @@ namespace DotRecast.Recast
} }
public static void sub(ref Vector3f e0, Vector3f i, float[] verts, int j) public static void Sub(ref Vector3f e0, Vector3f i, float[] verts, int j)
{ {
e0.x = i.x - verts[j]; e0.x = i.x - verts[j];
e0.y = i.y - verts[j + 1]; e0.y = i.y - verts[j + 1];
@ -103,21 +103,21 @@ namespace DotRecast.Recast
} }
public static void cross(float[] dest, float[] v1, float[] v2) public static void Cross(float[] dest, float[] v1, float[] v2)
{ {
dest[0] = v1[1] * v2[2] - v1[2] * v2[1]; dest[0] = v1[1] * v2[2] - v1[2] * v2[1];
dest[1] = v1[2] * v2[0] - v1[0] * v2[2]; dest[1] = v1[2] * v2[0] - v1[0] * v2[2];
dest[2] = v1[0] * v2[1] - v1[1] * v2[0]; dest[2] = v1[0] * v2[1] - v1[1] * v2[0];
} }
public static void cross(float[] dest, Vector3f v1, Vector3f v2) public static void Cross(float[] dest, Vector3f v1, Vector3f v2)
{ {
dest[0] = v1.y * v2.z - v1.z * v2.y; dest[0] = v1.y * v2.z - v1.z * v2.y;
dest[1] = v1.z * v2.x - v1.x * v2.z; dest[1] = v1.z * v2.x - v1.x * v2.z;
dest[2] = v1.x * v2.y - v1.y * v2.x; dest[2] = v1.x * v2.y - v1.y * v2.x;
} }
public static void cross(ref Vector3f dest, Vector3f v1, Vector3f v2) public static void Cross(ref Vector3f dest, Vector3f v1, Vector3f v2)
{ {
dest.x = v1.y * v2.z - v1.z * v2.y; dest.x = v1.y * v2.z - v1.z * v2.y;
dest.y = v1.z * v2.x - v1.x * v2.z; dest.y = v1.z * v2.x - v1.x * v2.z;
@ -125,7 +125,7 @@ namespace DotRecast.Recast
} }
public static void normalize(float[] v) public static void Normalize(float[] v)
{ {
float d = (float)(1.0f / Math.Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2])); float d = (float)(1.0f / Math.Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
v[0] *= d; v[0] *= d;
@ -133,7 +133,7 @@ namespace DotRecast.Recast
v[2] *= d; v[2] *= d;
} }
public static void normalize(ref Vector3f v) public static void Normalize(ref Vector3f v)
{ {
float d = (float)(1.0f / Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z)); float d = (float)(1.0f / Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z));
v.x *= d; v.x *= d;
@ -141,17 +141,17 @@ namespace DotRecast.Recast
v.z *= d; v.z *= d;
} }
public static float dot(float[] v1, float[] v2) public static float Dot(float[] v1, float[] v2)
{ {
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
} }
public static float dot(float[] v1, Vector3f v2) public static float Dot(float[] v1, Vector3f v2)
{ {
return v1[0] * v2.x + v1[1] * v2.y + v1[2] * v2.z; return v1[0] * v2.x + v1[1] * v2.y + v1[2] * v2.z;
} }
public static float dot(Vector3f v1, Vector3f v2) public static float Dot(Vector3f v1, Vector3f v2)
{ {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
} }

View File

@ -23,7 +23,7 @@ namespace DotRecast.Recast
{ {
public class RecastVoxelization public class RecastVoxelization
{ {
public static Heightfield buildSolidHeightfield(InputGeomProvider geomProvider, RecastBuilderConfig builderCfg, public static Heightfield BuildSolidHeightfield(InputGeomProvider geomProvider, RecastBuilderConfig builderCfg,
Telemetry ctx) Telemetry ctx)
{ {
RecastConfig cfg = builderCfg.cfg; RecastConfig cfg = builderCfg.cfg;
@ -41,9 +41,9 @@ namespace DotRecast.Recast
// If your input data is multiple meshes, you can transform them here, // If your input data is multiple meshes, you can transform them here,
// calculate // calculate
// the are type for each of the meshes and rasterize them. // the are type for each of the meshes and rasterize them.
foreach (TriMesh geom in geomProvider.meshes()) foreach (TriMesh geom in geomProvider.Meshes())
{ {
float[] verts = geom.getVerts(); float[] verts = geom.GetVerts();
if (cfg.useTiles) if (cfg.useTiles)
{ {
float[] tbmin = new float[2]; float[] tbmin = new float[2];
@ -52,21 +52,21 @@ namespace DotRecast.Recast
tbmin[1] = builderCfg.bmin.z; tbmin[1] = builderCfg.bmin.z;
tbmax[0] = builderCfg.bmax.x; tbmax[0] = builderCfg.bmax.x;
tbmax[1] = builderCfg.bmax.z; tbmax[1] = builderCfg.bmax.z;
List<ChunkyTriMeshNode> nodes = geom.getChunksOverlappingRect(tbmin, tbmax); List<ChunkyTriMeshNode> nodes = geom.GetChunksOverlappingRect(tbmin, tbmax);
foreach (ChunkyTriMeshNode node in nodes) foreach (ChunkyTriMeshNode node in nodes)
{ {
int[] tris = node.tris; int[] tris = node.tris;
int ntris = tris.Length / 3; int ntris = tris.Length / 3;
int[] m_triareas = Recast.markWalkableTriangles(ctx, cfg.walkableSlopeAngle, verts, tris, ntris, cfg.walkableAreaMod); int[] m_triareas = Recast.MarkWalkableTriangles(ctx, cfg.walkableSlopeAngle, verts, tris, ntris, cfg.walkableAreaMod);
RecastRasterization.rasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.walkableClimb, ctx); RecastRasterization.RasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.walkableClimb, ctx);
} }
} }
else else
{ {
int[] tris = geom.getTris(); int[] tris = geom.GetTris();
int ntris = tris.Length / 3; int ntris = tris.Length / 3;
int[] m_triareas = Recast.markWalkableTriangles(ctx, cfg.walkableSlopeAngle, verts, tris, ntris, cfg.walkableAreaMod); int[] m_triareas = Recast.MarkWalkableTriangles(ctx, cfg.walkableSlopeAngle, verts, tris, ntris, cfg.walkableAreaMod);
RecastRasterization.rasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.walkableClimb, ctx); RecastRasterization.RasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.walkableClimb, ctx);
} }
} }

View File

@ -31,19 +31,19 @@ namespace DotRecast.Recast
private readonly ThreadLocal<Dictionary<string, AtomicLong>> timerStart = new ThreadLocal<Dictionary<string, AtomicLong>>(() => new Dictionary<string, AtomicLong>()); private readonly ThreadLocal<Dictionary<string, AtomicLong>> timerStart = new ThreadLocal<Dictionary<string, AtomicLong>>(() => new Dictionary<string, AtomicLong>());
private readonly ConcurrentDictionary<string, AtomicLong> timerAccum = new ConcurrentDictionary<string, AtomicLong>(); private readonly ConcurrentDictionary<string, AtomicLong> timerAccum = new ConcurrentDictionary<string, AtomicLong>();
public void startTimer(string name) public void StartTimer(string name)
{ {
timerStart.Value[name] = new AtomicLong(FrequencyWatch.Ticks); timerStart.Value[name] = new AtomicLong(FrequencyWatch.Ticks);
} }
public void stopTimer(string name) public void StopTimer(string name)
{ {
timerAccum timerAccum
.GetOrAdd(name, _ => new AtomicLong(0)) .GetOrAdd(name, _ => new AtomicLong(0))
.AddAndGet(FrequencyWatch.Ticks - timerStart.Value?[name].Read() ?? 0); .AddAndGet(FrequencyWatch.Ticks - timerStart.Value?[name].Read() ?? 0);
} }
public void warn(string @string) public void Warn(string @string)
{ {
Console.WriteLine(@string); Console.WriteLine(@string);
} }

View File

@ -64,9 +64,9 @@ public class AbstractCrowdTest
protected List<CrowdAgent> agents; protected List<CrowdAgent> agents;
[SetUp] [SetUp]
public void setUp() public void SetUp()
{ {
nmd = new RecastTestMeshBuilder().getMeshData(); nmd = new RecastTestMeshBuilder().GetMeshData();
navmesh = new NavMesh(nmd, 6, 0); navmesh = new NavMesh(nmd, 6, 0);
query = new NavMeshQuery(navmesh); query = new NavMeshQuery(navmesh);
CrowdConfig config = new CrowdConfig(0.6f); CrowdConfig config = new CrowdConfig(0.6f);
@ -76,29 +76,29 @@ public class AbstractCrowdTest
option.adaptiveDivs = 5; option.adaptiveDivs = 5;
option.adaptiveRings = 2; option.adaptiveRings = 2;
option.adaptiveDepth = 1; option.adaptiveDepth = 1;
crowd.setObstacleAvoidanceParams(0, option); crowd.SetObstacleAvoidanceParams(0, option);
option = new ObstacleAvoidanceParams(); option = new ObstacleAvoidanceParams();
option.velBias = 0.5f; option.velBias = 0.5f;
option.adaptiveDivs = 5; option.adaptiveDivs = 5;
option.adaptiveRings = 2; option.adaptiveRings = 2;
option.adaptiveDepth = 2; option.adaptiveDepth = 2;
crowd.setObstacleAvoidanceParams(1, option); crowd.SetObstacleAvoidanceParams(1, option);
option = new ObstacleAvoidanceParams(); option = new ObstacleAvoidanceParams();
option.velBias = 0.5f; option.velBias = 0.5f;
option.adaptiveDivs = 7; option.adaptiveDivs = 7;
option.adaptiveRings = 2; option.adaptiveRings = 2;
option.adaptiveDepth = 3; option.adaptiveDepth = 3;
crowd.setObstacleAvoidanceParams(2, option); crowd.SetObstacleAvoidanceParams(2, option);
option = new ObstacleAvoidanceParams(); option = new ObstacleAvoidanceParams();
option.velBias = 0.5f; option.velBias = 0.5f;
option.adaptiveDivs = 7; option.adaptiveDivs = 7;
option.adaptiveRings = 3; option.adaptiveRings = 3;
option.adaptiveDepth = 3; option.adaptiveDepth = 3;
crowd.setObstacleAvoidanceParams(3, option); crowd.SetObstacleAvoidanceParams(3, option);
agents = new(); agents = new();
} }
protected CrowdAgentParams getAgentParams(int updateFlags, int obstacleAvoidanceType) protected CrowdAgentParams GetAgentParams(int updateFlags, int obstacleAvoidanceType)
{ {
CrowdAgentParams ap = new CrowdAgentParams(); CrowdAgentParams ap = new CrowdAgentParams();
ap.radius = 0.6f; ap.radius = 0.6f;
@ -113,9 +113,9 @@ public class AbstractCrowdTest
return ap; return ap;
} }
protected void addAgentGrid(int size, float distance, int updateFlags, int obstacleAvoidanceType, Vector3f startPos) protected void AddAgentGrid(int size, float distance, int updateFlags, int obstacleAvoidanceType, Vector3f startPos)
{ {
CrowdAgentParams ap = getAgentParams(updateFlags, obstacleAvoidanceType); CrowdAgentParams ap = GetAgentParams(updateFlags, obstacleAvoidanceType);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
for (int j = 0; j < size; j++) for (int j = 0; j < size; j++)
@ -124,46 +124,46 @@ public class AbstractCrowdTest
pos.x = startPos.x + i * distance; pos.x = startPos.x + i * distance;
pos.y = startPos.y; pos.y = startPos.y;
pos.z = startPos.z + j * distance; pos.z = startPos.z + j * distance;
agents.Add(crowd.addAgent(pos, ap)); agents.Add(crowd.AddAgent(pos, ap));
} }
} }
} }
protected void setMoveTarget(Vector3f pos, bool adjust) protected void SetMoveTarget(Vector3f pos, bool adjust)
{ {
Vector3f ext = crowd.getQueryExtents(); Vector3f ext = crowd.GetQueryExtents();
QueryFilter filter = crowd.getFilter(0); QueryFilter filter = crowd.GetFilter(0);
if (adjust) if (adjust)
{ {
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Vector3f vel = calcVel(ag.npos, pos, ag.option.maxSpeed); Vector3f vel = CalcVel(ag.npos, pos, ag.option.maxSpeed);
crowd.requestMoveVelocity(ag, vel); crowd.RequestMoveVelocity(ag, vel);
} }
} }
else else
{ {
Result<FindNearestPolyResult> nearest = query.findNearestPoly(pos, ext, filter); Result<FindNearestPolyResult> nearest = query.FindNearestPoly(pos, ext, filter);
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
crowd.requestMoveTarget(ag, nearest.result.getNearestRef(), nearest.result.getNearestPos()); crowd.RequestMoveTarget(ag, nearest.result.GetNearestRef(), nearest.result.GetNearestPos());
} }
} }
} }
protected Vector3f calcVel(Vector3f pos, Vector3f tgt, float speed) protected Vector3f CalcVel(Vector3f pos, Vector3f tgt, float speed)
{ {
Vector3f vel = vSub(tgt, pos); Vector3f vel = VSub(tgt, pos);
vel.y = 0.0f; vel.y = 0.0f;
vNormalize(ref vel); VNormalize(ref vel);
vel = vScale(vel, speed); vel = VScale(vel, speed);
return vel; return vel;
} }
protected void dumpActiveAgents(int i) protected void DumpActiveAgents(int i)
{ {
Console.WriteLine(crowd.getActiveAgents().Count); Console.WriteLine(crowd.GetActiveAgents().Count);
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Console.WriteLine(ag.state + ", " + ag.targetState); Console.WriteLine(ag.state + ", " + ag.targetState);
Console.WriteLine(ag.npos.x + ", " + ag.npos.y + ", " + ag.npos.z); Console.WriteLine(ag.npos.x + ", " + ag.npos.y + ", " + ag.npos.z);

View File

@ -563,17 +563,17 @@ public class Crowd1Test : AbstractCrowdTest
}; };
[Test] [Test]
public void testAgent1Quality0TVTA() public void TestAgent1Quality0TVTA()
{ {
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE; | CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE;
addAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]); AddAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]);
setMoveTarget(endPoss[0], false); SetMoveTarget(endPoss[0], false);
for (int i = 0; i < EXPECTED_A1Q0TVTA.Length; i++) for (int i = 0; i < EXPECTED_A1Q0TVTA.Length; i++)
{ {
crowd.update(1 / 5f, null); crowd.Update(1 / 5f, null);
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q0TVTA[i][0]).Within(0.001f)); Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q0TVTA[i][0]).Within(0.001f));
Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q0TVTA[i][1]).Within(0.001f)); Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q0TVTA[i][1]).Within(0.001f));
@ -586,17 +586,17 @@ public class Crowd1Test : AbstractCrowdTest
} }
[Test] [Test]
public void testAgent1Quality0TVT() public void TestAgent1Quality0TVT()
{ {
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO; | CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO;
addAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]); AddAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]);
setMoveTarget(endPoss[0], false); SetMoveTarget(endPoss[0], false);
for (int i = 0; i < EXPECTED_A1Q0TVT.Length; i++) for (int i = 0; i < EXPECTED_A1Q0TVT.Length; i++)
{ {
crowd.update(1 / 5f, null); crowd.Update(1 / 5f, null);
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q0TVT[i][0]).Within(0.001f)); Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q0TVT[i][0]).Within(0.001f));
Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q0TVT[i][1]).Within(0.001f)); Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q0TVT[i][1]).Within(0.001f));
@ -609,16 +609,16 @@ public class Crowd1Test : AbstractCrowdTest
} }
[Test] [Test]
public void testAgent1Quality0TV() public void TestAgent1Quality0TV()
{ {
int updateFlags = CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS; int updateFlags = CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS;
addAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]); AddAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]);
setMoveTarget(endPoss[0], false); SetMoveTarget(endPoss[0], false);
for (int i = 0; i < EXPECTED_A1Q0TV.Length; i++) for (int i = 0; i < EXPECTED_A1Q0TV.Length; i++)
{ {
crowd.update(1 / 5f, null); crowd.Update(1 / 5f, null);
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q0TV[i][0]).Within(0.001f)); Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q0TV[i][0]).Within(0.001f));
Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q0TV[i][1]).Within(0.001f)); Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q0TV[i][1]).Within(0.001f));
@ -631,16 +631,16 @@ public class Crowd1Test : AbstractCrowdTest
} }
[Test] [Test]
public void testAgent1Quality0T() public void TestAgent1Quality0T()
{ {
int updateFlags = CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO; int updateFlags = CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO;
addAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]); AddAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]);
setMoveTarget(endPoss[0], false); SetMoveTarget(endPoss[0], false);
for (int i = 0; i < EXPECTED_A1Q0T.Length; i++) for (int i = 0; i < EXPECTED_A1Q0T.Length; i++)
{ {
crowd.update(1 / 5f, null); crowd.Update(1 / 5f, null);
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q0T[i][0]).Within(0.001)); Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q0T[i][0]).Within(0.001));
Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q0T[i][1]).Within(0.001)); Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q0T[i][1]).Within(0.001));
@ -653,17 +653,17 @@ public class Crowd1Test : AbstractCrowdTest
} }
[Test] [Test]
public void testAgent1Quality1TVTA() public void TestAgent1Quality1TVTA()
{ {
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE; | CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE;
addAgentGrid(1, 0.4f, updateFlags, 1, startPoss[0]); AddAgentGrid(1, 0.4f, updateFlags, 1, startPoss[0]);
setMoveTarget(endPoss[0], false); SetMoveTarget(endPoss[0], false);
for (int i = 0; i < EXPECTED_A1Q1TVTA.Length; i++) for (int i = 0; i < EXPECTED_A1Q1TVTA.Length; i++)
{ {
crowd.update(1 / 5f, null); crowd.Update(1 / 5f, null);
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q1TVTA[i][0]).Within(0.001f)); Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q1TVTA[i][0]).Within(0.001f));
Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q1TVTA[i][1]).Within(0.001f)); Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q1TVTA[i][1]).Within(0.001f));
@ -676,17 +676,17 @@ public class Crowd1Test : AbstractCrowdTest
} }
[Test] [Test]
public void testAgent1Quality2TVTA() public void TestAgent1Quality2TVTA()
{ {
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE; | CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE;
addAgentGrid(1, 0.4f, updateFlags, 2, startPoss[0]); AddAgentGrid(1, 0.4f, updateFlags, 2, startPoss[0]);
setMoveTarget(endPoss[0], false); SetMoveTarget(endPoss[0], false);
for (int i = 0; i < EXPECTED_A1Q2TVTA.Length; i++) for (int i = 0; i < EXPECTED_A1Q2TVTA.Length; i++)
{ {
crowd.update(1 / 5f, null); crowd.Update(1 / 5f, null);
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q2TVTA[i][0]).Within(0.001f)); Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q2TVTA[i][0]).Within(0.001f));
Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q2TVTA[i][1]).Within(0.001f)); Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q2TVTA[i][1]).Within(0.001f));
@ -699,17 +699,17 @@ public class Crowd1Test : AbstractCrowdTest
} }
[Test] [Test]
public void testAgent1Quality3TVTA() public void TestAgent1Quality3TVTA()
{ {
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE; | CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE;
addAgentGrid(1, 0.4f, updateFlags, 3, startPoss[0]); AddAgentGrid(1, 0.4f, updateFlags, 3, startPoss[0]);
setMoveTarget(endPoss[0], false); SetMoveTarget(endPoss[0], false);
for (int i = 0; i < EXPECTED_A1Q3TVTA.Length; i++) for (int i = 0; i < EXPECTED_A1Q3TVTA.Length; i++)
{ {
crowd.update(1 / 5f, null); crowd.Update(1 / 5f, null);
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q3TVTA[i][0]).Within(0.001f)); Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q3TVTA[i][0]).Within(0.001f));
Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q3TVTA[i][1]).Within(0.001f)); Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q3TVTA[i][1]).Within(0.001f));
@ -722,18 +722,18 @@ public class Crowd1Test : AbstractCrowdTest
} }
[Test] [Test]
public void testAgent1Quality3TVTAS() public void TestAgent1Quality3TVTAS()
{ {
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE | CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE
| CrowdAgentParams.DT_CROWD_SEPARATION; | CrowdAgentParams.DT_CROWD_SEPARATION;
addAgentGrid(1, 0.4f, updateFlags, 3, startPoss[0]); AddAgentGrid(1, 0.4f, updateFlags, 3, startPoss[0]);
setMoveTarget(endPoss[0], false); SetMoveTarget(endPoss[0], false);
for (int i = 0; i < EXPECTED_A1Q3TVTAS.Length; i++) for (int i = 0; i < EXPECTED_A1Q3TVTAS.Length; i++)
{ {
crowd.update(1 / 5f, null); crowd.Update(1 / 5f, null);
foreach (CrowdAgent ag in crowd.getActiveAgents()) foreach (CrowdAgent ag in crowd.GetActiveAgents())
{ {
Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q3TVTAS[i][0]).Within(0.001f)); Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q3TVTAS[i][0]).Within(0.001f));
Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q3TVTAS[i][1]).Within(0.001f)); Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q3TVTAS[i][1]).Within(0.001f));

View File

@ -306,16 +306,16 @@ public class Crowd4Test : AbstractCrowdTest
}; };
[Test] [Test]
public void testAgent1Quality2TVTA() public void TestAgent1Quality2TVTA()
{ {
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE; | CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE;
addAgentGrid(2, 0.3f, updateFlags, 2, startPoss[0]); AddAgentGrid(2, 0.3f, updateFlags, 2, startPoss[0]);
setMoveTarget(endPoss[0], false); SetMoveTarget(endPoss[0], false);
for (int i = 0; i < EXPECTED_A1Q2TVTA.Length; i++) for (int i = 0; i < EXPECTED_A1Q2TVTA.Length; i++)
{ {
crowd.update(1 / 5f, null); crowd.Update(1 / 5f, null);
CrowdAgent ag = agents[2]; CrowdAgent ag = agents[2];
Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q2TVTA[i][0]).Within(0.001f), $"{i}"); Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q2TVTA[i][0]).Within(0.001f), $"{i}");
Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q2TVTA[i][1]).Within(0.001f), $"{i}"); Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q2TVTA[i][1]).Within(0.001f), $"{i}");
@ -327,17 +327,17 @@ public class Crowd4Test : AbstractCrowdTest
} }
[Test] [Test]
public void testAgent1Quality2TVTAS() public void TestAgent1Quality2TVTAS()
{ {
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE | CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE
| CrowdAgentParams.DT_CROWD_SEPARATION; | CrowdAgentParams.DT_CROWD_SEPARATION;
addAgentGrid(2, 0.3f, updateFlags, 2, startPoss[0]); AddAgentGrid(2, 0.3f, updateFlags, 2, startPoss[0]);
setMoveTarget(endPoss[0], false); SetMoveTarget(endPoss[0], false);
for (int i = 0; i < EXPECTED_A1Q2TVTAS.Length; i++) for (int i = 0; i < EXPECTED_A1Q2TVTAS.Length; i++)
{ {
crowd.update(1 / 5f, null); crowd.Update(1 / 5f, null);
CrowdAgent ag = agents[2]; CrowdAgent ag = agents[2];
Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q2TVTAS[i][0]).Within(0.001f), $"{i}"); Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q2TVTAS[i][0]).Within(0.001f), $"{i}");
Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q2TVTAS[i][1]).Within(0.001f), $"{i}"); Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q2TVTAS[i][1]).Within(0.001f), $"{i}");
@ -349,15 +349,15 @@ public class Crowd4Test : AbstractCrowdTest
} }
[Test] [Test]
public void testAgent1Quality2T() public void TestAgent1Quality2T()
{ {
int updateFlags = CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO; int updateFlags = CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO;
addAgentGrid(2, 0.3f, updateFlags, 2, startPoss[0]); AddAgentGrid(2, 0.3f, updateFlags, 2, startPoss[0]);
setMoveTarget(endPoss[0], false); SetMoveTarget(endPoss[0], false);
for (int i = 0; i < EXPECTED_A1Q2T.Length; i++) for (int i = 0; i < EXPECTED_A1Q2T.Length; i++)
{ {
crowd.update(1 / 5f, null); crowd.Update(1 / 5f, null);
CrowdAgent ag = agents[2]; CrowdAgent ag = agents[2];
Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q2T[i][0]).Within(0.00001f), $"{i} - {ag.npos.x} {EXPECTED_A1Q2T[i][0]}"); Assert.That(ag.npos.x, Is.EqualTo(EXPECTED_A1Q2T[i][0]).Within(0.00001f), $"{i} - {ag.npos.x} {EXPECTED_A1Q2T[i][0]}");
Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q2T[i][1]).Within(0.00001f), $"{i} - {ag.npos.y} {EXPECTED_A1Q2T[i][1]}"); Assert.That(ag.npos.y, Is.EqualTo(EXPECTED_A1Q2T[i][1]).Within(0.00001f), $"{i} - {ag.npos.y} {EXPECTED_A1Q2T[i][1]}");

View File

@ -97,19 +97,19 @@ public class Crowd4VelocityTest : AbstractCrowdTest
}; };
[Test] [Test]
public void testAgent1Quality3TVTA() public void TestAgent1Quality3TVTA()
{ {
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE; | CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE;
addAgentGrid(2, 0.3f, updateFlags, 3, endPoss[0]); AddAgentGrid(2, 0.3f, updateFlags, 3, endPoss[0]);
setMoveTarget(endPoss[4], false); SetMoveTarget(endPoss[4], false);
for (int i = 0; i < EXPECTED_A1Q3TVTA.Length; i++) for (int i = 0; i < EXPECTED_A1Q3TVTA.Length; i++)
{ {
crowd.update(1 / 5f, null); crowd.Update(1 / 5f, null);
if (i == 20) if (i == 20)
{ {
setMoveTarget(startPoss[2], true); SetMoveTarget(startPoss[2], true);
} }
CrowdAgent ag = agents[1]; CrowdAgent ag = agents[1];

View File

@ -31,13 +31,13 @@ public class PathCorridorTest
private readonly QueryFilter filter = new DefaultQueryFilter(); private readonly QueryFilter filter = new DefaultQueryFilter();
[SetUp] [SetUp]
public void setUp() public void SetUp()
{ {
corridor.reset(0, Vector3f.Of(10, 20, 30)); corridor.Reset(0, Vector3f.Of(10, 20, 30));
} }
[Test] [Test]
public void shouldKeepOriginalPathInFindCornersWhenNothingCanBePruned() public void ShouldKeepOriginalPathInFindCornersWhenNothingCanBePruned()
{ {
List<StraightPathItem> straightPath = new(); List<StraightPathItem> straightPath = new();
straightPath.Add(new StraightPathItem(Vector3f.Of(11, 20, 30.00001f), 0, 0)); straightPath.Add(new StraightPathItem(Vector3f.Of(11, 20, 30.00001f), 0, 0));
@ -46,20 +46,20 @@ public class PathCorridorTest
straightPath.Add(new StraightPathItem(Vector3f.Of(11f, 21, 32f), 0, 0)); straightPath.Add(new StraightPathItem(Vector3f.Of(11f, 21, 32f), 0, 0));
Result<List<StraightPathItem>> result = Results.Success(straightPath); Result<List<StraightPathItem>> result = Results.Success(straightPath);
var mockQuery = new Mock<NavMeshQuery>(It.IsAny<NavMesh>()); var mockQuery = new Mock<NavMeshQuery>(It.IsAny<NavMesh>());
mockQuery.Setup(q => q.findStraightPath( mockQuery.Setup(q => q.FindStraightPath(
It.IsAny<Vector3f>(), It.IsAny<Vector3f>(),
It.IsAny<Vector3f>(), It.IsAny<Vector3f>(),
It.IsAny<List<long>>(), It.IsAny<List<long>>(),
It.IsAny<int>(), It.IsAny<int>(),
It.IsAny<int>()) It.IsAny<int>())
).Returns(result); ).Returns(result);
List<StraightPathItem> path = corridor.findCorners(int.MaxValue, mockQuery.Object, filter); List<StraightPathItem> path = corridor.FindCorners(int.MaxValue, mockQuery.Object, filter);
Assert.That(path.Count, Is.EqualTo(4)); Assert.That(path.Count, Is.EqualTo(4));
Assert.That(path, Is.EqualTo(straightPath)); Assert.That(path, Is.EqualTo(straightPath));
} }
[Test] [Test]
public void shouldPrunePathInFindCorners() public void ShouldPrunePathInFindCorners()
{ {
List<StraightPathItem> straightPath = new(); List<StraightPathItem> straightPath = new();
straightPath.Add(new StraightPathItem(Vector3f.Of(10, 20, 30.00001f), 0, 0)); // too close straightPath.Add(new StraightPathItem(Vector3f.Of(10, 20, 30.00001f), 0, 0)); // too close
@ -70,7 +70,7 @@ public class PathCorridorTest
Result<List<StraightPathItem>> result = Results.Success(straightPath); Result<List<StraightPathItem>> result = Results.Success(straightPath);
var mockQuery = new Mock<NavMeshQuery>(It.IsAny<NavMesh>()); var mockQuery = new Mock<NavMeshQuery>(It.IsAny<NavMesh>());
var s = mockQuery.Setup(q => q.findStraightPath( var s = mockQuery.Setup(q => q.FindStraightPath(
It.IsAny<Vector3f>(), It.IsAny<Vector3f>(),
It.IsAny<Vector3f>(), It.IsAny<Vector3f>(),
It.IsAny<List<long>>(), It.IsAny<List<long>>(),
@ -78,7 +78,7 @@ public class PathCorridorTest
It.IsAny<int>()) It.IsAny<int>())
).Returns(result); ).Returns(result);
List<StraightPathItem> path = corridor.findCorners(int.MaxValue, mockQuery.Object, filter); List<StraightPathItem> path = corridor.FindCorners(int.MaxValue, mockQuery.Object, filter);
Assert.That(path.Count, Is.EqualTo(2)); Assert.That(path.Count, Is.EqualTo(2));
Assert.That(path, Is.EqualTo(new List<StraightPathItem> { straightPath[2], straightPath[3] })); Assert.That(path, Is.EqualTo(new List<StraightPathItem> { straightPath[2], straightPath[3] }));
} }

View File

@ -39,7 +39,7 @@ public class RecastTestMeshBuilder
public const float m_detailSampleDist = 6.0f; public const float m_detailSampleDist = 6.0f;
public const float m_detailSampleMaxError = 1.0f; public const float m_detailSampleMaxError = 1.0f;
public RecastTestMeshBuilder() : this(ObjImporter.load(Loader.ToBytes("dungeon.obj")), public RecastTestMeshBuilder() : this(ObjImporter.Load(Loader.ToBytes("dungeon.obj")),
PartitionType.WATERSHED, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_agentMaxSlope, PartitionType.WATERSHED, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_agentMaxSlope,
m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist, m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist,
m_detailSampleMaxError) m_detailSampleMaxError)
@ -54,16 +54,16 @@ public class RecastTestMeshBuilder
RecastConfig cfg = new RecastConfig(m_partitionType, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, RecastConfig cfg = new RecastConfig(m_partitionType, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius,
m_agentMaxClimb, m_agentMaxSlope, m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_agentMaxClimb, m_agentMaxSlope, m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError,
m_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND); m_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, m_geom.getMeshBoundsMin(), m_geom.getMeshBoundsMax()); RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, m_geom.GetMeshBoundsMin(), m_geom.GetMeshBoundsMax());
RecastBuilder rcBuilder = new RecastBuilder(); RecastBuilder rcBuilder = new RecastBuilder();
RecastBuilderResult rcResult = rcBuilder.build(m_geom, bcfg); RecastBuilderResult rcResult = rcBuilder.Build(m_geom, bcfg);
PolyMesh m_pmesh = rcResult.getMesh(); PolyMesh m_pmesh = rcResult.GetMesh();
for (int i = 0; i < m_pmesh.npolys; ++i) for (int i = 0; i < m_pmesh.npolys; ++i)
{ {
m_pmesh.flags[i] = 1; m_pmesh.flags[i] = 1;
} }
PolyMeshDetail m_dmesh = rcResult.getMeshDetail(); PolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
NavMeshDataCreateParams option = new NavMeshDataCreateParams(); NavMeshDataCreateParams option = new NavMeshDataCreateParams();
option.verts = m_pmesh.verts; option.verts = m_pmesh.verts;
option.vertCount = m_pmesh.nverts; option.vertCount = m_pmesh.nverts;
@ -104,10 +104,10 @@ public class RecastTestMeshBuilder
option.offMeshConUserID = new int[1]; option.offMeshConUserID = new int[1];
option.offMeshConUserID[0] = 0x4567; option.offMeshConUserID[0] = 0x4567;
option.offMeshConCount = 1; option.offMeshConCount = 1;
meshData = NavMeshBuilder.createNavMeshData(option); meshData = NavMeshBuilder.CreateNavMeshData(option);
} }
public MeshData getMeshData() public MeshData GetMeshData()
{ {
return meshData; return meshData;
} }

View File

@ -19,7 +19,7 @@ public class DynamicNavMeshTest
[Test] [Test]
public void e2eTest() public void E2eTest()
{ {
byte[] bytes = Loader.ToBytes("test_tiles.voxels"); byte[] bytes = Loader.ToBytes("test_tiles.voxels");
using var ms = new MemoryStream(bytes); using var ms = new MemoryStream(bytes);
@ -27,51 +27,51 @@ public class DynamicNavMeshTest
// load voxels from file // load voxels from file
VoxelFileReader reader = new VoxelFileReader(); VoxelFileReader reader = new VoxelFileReader();
VoxelFile f = reader.read(bis); VoxelFile f = reader.Read(bis);
// create dynamic navmesh // create dynamic navmesh
DynamicNavMesh mesh = new DynamicNavMesh(f); DynamicNavMesh mesh = new DynamicNavMesh(f);
// build navmesh asynchronously using multiple threads // build navmesh asynchronously using multiple threads
Task<bool> future = mesh.build(Task.Factory); Task<bool> future = mesh.Build(Task.Factory);
// wait for build to complete // wait for build to complete
bool _ = future.Result; bool _ = future.Result;
// create new query // create new query
NavMeshQuery query = new NavMeshQuery(mesh.navMesh()); NavMeshQuery query = new NavMeshQuery(mesh.NavMesh());
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
// find path // find path
FindNearestPolyResult start = query.findNearestPoly(START_POS, EXTENT, filter).result; FindNearestPolyResult start = query.FindNearestPoly(START_POS, EXTENT, filter).result;
FindNearestPolyResult end = query.findNearestPoly(END_POS, EXTENT, filter).result; FindNearestPolyResult end = query.FindNearestPoly(END_POS, EXTENT, filter).result;
List<long> path = query.findPath(start.getNearestRef(), end.getNearestRef(), start.getNearestPos(), List<long> path = query.FindPath(start.GetNearestRef(), end.GetNearestRef(), start.GetNearestPos(),
end.getNearestPos(), filter, NavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue).result; end.GetNearestPos(), filter, NavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue).result;
// check path length without any obstacles // check path length without any obstacles
Assert.That(path.Count, Is.EqualTo(16)); Assert.That(path.Count, Is.EqualTo(16));
// place obstacle // place obstacle
Collider colldier = new SphereCollider(SPHERE_POS, 20, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND, 0.1f); Collider colldier = new SphereCollider(SPHERE_POS, 20, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND, 0.1f);
long colliderId = mesh.addCollider(colldier); long colliderId = mesh.AddCollider(colldier);
// update navmesh asynchronously // update navmesh asynchronously
future = mesh.update(Task.Factory); future = mesh.Update(Task.Factory);
// wait for update to complete // wait for update to complete
_ = future.Result; _ = future.Result;
// create new query // create new query
query = new NavMeshQuery(mesh.navMesh()); query = new NavMeshQuery(mesh.NavMesh());
// find path again // find path again
start = query.findNearestPoly(START_POS, EXTENT, filter).result; start = query.FindNearestPoly(START_POS, EXTENT, filter).result;
end = query.findNearestPoly(END_POS, EXTENT, filter).result; end = query.FindNearestPoly(END_POS, EXTENT, filter).result;
path = query.findPath(start.getNearestRef(), end.getNearestRef(), start.getNearestPos(), end.getNearestPos(), filter, path = query.FindPath(start.GetNearestRef(), end.GetNearestRef(), start.GetNearestPos(), end.GetNearestPos(), filter,
NavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue).result; NavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue).result;
// check path length with obstacles // check path length with obstacles
Assert.That(path.Count, Is.EqualTo(19)); Assert.That(path.Count, Is.EqualTo(19));
// remove obstacle // remove obstacle
mesh.removeCollider(colliderId); mesh.RemoveCollider(colliderId);
// update navmesh asynchronously // update navmesh asynchronously
future = mesh.update(Task.Factory); future = mesh.Update(Task.Factory);
// wait for update to complete // wait for update to complete
_ = future.Result; _ = future.Result;
// create new query // create new query
query = new NavMeshQuery(mesh.navMesh()); query = new NavMeshQuery(mesh.NavMesh());
// find path one more time // find path one more time
start = query.findNearestPoly(START_POS, EXTENT, filter).result; start = query.FindNearestPoly(START_POS, EXTENT, filter).result;
end = query.findNearestPoly(END_POS, EXTENT, filter).result; end = query.FindNearestPoly(END_POS, EXTENT, filter).result;
path = query.findPath(start.getNearestRef(), end.getNearestRef(), start.getNearestPos(), end.getNearestPos(), filter, path = query.FindPath(start.GetNearestRef(), end.GetNearestRef(), start.GetNearestPos(), end.GetNearestPos(), filter,
NavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue).result; NavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue).result;
// path length should be back to the initial value // path length should be back to the initial value
Assert.That(path.Count, Is.EqualTo(16)); Assert.That(path.Count, Is.EqualTo(16));

View File

@ -27,14 +27,14 @@ namespace DotRecast.Detour.Dynamic.Test.Io;
public class VoxelFileReaderTest public class VoxelFileReaderTest
{ {
[Test] [Test]
public void shouldReadSingleTileFile() public void ShouldReadSingleTileFile()
{ {
byte[] bytes = Loader.ToBytes("test.voxels"); byte[] bytes = Loader.ToBytes("test.voxels");
using var ms = new MemoryStream(bytes); using var ms = new MemoryStream(bytes);
using var bis = new BinaryReader(ms); using var bis = new BinaryReader(ms);
VoxelFileReader reader = new VoxelFileReader(); VoxelFileReader reader = new VoxelFileReader();
VoxelFile f = reader.read(bis); VoxelFile f = reader.Read(bis);
Assert.That(f.useTiles, Is.False); Assert.That(f.useTiles, Is.False);
Assert.That(f.bounds, Is.EqualTo(new float[] { -100.0f, 0f, -100f, 100f, 5f, 100f })); Assert.That(f.bounds, Is.EqualTo(new float[] { -100.0f, 0f, -100f, 100f, 5f, 100f }));
Assert.That(f.cellSize, Is.EqualTo(0.25f)); Assert.That(f.cellSize, Is.EqualTo(0.25f));
@ -53,14 +53,14 @@ public class VoxelFileReaderTest
} }
[Test] [Test]
public void shouldReadMultiTileFile() public void ShouldReadMultiTileFile()
{ {
byte[] bytes = Loader.ToBytes("test_tiles.voxels"); byte[] bytes = Loader.ToBytes("test_tiles.voxels");
using var ms = new MemoryStream(bytes); using var ms = new MemoryStream(bytes);
using var bis = new BinaryReader(ms); using var bis = new BinaryReader(ms);
VoxelFileReader reader = new VoxelFileReader(); VoxelFileReader reader = new VoxelFileReader();
VoxelFile f = reader.read(bis); VoxelFile f = reader.Read(bis);
Assert.That(f.useTiles, Is.True); Assert.That(f.useTiles, Is.True);
Assert.That(f.bounds, Is.EqualTo(new float[] { -100.0f, 0f, -100f, 100f, 5f, 100f })); Assert.That(f.bounds, Is.EqualTo(new float[] { -100.0f, 0f, -100f, 100f, 5f, 100f }));

View File

@ -28,13 +28,13 @@ public class VoxelFileReaderWriterTest
{ {
[TestCase(false)] [TestCase(false)]
[TestCase(true)] [TestCase(true)]
public void shouldReadSingleTileFile(bool compression) public void ShouldReadSingleTileFile(bool compression)
{ {
byte[] bytes = Loader.ToBytes("test.voxels"); byte[] bytes = Loader.ToBytes("test.voxels");
using var ms = new MemoryStream(bytes); using var ms = new MemoryStream(bytes);
using var bis = new BinaryReader(ms); using var bis = new BinaryReader(ms);
VoxelFile f = readWriteRead(bis, compression); VoxelFile f = ReadWriteRead(bis, compression);
Assert.That(f.useTiles, Is.False); Assert.That(f.useTiles, Is.False);
Assert.That(f.bounds, Is.EqualTo(new[] { -100.0f, 0f, -100f, 100f, 5f, 100f })); Assert.That(f.bounds, Is.EqualTo(new[] { -100.0f, 0f, -100f, 100f, 5f, 100f }));
Assert.That(f.cellSize, Is.EqualTo(0.25f)); Assert.That(f.cellSize, Is.EqualTo(0.25f));
@ -56,13 +56,13 @@ public class VoxelFileReaderWriterTest
[TestCase(false)] [TestCase(false)]
[TestCase(true)] [TestCase(true)]
public void shouldReadMultiTileFile(bool compression) public void ShouldReadMultiTileFile(bool compression)
{ {
byte[] bytes = Loader.ToBytes("test_tiles.voxels"); byte[] bytes = Loader.ToBytes("test_tiles.voxels");
using var ms = new MemoryStream(bytes); using var ms = new MemoryStream(bytes);
using var bis = new BinaryReader(ms); using var bis = new BinaryReader(ms);
VoxelFile f = readWriteRead(bis, compression); VoxelFile f = ReadWriteRead(bis, compression);
Assert.That(f.useTiles, Is.True); Assert.That(f.useTiles, Is.True);
Assert.That(f.bounds, Is.EqualTo(new[] { -100.0f, 0f, -100f, 100f, 5f, 100f })); Assert.That(f.bounds, Is.EqualTo(new[] { -100.0f, 0f, -100f, 100f, 5f, 100f }));
@ -85,18 +85,18 @@ public class VoxelFileReaderWriterTest
Assert.That(f.tiles[0].boundsMax, Is.EqualTo(Vector3f.Of(-78.75f, 5.0f, -78.75f))); Assert.That(f.tiles[0].boundsMax, Is.EqualTo(Vector3f.Of(-78.75f, 5.0f, -78.75f)));
} }
private VoxelFile readWriteRead(BinaryReader bis, bool compression) private VoxelFile ReadWriteRead(BinaryReader bis, bool compression)
{ {
VoxelFileReader reader = new VoxelFileReader(); VoxelFileReader reader = new VoxelFileReader();
VoxelFile f = reader.read(bis); VoxelFile f = reader.Read(bis);
using var msOut = new MemoryStream(); using var msOut = new MemoryStream();
using var bwOut = new BinaryWriter(msOut); using var bwOut = new BinaryWriter(msOut);
VoxelFileWriter writer = new VoxelFileWriter(); VoxelFileWriter writer = new VoxelFileWriter();
writer.write(bwOut, f, compression); writer.Write(bwOut, f, compression);
using var msIn = new MemoryStream(msOut.ToArray()); using var msIn = new MemoryStream(msOut.ToArray());
using var brIn = new BinaryReader(msIn); using var brIn = new BinaryReader(msIn);
return reader.read(brIn); return reader.Read(brIn);
} }
} }

View File

@ -37,7 +37,7 @@ public class VoxelQueryTest
[Test] [Test]
public void shouldTraverseTiles() public void ShouldTraverseTiles()
{ {
var hfProvider = new Mock<Func<int, int, Heightfield>>(); var hfProvider = new Mock<Func<int, int, Heightfield>>();
@ -59,7 +59,7 @@ public class VoxelQueryTest
Vector3f end = Vector3f.Of(320, 10, 57); Vector3f end = Vector3f.Of(320, 10, 57);
// When // When
query.raycast(start, end); query.Raycast(start, end);
// Then // Then
hfProvider.Verify(mock => mock.Invoke(It.IsAny<int>(), It.IsAny<int>()), Times.Exactly(6)); hfProvider.Verify(mock => mock.Invoke(It.IsAny<int>(), It.IsAny<int>()), Times.Exactly(6));
Assert.That(captorX, Is.EqualTo(new[] { 0, 1, 1, 1, 2, 2 })); Assert.That(captorX, Is.EqualTo(new[] { 0, 1, 1, 1, 2, 2 }));
@ -67,29 +67,29 @@ public class VoxelQueryTest
} }
[Test] [Test]
public void shouldHandleRaycastWithoutObstacles() public void ShouldHandleRaycastWithoutObstacles()
{ {
DynamicNavMesh mesh = createDynaMesh(); DynamicNavMesh mesh = CreateDynaMesh();
VoxelQuery query = mesh.voxelQuery(); VoxelQuery query = mesh.VoxelQuery();
Vector3f start = Vector3f.Of(7.4f, 0.5f, -64.8f); Vector3f start = Vector3f.Of(7.4f, 0.5f, -64.8f);
Vector3f end = Vector3f.Of(31.2f, 0.5f, -75.3f); Vector3f end = Vector3f.Of(31.2f, 0.5f, -75.3f);
float? hit = query.raycast(start, end); float? hit = query.Raycast(start, end);
Assert.That(hit, Is.Null); Assert.That(hit, Is.Null);
} }
[Test] [Test]
public void shouldHandleRaycastWithObstacles() public void ShouldHandleRaycastWithObstacles()
{ {
DynamicNavMesh mesh = createDynaMesh(); DynamicNavMesh mesh = CreateDynaMesh();
VoxelQuery query = mesh.voxelQuery(); VoxelQuery query = mesh.VoxelQuery();
Vector3f start = Vector3f.Of(32.3f, 0.5f, 47.9f); Vector3f start = Vector3f.Of(32.3f, 0.5f, 47.9f);
Vector3f end = Vector3f.Of(-31.2f, 0.5f, -29.8f); Vector3f end = Vector3f.Of(-31.2f, 0.5f, -29.8f);
float? hit = query.raycast(start, end); float? hit = query.Raycast(start, end);
Assert.That(hit, Is.Not.Null); Assert.That(hit, Is.Not.Null);
Assert.That(hit.Value, Is.EqualTo(0.5263836f).Within(1e-7f)); Assert.That(hit.Value, Is.EqualTo(0.5263836f).Within(1e-7f));
} }
private DynamicNavMesh createDynaMesh() private DynamicNavMesh CreateDynaMesh()
{ {
var bytes = Loader.ToBytes("test_tiles.voxels"); var bytes = Loader.ToBytes("test_tiles.voxels");
using var ms = new MemoryStream(bytes); using var ms = new MemoryStream(bytes);
@ -97,11 +97,11 @@ public class VoxelQueryTest
// load voxels from file // load voxels from file
VoxelFileReader reader = new VoxelFileReader(); VoxelFileReader reader = new VoxelFileReader();
VoxelFile f = reader.read(bis); VoxelFile f = reader.Read(bis);
// create dynamic navmesh // create dynamic navmesh
var mesh = new DynamicNavMesh(f); var mesh = new DynamicNavMesh(f);
// build navmesh asynchronously using multiple threads // build navmesh asynchronously using multiple threads
Task<bool> future = mesh.build(Task.Factory); Task<bool> future = mesh.Build(Task.Factory);
// wait for build to complete // wait for build to complete
var _ = future.Result; var _ = future.Result;
return mesh; return mesh;

View File

@ -31,53 +31,53 @@ namespace DotRecast.Detour.Extras.Test.Unity.Astar;
public class UnityAStarPathfindingImporterTest public class UnityAStarPathfindingImporterTest
{ {
[Test] [Test]
public void test_v4_0_6() public void Test_v4_0_6()
{ {
NavMesh mesh = loadNavMesh("graph.zip"); NavMesh mesh = LoadNavMesh("graph.zip");
Vector3f startPos = Vector3f.Of(8.200293f, 2.155071f, -26.176147f); Vector3f startPos = Vector3f.Of(8.200293f, 2.155071f, -26.176147f);
Vector3f endPos = Vector3f.Of(11.971109f, 0.000000f, 8.663261f); Vector3f endPos = Vector3f.Of(11.971109f, 0.000000f, 8.663261f);
Result<List<long>> path = findPath(mesh, startPos, endPos); Result<List<long>> path = FindPath(mesh, startPos, endPos);
Assert.That(path.status, Is.EqualTo(Status.SUCCSESS)); Assert.That(path.status, Is.EqualTo(Status.SUCCSESS));
Assert.That(path.result.Count, Is.EqualTo(57)); Assert.That(path.result.Count, Is.EqualTo(57));
saveMesh(mesh, "v4_0_6"); SaveMesh(mesh, "v4_0_6");
} }
[Test] [Test]
public void test_v4_1_16() public void Test_v4_1_16()
{ {
NavMesh mesh = loadNavMesh("graph_v4_1_16.zip"); NavMesh mesh = LoadNavMesh("graph_v4_1_16.zip");
Vector3f startPos = Vector3f.Of(22.93f, -2.37f, -5.11f); Vector3f startPos = Vector3f.Of(22.93f, -2.37f, -5.11f);
Vector3f endPos = Vector3f.Of(16.81f, -2.37f, 25.52f); Vector3f endPos = Vector3f.Of(16.81f, -2.37f, 25.52f);
Result<List<long>> path = findPath(mesh, startPos, endPos); Result<List<long>> path = FindPath(mesh, startPos, endPos);
Assert.That(path.status.isSuccess(), Is.True); Assert.That(path.status.IsSuccess(), Is.True);
Assert.That(path.result.Count, Is.EqualTo(15)); Assert.That(path.result.Count, Is.EqualTo(15));
saveMesh(mesh, "v4_1_16"); SaveMesh(mesh, "v4_1_16");
} }
[Test] [Test]
public void testBoundsTree() public void TestBoundsTree()
{ {
NavMesh mesh = loadNavMesh("test_boundstree.zip"); NavMesh mesh = LoadNavMesh("test_boundstree.zip");
Vector3f position = Vector3f.Of(387.52988f, 19.997f, 368.86282f); Vector3f position = Vector3f.Of(387.52988f, 19.997f, 368.86282f);
int[] tilePos = mesh.calcTileLoc(position); int[] tilePos = mesh.CalcTileLoc(position);
long tileRef = mesh.getTileRefAt(tilePos[0], tilePos[1], 0); long tileRef = mesh.GetTileRefAt(tilePos[0], tilePos[1], 0);
MeshTile tile = mesh.getTileByRef(tileRef); MeshTile tile = mesh.GetTileByRef(tileRef);
MeshData data = tile.data; MeshData data = tile.data;
BVNode[] bvNodes = data.bvTree; BVNode[] bvNodes = data.bvTree;
data.bvTree = null; // set BV-Tree empty to get 'clear' search poly without BV data.bvTree = null; // set BV-Tree empty to get 'clear' search poly without BV
FindNearestPolyResult clearResult = getNearestPolys(mesh, position)[0]; // check poly to exists FindNearestPolyResult clearResult = GetNearestPolys(mesh, position)[0]; // check poly to exists
// restore BV-Tree and try search again // restore BV-Tree and try search again
// important aspect in that test: BV result must equals result without BV // important aspect in that test: BV result must equals result without BV
// if poly not found or found other poly - tile bounds is wrong! // if poly not found or found other poly - tile bounds is wrong!
data.bvTree = bvNodes; data.bvTree = bvNodes;
FindNearestPolyResult bvResult = getNearestPolys(mesh, position)[0]; FindNearestPolyResult bvResult = GetNearestPolys(mesh, position)[0];
Assert.That(bvResult.getNearestRef(), Is.EqualTo(clearResult.getNearestRef())); Assert.That(bvResult.GetNearestRef(), Is.EqualTo(clearResult.GetNearestRef()));
} }
private NavMesh loadNavMesh(string filename) private NavMesh LoadNavMesh(string filename)
{ {
var filepath = Loader.ToRPath(filename); var filepath = Loader.ToRPath(filename);
using var fs = new FileStream(filepath, FileMode.Open, FileAccess.Read); using var fs = new FileStream(filepath, FileMode.Open, FileAccess.Read);
@ -85,21 +85,21 @@ public class UnityAStarPathfindingImporterTest
// Import the graphs // Import the graphs
UnityAStarPathfindingImporter importer = new UnityAStarPathfindingImporter(); UnityAStarPathfindingImporter importer = new UnityAStarPathfindingImporter();
NavMesh[] meshes = importer.load(fs); NavMesh[] meshes = importer.Load(fs);
return meshes[0]; return meshes[0];
} }
private Result<List<long>> findPath(NavMesh mesh, Vector3f startPos, Vector3f endPos) private Result<List<long>> FindPath(NavMesh mesh, Vector3f startPos, Vector3f endPos)
{ {
// Perform a simple pathfinding // Perform a simple pathfinding
NavMeshQuery query = new NavMeshQuery(mesh); NavMeshQuery query = new NavMeshQuery(mesh);
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
FindNearestPolyResult[] polys = getNearestPolys(mesh, startPos, endPos); FindNearestPolyResult[] polys = GetNearestPolys(mesh, startPos, endPos);
return query.findPath(polys[0].getNearestRef(), polys[1].getNearestRef(), startPos, endPos, filter); return query.FindPath(polys[0].GetNearestRef(), polys[1].GetNearestRef(), startPos, endPos, filter);
} }
private FindNearestPolyResult[] getNearestPolys(NavMesh mesh, params Vector3f[] positions) private FindNearestPolyResult[] GetNearestPolys(NavMesh mesh, params Vector3f[] positions)
{ {
NavMeshQuery query = new NavMeshQuery(mesh); NavMeshQuery query = new NavMeshQuery(mesh);
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
@ -109,21 +109,21 @@ public class UnityAStarPathfindingImporterTest
for (int i = 0; i < results.Length; i++) for (int i = 0; i < results.Length; i++)
{ {
Vector3f position = positions[i]; Vector3f position = positions[i];
Result<FindNearestPolyResult> result = query.findNearestPoly(position, extents, filter); Result<FindNearestPolyResult> result = query.FindNearestPoly(position, extents, filter);
Assert.That(result.Succeeded(), Is.True); Assert.That(result.Succeeded(), Is.True);
Assert.That(result.result.getNearestPos(), Is.Not.EqualTo(Vector3f.Zero), "Nearest start position is null!"); Assert.That(result.result.GetNearestPos(), Is.Not.EqualTo(Vector3f.Zero), "Nearest start position is null!");
results[i] = result.result; results[i] = result.result;
} }
return results; return results;
} }
private void saveMesh(NavMesh mesh, string filePostfix) private void SaveMesh(NavMesh mesh, string filePostfix)
{ {
// Set the flag to RecastDemo work properly // Set the flag to RecastDemo work properly
for (int i = 0; i < mesh.getTileCount(); i++) for (int i = 0; i < mesh.GetTileCount(); i++)
{ {
foreach (Poly p in mesh.getTile(i).data.polys) foreach (Poly p in mesh.GetTile(i).data.polys)
{ {
p.flags = 1; p.flags = 1;
} }
@ -135,6 +135,6 @@ public class UnityAStarPathfindingImporterTest
string filepath = Path.Combine("test-output", filename); string filepath = Path.Combine("test-output", filename);
using var fs = new FileStream(filename, FileMode.Create); using var fs = new FileStream(filename, FileMode.Create);
using var os = new BinaryWriter(fs); using var os = new BinaryWriter(fs);
writer.write(os, mesh, ByteOrder.LITTLE_ENDIAN, true); writer.Write(os, mesh, ByteOrder.LITTLE_ENDIAN, true);
} }
} }

View File

@ -56,14 +56,14 @@ public abstract class AbstractDetourTest
protected NavMesh navmesh; protected NavMesh navmesh;
[SetUp] [SetUp]
public void setUp() public void SetUp()
{ {
navmesh = createNavMesh(); navmesh = CreateNavMesh();
query = new NavMeshQuery(navmesh); query = new NavMeshQuery(navmesh);
} }
protected NavMesh createNavMesh() protected NavMesh CreateNavMesh()
{ {
return new NavMesh(new RecastTestMeshBuilder().getMeshData(), 6, 0); return new NavMesh(new RecastTestMeshBuilder().GetMeshData(), 6, 0);
} }
} }

View File

@ -24,21 +24,21 @@ namespace DotRecast.Detour.Test;
public class ConvexConvexIntersectionTest public class ConvexConvexIntersectionTest
{ {
[Test] [Test]
public void shouldHandleSamePolygonIntersection() public void ShouldHandleSamePolygonIntersection()
{ {
float[] p = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 }; float[] p = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
float[] q = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 }; float[] q = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
float[] intersection = ConvexConvexIntersection.intersect(p, q); float[] intersection = ConvexConvexIntersection.Intersect(p, q);
Assert.That(intersection.Length, Is.EqualTo(5 * 3)); Assert.That(intersection.Length, Is.EqualTo(5 * 3));
Assert.That(intersection, Is.EqualTo(p)); Assert.That(intersection, Is.EqualTo(p));
} }
[Test] [Test]
public void shouldHandleIntersection() public void ShouldHandleIntersection()
{ {
float[] p = { -5, 0, -5, -5, 0, 4, 1, 0, 4, 1, 0, -5 }; float[] p = { -5, 0, -5, -5, 0, 4, 1, 0, 4, 1, 0, -5 };
float[] q = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 }; float[] q = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
float[] intersection = ConvexConvexIntersection.intersect(p, q); float[] intersection = ConvexConvexIntersection.Intersect(p, q);
Assert.That(intersection.Length, Is.EqualTo(5 * 3)); Assert.That(intersection.Length, Is.EqualTo(5 * 3));
Assert.That(intersection, Is.EqualTo(new[] { 1, 0, 3, 1, 0, -3.4f, -2, 0, -4, -4, 0, 0, -3, 0, 3 })); Assert.That(intersection, Is.EqualTo(new[] { 1, 0, 3, 1, 0, -3.4f, -2, 0, -4, -4, 0, 0, -3, 0, 3 }));
} }

View File

@ -46,23 +46,23 @@ public class FindDistanceToWallTest : AbstractDetourTest
}; };
[Test] [Test]
public void testFindDistanceToWall() public void TestFindDistanceToWall()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
{ {
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Result<FindDistanceToWallResult> result = query.findDistanceToWall(startRefs[i], startPos, 3.5f, filter); Result<FindDistanceToWallResult> result = query.FindDistanceToWall(startRefs[i], startPos, 3.5f, filter);
FindDistanceToWallResult hit = result.result; FindDistanceToWallResult hit = result.result;
Assert.That(hit.getDistance(), Is.EqualTo(DISTANCES_TO_WALL[i]).Within(0.001f)); Assert.That(hit.GetDistance(), Is.EqualTo(DISTANCES_TO_WALL[i]).Within(0.001f));
Assert.That(hit.getPosition().x, Is.EqualTo(HIT_POSITION[i].x).Within(0.001f)); Assert.That(hit.GetPosition().x, Is.EqualTo(HIT_POSITION[i].x).Within(0.001f));
Assert.That(hit.getPosition().y, Is.EqualTo(HIT_POSITION[i].y).Within(0.001f)); Assert.That(hit.GetPosition().y, Is.EqualTo(HIT_POSITION[i].y).Within(0.001f));
Assert.That(hit.getPosition().z, Is.EqualTo(HIT_POSITION[i].z).Within(0.001f)); Assert.That(hit.GetPosition().z, Is.EqualTo(HIT_POSITION[i].z).Within(0.001f));
Assert.That(hit.getNormal().x, Is.EqualTo(HIT_NORMAL[i].x).Within(0.001f)); Assert.That(hit.GetNormal().x, Is.EqualTo(HIT_NORMAL[i].x).Within(0.001f));
Assert.That(hit.getNormal().y, Is.EqualTo(HIT_NORMAL[i].y).Within(0.001f)); Assert.That(hit.GetNormal().y, Is.EqualTo(HIT_NORMAL[i].y).Within(0.001f));
Assert.That(hit.getNormal().z, Is.EqualTo(HIT_NORMAL[i].z).Within(0.001f)); Assert.That(hit.GetNormal().z, Is.EqualTo(HIT_NORMAL[i].z).Within(0.001f));
} }
} }
} }

View File

@ -52,17 +52,17 @@ public class FindLocalNeighbourhoodTest : AbstractDetourTest
}; };
[Test] [Test]
public void testFindNearestPoly() public void TestFindNearestPoly()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
{ {
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Result<FindLocalNeighbourhoodResult> poly = query.findLocalNeighbourhood(startRefs[i], startPos, 3.5f, filter); Result<FindLocalNeighbourhoodResult> poly = query.FindLocalNeighbourhood(startRefs[i], startPos, 3.5f, filter);
Assert.That(poly.result.getRefs().Count, Is.EqualTo(REFS[i].Length)); Assert.That(poly.result.GetRefs().Count, Is.EqualTo(REFS[i].Length));
for (int v = 0; v < REFS[i].Length; v++) for (int v = 0; v < REFS[i].Length; v++)
{ {
Assert.That(poly.result.getRefs()[v], Is.EqualTo(REFS[i][v])); Assert.That(poly.result.GetRefs()[v], Is.EqualTo(REFS[i][v]));
} }
} }
} }

View File

@ -35,31 +35,31 @@ public class FindNearestPolyTest : AbstractDetourTest
}; };
[Test] [Test]
public void testFindNearestPoly() public void TestFindNearestPoly()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
Vector3f extents = Vector3f.Of(2, 4, 2); Vector3f extents = Vector3f.Of(2, 4, 2);
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
{ {
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Result<FindNearestPolyResult> poly = query.findNearestPoly(startPos, extents, filter); Result<FindNearestPolyResult> poly = query.FindNearestPoly(startPos, extents, filter);
Assert.That(poly.Succeeded(), Is.True); Assert.That(poly.Succeeded(), Is.True);
Assert.That(poly.result.getNearestRef(), Is.EqualTo(POLY_REFS[i])); Assert.That(poly.result.GetNearestRef(), Is.EqualTo(POLY_REFS[i]));
for (int v = 0; v < POLY_POS[i].Length; v++) for (int v = 0; v < POLY_POS[i].Length; v++)
{ {
Assert.That(poly.result.getNearestPos()[v], Is.EqualTo(POLY_POS[i][v]).Within(0.001f)); Assert.That(poly.result.GetNearestPos()[v], Is.EqualTo(POLY_POS[i][v]).Within(0.001f));
} }
} }
} }
public class EmptyQueryFilter : QueryFilter public class EmptyQueryFilter : QueryFilter
{ {
public bool passFilter(long refs, MeshTile tile, Poly poly) public bool PassFilter(long refs, MeshTile tile, Poly poly)
{ {
return false; return false;
} }
public float getCost(Vector3f pa, Vector3f pb, long prevRef, MeshTile prevTile, Poly prevPoly, long curRef, MeshTile curTile, public float GetCost(Vector3f pa, Vector3f pb, long prevRef, MeshTile prevTile, Poly prevPoly, long curRef, MeshTile curTile,
Poly curPoly, long nextRef, MeshTile nextTile, Poly nextPoly) Poly curPoly, long nextRef, MeshTile nextTile, Poly nextPoly)
{ {
return 0; return 0;
@ -67,19 +67,19 @@ public class FindNearestPolyTest : AbstractDetourTest
} }
[Test] [Test]
public void shouldReturnStartPosWhenNoPolyIsValid() public void ShouldReturnStartPosWhenNoPolyIsValid()
{ {
var filter = new EmptyQueryFilter(); var filter = new EmptyQueryFilter();
Vector3f extents = Vector3f.Of(2, 4, 2); Vector3f extents = Vector3f.Of(2, 4, 2);
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
{ {
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Result<FindNearestPolyResult> poly = query.findNearestPoly(startPos, extents, filter); Result<FindNearestPolyResult> poly = query.FindNearestPoly(startPos, extents, filter);
Assert.That(poly.Succeeded(), Is.True); Assert.That(poly.Succeeded(), Is.True);
Assert.That(poly.result.getNearestRef(), Is.EqualTo(0L)); Assert.That(poly.result.GetNearestRef(), Is.EqualTo(0L));
for (int v = 0; v < POLY_POS[i].Length; v++) for (int v = 0; v < POLY_POS[i].Length; v++)
{ {
Assert.That(poly.result.getNearestPos()[v], Is.EqualTo(startPos[v]).Within(0.001f)); Assert.That(poly.result.GetNearestPos()[v], Is.EqualTo(startPos[v]).Within(0.001f));
} }
} }
} }

View File

@ -129,7 +129,7 @@ public class FindPathTest : AbstractDetourTest
}; };
[Test] [Test]
public void testFindPath() public void TestFindPath()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
@ -138,7 +138,7 @@ public class FindPathTest : AbstractDetourTest
long endRef = endRefs[i]; long endRef = endRefs[i];
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Vector3f endPos = endPoss[i]; Vector3f endPos = endPoss[i];
Result<List<long>> path = query.findPath(startRef, endRef, startPos, endPos, filter); Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter);
Assert.That(path.status, Is.EqualTo(STATUSES[i])); Assert.That(path.status, Is.EqualTo(STATUSES[i]));
Assert.That(path.result.Count, Is.EqualTo(RESULTS[i].Length)); Assert.That(path.result.Count, Is.EqualTo(RESULTS[i].Length));
for (int j = 0; j < RESULTS[i].Length; j++) for (int j = 0; j < RESULTS[i].Length; j++)
@ -149,7 +149,7 @@ public class FindPathTest : AbstractDetourTest
} }
[Test] [Test]
public void testFindPathSliced() public void TestFindPathSliced()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
@ -158,15 +158,15 @@ public class FindPathTest : AbstractDetourTest
long endRef = endRefs[i]; long endRef = endRefs[i];
var startPos = startPoss[i]; var startPos = startPoss[i];
var endPos = endPoss[i]; var endPos = endPoss[i];
query.initSlicedFindPath(startRef, endRef, startPos, endPos, filter, NavMeshQuery.DT_FINDPATH_ANY_ANGLE); query.InitSlicedFindPath(startRef, endRef, startPos, endPos, filter, NavMeshQuery.DT_FINDPATH_ANY_ANGLE);
Status status = Status.IN_PROGRESS; Status status = Status.IN_PROGRESS;
while (status == Status.IN_PROGRESS) while (status == Status.IN_PROGRESS)
{ {
Result<int> res = query.updateSlicedFindPath(10); Result<int> res = query.UpdateSlicedFindPath(10);
status = res.status; status = res.status;
} }
Result<List<long>> path = query.finalizeSlicedFindPath(); Result<List<long>> path = query.FinalizeSlicedFindPath();
Assert.That(path.status, Is.EqualTo(STATUSES[i])); Assert.That(path.status, Is.EqualTo(STATUSES[i]));
Assert.That(path.result.Count, Is.EqualTo(RESULTS[i].Length)); Assert.That(path.result.Count, Is.EqualTo(RESULTS[i].Length));
for (int j = 0; j < RESULTS[i].Length; j++) for (int j = 0; j < RESULTS[i].Length; j++)
@ -177,7 +177,7 @@ public class FindPathTest : AbstractDetourTest
} }
[Test] [Test]
public void testFindPathStraight() public void TestFindPathStraight()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < STRAIGHT_PATHS.Length; i++) for (int i = 0; i < STRAIGHT_PATHS.Length; i++)
@ -187,8 +187,8 @@ public class FindPathTest : AbstractDetourTest
long endRef = endRefs[i]; long endRef = endRefs[i];
var startPos = startPoss[i]; var startPos = startPoss[i];
var endPos = endPoss[i]; var endPos = endPoss[i];
Result<List<long>> path = query.findPath(startRef, endRef, startPos, endPos, filter); Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter);
Result<List<StraightPathItem>> result = query.findStraightPath(startPos, endPos, path.result, Result<List<StraightPathItem>> result = query.FindStraightPath(startPos, endPos, path.result,
int.MaxValue, 0); int.MaxValue, 0);
List<StraightPathItem> straightPath = result.result; List<StraightPathItem> straightPath = result.result;
Assert.That(straightPath.Count, Is.EqualTo(STRAIGHT_PATHS[i].Length)); Assert.That(straightPath.Count, Is.EqualTo(STRAIGHT_PATHS[i].Length));

View File

@ -99,26 +99,26 @@ public class FindPolysAroundCircleTest : AbstractDetourTest
}; };
[Test] [Test]
public void testFindPolysAroundCircle() public void TestFindPolysAroundCircle()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
{ {
long startRef = startRefs[i]; long startRef = startRefs[i];
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Result<FindPolysAroundResult> result = query.findPolysAroundCircle(startRef, startPos, 7.5f, filter); Result<FindPolysAroundResult> result = query.FindPolysAroundCircle(startRef, startPos, 7.5f, filter);
Assert.That(result.Succeeded(), Is.True); Assert.That(result.Succeeded(), Is.True);
FindPolysAroundResult polys = result.result; FindPolysAroundResult polys = result.result;
Assert.That(polys.getRefs().Count, Is.EqualTo(REFS[i].Length)); Assert.That(polys.GetRefs().Count, Is.EqualTo(REFS[i].Length));
for (int v = 0; v < REFS[i].Length; v++) for (int v = 0; v < REFS[i].Length; v++)
{ {
bool found = false; bool found = false;
for (int w = 0; w < REFS[i].Length; w++) for (int w = 0; w < REFS[i].Length; w++)
{ {
if (REFS[i][v] == polys.getRefs()[w]) if (REFS[i][v] == polys.GetRefs()[w])
{ {
Assert.That(polys.getParentRefs()[w], Is.EqualTo(PARENT_REFS[i][v])); Assert.That(polys.GetParentRefs()[w], Is.EqualTo(PARENT_REFS[i][v]));
Assert.That(polys.getCosts()[w], Is.EqualTo(COSTS[i][v]).Within(0.01f)); Assert.That(polys.GetCosts()[w], Is.EqualTo(COSTS[i][v]).Within(0.01f));
found = true; found = true;
} }
} }

View File

@ -126,24 +126,24 @@ public class FindPolysAroundShapeTest : AbstractDetourTest
}; };
[Test] [Test]
public void testFindPolysAroundShape() public void TestFindPolysAroundShape()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
{ {
long startRef = startRefs[i]; long startRef = startRefs[i];
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Result<FindPolysAroundResult> polys = query.findPolysAroundShape(startRef, getQueryPoly(startPos, endPoss[i]), filter); Result<FindPolysAroundResult> polys = query.FindPolysAroundShape(startRef, GetQueryPoly(startPos, endPoss[i]), filter);
Assert.That(polys.result.getRefs().Count, Is.EqualTo(REFS[i].Length)); Assert.That(polys.result.GetRefs().Count, Is.EqualTo(REFS[i].Length));
for (int v = 0; v < REFS[i].Length; v++) for (int v = 0; v < REFS[i].Length; v++)
{ {
bool found = false; bool found = false;
for (int w = 0; w < REFS[i].Length; w++) for (int w = 0; w < REFS[i].Length; w++)
{ {
if (REFS[i][v] == polys.result.getRefs()[w]) if (REFS[i][v] == polys.result.GetRefs()[w])
{ {
Assert.That(polys.result.getParentRefs()[w], Is.EqualTo(PARENT_REFS[i][v])); Assert.That(polys.result.GetParentRefs()[w], Is.EqualTo(PARENT_REFS[i][v]));
Assert.That(polys.result.getCosts()[w], Is.EqualTo(COSTS[i][v]).Within(0.01f)); Assert.That(polys.result.GetCosts()[w], Is.EqualTo(COSTS[i][v]).Within(0.01f));
found = true; found = true;
} }
} }
@ -153,7 +153,7 @@ public class FindPolysAroundShapeTest : AbstractDetourTest
} }
} }
private float[] getQueryPoly(Vector3f m_spos, Vector3f m_epos) private float[] GetQueryPoly(Vector3f m_spos, Vector3f m_epos)
{ {
float nx = (m_epos.z - m_spos.z) * 0.25f; float nx = (m_epos.z - m_spos.z) * 0.25f;
float nz = -(m_epos.x - m_spos.x) * 0.25f; float nz = -(m_epos.x - m_spos.x) * 0.25f;

View File

@ -75,26 +75,26 @@ public class GetPolyWallSegmentsTest : AbstractDetourTest
}; };
[Test] [Test]
public void testFindDistanceToWall() public void TestFindDistanceToWall()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
{ {
Result<GetPolyWallSegmentsResult> result = query.getPolyWallSegments(startRefs[i], true, filter); Result<GetPolyWallSegmentsResult> result = query.GetPolyWallSegments(startRefs[i], true, filter);
GetPolyWallSegmentsResult segments = result.result; GetPolyWallSegmentsResult segments = result.result;
Assert.That(segments.countSegmentVerts(), Is.EqualTo(VERTICES[i].Length / 6)); Assert.That(segments.CountSegmentVerts(), Is.EqualTo(VERTICES[i].Length / 6));
Assert.That(segments.countSegmentRefs(), Is.EqualTo(REFS[i].Length)); Assert.That(segments.CountSegmentRefs(), Is.EqualTo(REFS[i].Length));
for (int v = 0; v < VERTICES[i].Length / 6; v++) for (int v = 0; v < VERTICES[i].Length / 6; v++)
{ {
for (int n = 0; n < 6; n++) for (int n = 0; n < 6; n++)
{ {
Assert.That(segments.getSegmentVert(v)[n], Is.EqualTo(VERTICES[i][v * 6 + n]).Within(0.001f)); Assert.That(segments.GetSegmentVert(v)[n], Is.EqualTo(VERTICES[i][v * 6 + n]).Within(0.001f));
} }
} }
for (int v = 0; v < REFS[i].Length; v++) for (int v = 0; v < REFS[i].Length; v++)
{ {
Assert.That(segments.getSegmentRef(v), Is.EqualTo(REFS[i][v])); Assert.That(segments.GetSegmentRef(v), Is.EqualTo(REFS[i][v]));
} }
} }
} }

View File

@ -30,48 +30,48 @@ public class MeshDataReaderWriterTest
private MeshData meshData; private MeshData meshData;
[SetUp] [SetUp]
public void setUp() public void SetUp()
{ {
RecastTestMeshBuilder rcBuilder = new RecastTestMeshBuilder(); RecastTestMeshBuilder rcBuilder = new RecastTestMeshBuilder();
meshData = rcBuilder.getMeshData(); meshData = rcBuilder.GetMeshData();
} }
[Test] [Test]
public void testCCompatibility() public void TestCCompatibility()
{ {
test(true, ByteOrder.BIG_ENDIAN); Test(true, ByteOrder.BIG_ENDIAN);
} }
[Test] [Test]
public void testCompact() public void TestCompact()
{ {
test(false, ByteOrder.BIG_ENDIAN); Test(false, ByteOrder.BIG_ENDIAN);
} }
[Test] [Test]
public void testCCompatibilityLE() public void TestCCompatibilityLE()
{ {
test(true, ByteOrder.LITTLE_ENDIAN); Test(true, ByteOrder.LITTLE_ENDIAN);
} }
[Test] [Test]
public void testCompactLE() public void TestCompactLE()
{ {
test(false, ByteOrder.LITTLE_ENDIAN); Test(false, ByteOrder.LITTLE_ENDIAN);
} }
public void test(bool cCompatibility, ByteOrder order) public void Test(bool cCompatibility, ByteOrder order)
{ {
using var ms = new MemoryStream(); using var ms = new MemoryStream();
using var bwos = new BinaryWriter(ms); using var bwos = new BinaryWriter(ms);
MeshDataWriter writer = new MeshDataWriter(); MeshDataWriter writer = new MeshDataWriter();
writer.write(bwos, meshData, order, cCompatibility); writer.Write(bwos, meshData, order, cCompatibility);
ms.Seek(0, SeekOrigin.Begin); ms.Seek(0, SeekOrigin.Begin);
using var bris = new BinaryReader(ms); using var bris = new BinaryReader(ms);
MeshDataReader reader = new MeshDataReader(); MeshDataReader reader = new MeshDataReader();
MeshData readData = reader.read(bris, VERTS_PER_POLYGON); MeshData readData = reader.Read(bris, VERTS_PER_POLYGON);
Assert.That(readData.header.vertCount, Is.EqualTo(meshData.header.vertCount)); Assert.That(readData.header.vertCount, Is.EqualTo(meshData.header.vertCount));
Assert.That(readData.header.polyCount, Is.EqualTo(meshData.header.polyCount)); Assert.That(readData.header.polyCount, Is.EqualTo(meshData.header.polyCount));

View File

@ -30,86 +30,86 @@ public class MeshSetReaderTest
private readonly MeshSetReader reader = new MeshSetReader(); private readonly MeshSetReader reader = new MeshSetReader();
[Test] [Test]
public void testNavmesh() public void TestNavmesh()
{ {
byte[] @is = Loader.ToBytes("all_tiles_navmesh.bin"); byte[] @is = Loader.ToBytes("all_tiles_navmesh.bin");
using var ms = new MemoryStream(@is); using var ms = new MemoryStream(@is);
using var bris = new BinaryReader(ms); using var bris = new BinaryReader(ms);
NavMesh mesh = reader.read(bris, 6); NavMesh mesh = reader.Read(bris, 6);
Assert.That(mesh.getMaxTiles(), Is.EqualTo(128)); Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128));
Assert.That(mesh.getParams().maxPolys, Is.EqualTo(0x8000)); Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000));
Assert.That(mesh.getParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f)); Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
List<MeshTile> tiles = mesh.getTilesAt(4, 7); List<MeshTile> tiles = mesh.GetTilesAt(4, 7);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(7)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(7));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(22 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(22 * 3));
tiles = mesh.getTilesAt(1, 6); tiles = mesh.GetTilesAt(1, 6);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(7)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(7));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(26 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(26 * 3));
tiles = mesh.getTilesAt(6, 2); tiles = mesh.GetTilesAt(6, 2);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(1));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(4 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(4 * 3));
tiles = mesh.getTilesAt(7, 6); tiles = mesh.GetTilesAt(7, 6);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(8)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(8));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(24 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(24 * 3));
} }
[Test] [Test]
public void testDungeon() public void TestDungeon()
{ {
byte[] @is = Loader.ToBytes("dungeon_all_tiles_navmesh.bin"); byte[] @is = Loader.ToBytes("dungeon_all_tiles_navmesh.bin");
using var ms = new MemoryStream(@is); using var ms = new MemoryStream(@is);
using var bris = new BinaryReader(ms); using var bris = new BinaryReader(ms);
NavMesh mesh = reader.read(bris, 6); NavMesh mesh = reader.Read(bris, 6);
Assert.That(mesh.getMaxTiles(), Is.EqualTo(128)); Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128));
Assert.That(mesh.getParams().maxPolys, Is.EqualTo(0x8000)); Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000));
Assert.That(mesh.getParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f)); Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
List<MeshTile> tiles = mesh.getTilesAt(6, 9); List<MeshTile> tiles = mesh.GetTilesAt(6, 9);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(7 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(7 * 3));
tiles = mesh.getTilesAt(2, 9); tiles = mesh.GetTilesAt(2, 9);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(9 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(9 * 3));
tiles = mesh.getTilesAt(4, 3); tiles = mesh.GetTilesAt(4, 3);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(3)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(3));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(6 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(6 * 3));
tiles = mesh.getTilesAt(2, 8); tiles = mesh.GetTilesAt(2, 8);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(5)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(5));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3));
} }
[Test] [Test]
public void testDungeon32Bit() public void TestDungeon32Bit()
{ {
byte[] @is = Loader.ToBytes("dungeon_all_tiles_navmesh_32bit.bin"); byte[] @is = Loader.ToBytes("dungeon_all_tiles_navmesh_32bit.bin");
using var ms = new MemoryStream(@is); using var ms = new MemoryStream(@is);
using var bris = new BinaryReader(ms); using var bris = new BinaryReader(ms);
NavMesh mesh = reader.read32Bit(bris, 6); NavMesh mesh = reader.Read32Bit(bris, 6);
Assert.That(mesh.getMaxTiles(), Is.EqualTo(128)); Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128));
Assert.That(mesh.getParams().maxPolys, Is.EqualTo(0x8000)); Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000));
Assert.That(mesh.getParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f)); Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
List<MeshTile> tiles = mesh.getTilesAt(6, 9); List<MeshTile> tiles = mesh.GetTilesAt(6, 9);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(7 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(7 * 3));
tiles = mesh.getTilesAt(2, 9); tiles = mesh.GetTilesAt(2, 9);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(9 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(9 * 3));
tiles = mesh.getTilesAt(4, 3); tiles = mesh.GetTilesAt(4, 3);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(3)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(3));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(6 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(6 * 3));
tiles = mesh.getTilesAt(2, 8); tiles = mesh.GetTilesAt(2, 8);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(5)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(5));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3));

View File

@ -52,14 +52,14 @@ public class MeshSetReaderWriterTest
private const int m_maxPolysPerTile = 0x8000; private const int m_maxPolysPerTile = 0x8000;
[Test] [Test]
public void test() public void Test()
{ {
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("dungeon.obj")); InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
NavMeshSetHeader header = new NavMeshSetHeader(); NavMeshSetHeader header = new NavMeshSetHeader();
header.magic = NavMeshSetHeader.NAVMESHSET_MAGIC; header.magic = NavMeshSetHeader.NAVMESHSET_MAGIC;
header.version = NavMeshSetHeader.NAVMESHSET_VERSION; header.version = NavMeshSetHeader.NAVMESHSET_VERSION;
header.option.orig = geom.getMeshBoundsMin(); header.option.orig = geom.GetMeshBoundsMin();
header.option.tileWidth = m_tileSize * m_cellSize; header.option.tileWidth = m_tileSize * m_cellSize;
header.option.tileHeight = m_tileSize * m_cellSize; header.option.tileHeight = m_tileSize * m_cellSize;
header.option.maxTiles = m_maxTiles; header.option.maxTiles = m_maxTiles;
@ -67,9 +67,9 @@ public class MeshSetReaderWriterTest
header.numTiles = 0; header.numTiles = 0;
NavMesh mesh = new NavMesh(header.option, 6); NavMesh mesh = new NavMesh(header.option, 6);
Vector3f bmin = geom.getMeshBoundsMin(); Vector3f bmin = geom.GetMeshBoundsMin();
Vector3f bmax = geom.getMeshBoundsMax(); Vector3f bmax = geom.GetMeshBoundsMax();
int[] twh = DotRecast.Recast.Recast.calcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize); int[] twh = DotRecast.Recast.Recast.CalcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize);
int tw = twh[0]; int tw = twh[0];
int th = twh[1]; int th = twh[1];
for (int y = 0; y < th; ++y) for (int y = 0; y < th; ++y)
@ -77,44 +77,44 @@ public class MeshSetReaderWriterTest
for (int x = 0; x < tw; ++x) for (int x = 0; x < tw; ++x)
{ {
RecastConfig cfg = new RecastConfig(true, m_tileSize, m_tileSize, RecastConfig cfg = new RecastConfig(true, m_tileSize, m_tileSize,
RecastConfig.calcBorder(m_agentRadius, m_cellSize), PartitionType.WATERSHED, m_cellSize, m_cellHeight, RecastConfig.CalcBorder(m_agentRadius, m_cellSize), PartitionType.WATERSHED, m_cellSize, m_cellHeight,
m_agentMaxSlope, true, true, true, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_regionMinArea, m_agentMaxSlope, true, true, true, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_regionMinArea,
m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true, m_detailSampleDist, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true, m_detailSampleDist,
m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND); m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, bmin, bmax, x, y); RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, bmin, bmax, x, y);
TestDetourBuilder db = new TestDetourBuilder(); TestDetourBuilder db = new TestDetourBuilder();
MeshData data = db.build(geom, bcfg, m_agentHeight, m_agentRadius, m_agentMaxClimb, x, y, true); MeshData data = db.Build(geom, bcfg, m_agentHeight, m_agentRadius, m_agentMaxClimb, x, y, true);
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);
} }
} }
} }
using var ms = new MemoryStream(); using var ms = new MemoryStream();
using var os = new BinaryWriter(ms); using var os = new BinaryWriter(ms);
writer.write(os, mesh, ByteOrder.LITTLE_ENDIAN, true); writer.Write(os, mesh, ByteOrder.LITTLE_ENDIAN, true);
ms.Seek(0, SeekOrigin.Begin); ms.Seek(0, SeekOrigin.Begin);
using var @is = new BinaryReader(ms); using var @is = new BinaryReader(ms);
mesh = reader.read(@is, 6); mesh = reader.Read(@is, 6);
Assert.That(mesh.getMaxTiles(), Is.EqualTo(128)); Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128));
Assert.That(mesh.getParams().maxPolys, Is.EqualTo(0x8000)); Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000));
Assert.That(mesh.getParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f)); Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
List<MeshTile> tiles = mesh.getTilesAt(6, 9); List<MeshTile> tiles = mesh.GetTilesAt(6, 9);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(7 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(7 * 3));
tiles = mesh.getTilesAt(2, 9); tiles = mesh.GetTilesAt(2, 9);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(9 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(9 * 3));
tiles = mesh.getTilesAt(4, 3); tiles = mesh.GetTilesAt(4, 3);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(3)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(3));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(6 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(6 * 3));
tiles = mesh.getTilesAt(2, 8); tiles = mesh.GetTilesAt(2, 8);
Assert.That(tiles.Count, Is.EqualTo(1)); Assert.That(tiles.Count, Is.EqualTo(1));
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(5)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(5));
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3));

View File

@ -66,7 +66,7 @@ public class MoveAlongSurfaceTest : AbstractDetourTest
}; };
[Test] [Test]
public void testMoveAlongSurface() public void TestMoveAlongSurface()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
@ -74,18 +74,18 @@ public class MoveAlongSurfaceTest : AbstractDetourTest
long startRef = startRefs[i]; long startRef = startRefs[i];
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Vector3f endPos = endPoss[i]; Vector3f endPos = endPoss[i];
Result<MoveAlongSurfaceResult> result = query.moveAlongSurface(startRef, startPos, endPos, filter); Result<MoveAlongSurfaceResult> result = query.MoveAlongSurface(startRef, startPos, endPos, filter);
Assert.That(result.Succeeded(), Is.True); Assert.That(result.Succeeded(), Is.True);
MoveAlongSurfaceResult path = result.result; MoveAlongSurfaceResult path = result.result;
for (int v = 0; v < 3; v++) for (int v = 0; v < 3; v++)
{ {
Assert.That(path.getResultPos()[v], Is.EqualTo(POSITION[i][v]).Within(0.01f)); Assert.That(path.GetResultPos()[v], Is.EqualTo(POSITION[i][v]).Within(0.01f));
} }
Assert.That(path.getVisited().Count, Is.EqualTo(VISITED[i].Length)); Assert.That(path.GetVisited().Count, Is.EqualTo(VISITED[i].Length));
for (int j = 0; j < POSITION[i].Length; j++) for (int j = 0; j < POSITION[i].Length; j++)
{ {
Assert.That(path.getVisited()[j], Is.EqualTo(VISITED[i][j])); Assert.That(path.GetVisited()[j], Is.EqualTo(VISITED[i][j]));
} }
} }
} }

View File

@ -26,13 +26,13 @@ public class NavMeshBuilderTest
private MeshData nmd; private MeshData nmd;
[SetUp] [SetUp]
public void setUp() public void SetUp()
{ {
nmd = new RecastTestMeshBuilder().getMeshData(); nmd = new RecastTestMeshBuilder().GetMeshData();
} }
[Test] [Test]
public void testBVTree() public void TestBVTree()
{ {
Assert.That(nmd.verts.Length / 3, Is.EqualTo(225)); Assert.That(nmd.verts.Length / 3, Is.EqualTo(225));
Assert.That(nmd.polys.Length, Is.EqualTo(119)); Assert.That(nmd.polys.Length, Is.EqualTo(119));
@ -63,7 +63,7 @@ public class NavMeshBuilderTest
Assert.That(nmd.polys[118].verts[0], Is.EqualTo(223)); Assert.That(nmd.polys[118].verts[0], Is.EqualTo(223));
Assert.That(nmd.polys[118].verts[1], Is.EqualTo(224)); Assert.That(nmd.polys[118].verts[1], Is.EqualTo(224));
Assert.That(nmd.polys[118].flags, Is.EqualTo(12)); Assert.That(nmd.polys[118].flags, Is.EqualTo(12));
Assert.That(nmd.polys[118].getArea(), Is.EqualTo(2)); Assert.That(nmd.polys[118].GetArea(), Is.EqualTo(2));
Assert.That(nmd.polys[118].getType(), Is.EqualTo(Poly.DT_POLYTYPE_OFFMESH_CONNECTION)); Assert.That(nmd.polys[118].GetType(), Is.EqualTo(Poly.DT_POLYTYPE_OFFMESH_CONNECTION));
} }
} }

View File

@ -27,34 +27,34 @@ public class PolygonByCircleConstraintTest
private readonly PolygonByCircleConstraint constraint = new PolygonByCircleConstraint.StrictPolygonByCircleConstraint(); private readonly PolygonByCircleConstraint constraint = new PolygonByCircleConstraint.StrictPolygonByCircleConstraint();
[Test] [Test]
public void shouldHandlePolygonFullyInsideCircle() public void ShouldHandlePolygonFullyInsideCircle()
{ {
float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 }; float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 };
Vector3f center = Vector3f.Of(1, 0, 1); Vector3f center = Vector3f.Of(1, 0, 1);
float[] constrained = constraint.aply(polygon, center, 6); float[] constrained = constraint.Aply(polygon, center, 6);
Assert.That(constrained, Is.EqualTo(polygon)); Assert.That(constrained, Is.EqualTo(polygon));
} }
[Test] [Test]
public void shouldHandleVerticalSegment() public void ShouldHandleVerticalSegment()
{ {
int expectedSize = 21; int expectedSize = 21;
float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 }; float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 };
Vector3f center = Vector3f.Of(2, 0, 0); Vector3f center = Vector3f.Of(2, 0, 0);
float[] constrained = constraint.aply(polygon, center, 3); float[] constrained = constraint.Aply(polygon, center, 3);
Assert.That(constrained.Length, Is.EqualTo(expectedSize)); Assert.That(constrained.Length, Is.EqualTo(expectedSize));
Assert.That(constrained, Is.SupersetOf(new[] { 2f, 0f, 2f, 2f, 0f, -2f })); Assert.That(constrained, Is.SupersetOf(new[] { 2f, 0f, 2f, 2f, 0f, -2f }));
} }
[Test] [Test]
public void shouldHandleCircleFullyInsidePolygon() public void ShouldHandleCircleFullyInsidePolygon()
{ {
int expectedSize = 12 * 3; int expectedSize = 12 * 3;
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 }; float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
Vector3f center = Vector3f.Of(-1, 0, -1); Vector3f center = Vector3f.Of(-1, 0, -1);
float[] constrained = constraint.aply(polygon, center, 2); float[] constrained = constraint.Aply(polygon, center, 2);
Assert.That(constrained.Length, Is.EqualTo(expectedSize)); Assert.That(constrained.Length, Is.EqualTo(expectedSize));
@ -67,24 +67,24 @@ public class PolygonByCircleConstraintTest
} }
[Test] [Test]
public void shouldHandleCircleInsidePolygon() public void ShouldHandleCircleInsidePolygon()
{ {
int expectedSize = 9 * 3; int expectedSize = 9 * 3;
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 }; float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
Vector3f center = Vector3f.Of(-2, 0, -1); Vector3f center = Vector3f.Of(-2, 0, -1);
float[] constrained = constraint.aply(polygon, center, 3); float[] constrained = constraint.Aply(polygon, center, 3);
Assert.That(constrained.Length, Is.EqualTo(expectedSize)); Assert.That(constrained.Length, Is.EqualTo(expectedSize));
Assert.That(constrained, Is.SupersetOf(new[] { -2f, 0f, -4f, -4f, 0f, 0f, -3.4641016f, 0.0f, 1.6076951f, -2.0f, 0.0f, 2.0f })); Assert.That(constrained, Is.SupersetOf(new[] { -2f, 0f, -4f, -4f, 0f, 0f, -3.4641016f, 0.0f, 1.6076951f, -2.0f, 0.0f, 2.0f }));
} }
[Test] [Test]
public void shouldHandleCircleOutsidePolygon() public void ShouldHandleCircleOutsidePolygon()
{ {
int expectedSize = 7 * 3; int expectedSize = 7 * 3;
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 }; float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
Vector3f center = Vector3f.Of(4, 0, 0); Vector3f center = Vector3f.Of(4, 0, 0);
float[] constrained = constraint.aply(polygon, center, 4); float[] constrained = constraint.Aply(polygon, center, 4);
Assert.That(constrained.Length, Is.EqualTo(expectedSize)); Assert.That(constrained.Length, Is.EqualTo(expectedSize));
Assert.That(constrained, Is.SupersetOf(new[] { 1.5358982f, 0f, 3f, 2f, 0f, 3f, 3f, 0f, -3f })); Assert.That(constrained, Is.SupersetOf(new[] { 1.5358982f, 0f, 3f, 2f, 0f, 3f, 3f, 0f, -3f }));

View File

@ -29,15 +29,15 @@ namespace DotRecast.Detour.Test;
public class RandomPointTest : AbstractDetourTest public class RandomPointTest : AbstractDetourTest
{ {
[Test] [Test]
public void testRandom() public void TestRandom()
{ {
FRand f = new FRand(1); FRand f = new FRand(1);
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)
{ {
Result<FindRandomPointResult> point = query.findRandomPoint(filter, f); Result<FindRandomPointResult> point = query.FindRandomPoint(filter, f);
Assert.That(point.Succeeded(), Is.True); Assert.That(point.Succeeded(), Is.True);
Tuple<MeshTile, Poly> tileAndPoly = navmesh.getTileAndPolyByRef(point.result.getRandomRef()).result; Tuple<MeshTile, Poly> tileAndPoly = navmesh.GetTileAndPolyByRef(point.result.GetRandomRef()).result;
float[] bmin = new float[2]; float[] bmin = new float[2];
float[] bmax = new float[2]; float[] bmax = new float[2];
for (int j = 0; j < tileAndPoly.Item2.vertCount; j++) for (int j = 0; j < tileAndPoly.Item2.vertCount; j++)
@ -49,26 +49,26 @@ public class RandomPointTest : AbstractDetourTest
bmax[1] = j == 0 ? tileAndPoly.Item1.data.verts[v + 2] : Math.Max(bmax[1], tileAndPoly.Item1.data.verts[v + 2]); bmax[1] = j == 0 ? tileAndPoly.Item1.data.verts[v + 2] : Math.Max(bmax[1], tileAndPoly.Item1.data.verts[v + 2]);
} }
Assert.That(point.result.getRandomPt().x >= bmin[0], Is.True); Assert.That(point.result.GetRandomPt().x >= bmin[0], Is.True);
Assert.That(point.result.getRandomPt().x <= bmax[0], Is.True); Assert.That(point.result.GetRandomPt().x <= bmax[0], Is.True);
Assert.That(point.result.getRandomPt().z >= bmin[1], Is.True); Assert.That(point.result.GetRandomPt().z >= bmin[1], Is.True);
Assert.That(point.result.getRandomPt().z <= bmax[1], Is.True); Assert.That(point.result.GetRandomPt().z <= bmax[1], Is.True);
} }
} }
[Test] [Test]
public void testRandomAroundCircle() public void TestRandomAroundCircle()
{ {
FRand f = new FRand(1); FRand f = new FRand(1);
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
FindRandomPointResult point = query.findRandomPoint(filter, f).result; FindRandomPointResult point = query.FindRandomPoint(filter, f).result;
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)
{ {
Result<FindRandomPointResult> result = query.findRandomPointAroundCircle(point.getRandomRef(), point.getRandomPt(), Result<FindRandomPointResult> result = query.FindRandomPointAroundCircle(point.GetRandomRef(), point.GetRandomPt(),
5f, filter, f); 5f, filter, f);
Assert.That(result.Failed(), Is.False); Assert.That(result.Failed(), Is.False);
point = result.result; point = result.result;
Tuple<MeshTile, Poly> tileAndPoly = navmesh.getTileAndPolyByRef(point.getRandomRef()).result; Tuple<MeshTile, Poly> tileAndPoly = navmesh.GetTileAndPolyByRef(point.GetRandomRef()).result;
float[] bmin = new float[2]; float[] bmin = new float[2];
float[] bmax = new float[2]; float[] bmax = new float[2];
for (int j = 0; j < tileAndPoly.Item2.vertCount; j++) for (int j = 0; j < tileAndPoly.Item2.vertCount; j++)
@ -80,59 +80,59 @@ public class RandomPointTest : AbstractDetourTest
bmax[1] = j == 0 ? tileAndPoly.Item1.data.verts[v + 2] : Math.Max(bmax[1], tileAndPoly.Item1.data.verts[v + 2]); bmax[1] = j == 0 ? tileAndPoly.Item1.data.verts[v + 2] : Math.Max(bmax[1], tileAndPoly.Item1.data.verts[v + 2]);
} }
Assert.That(point.getRandomPt().x >= bmin[0], Is.True); Assert.That(point.GetRandomPt().x >= bmin[0], Is.True);
Assert.That(point.getRandomPt().x <= bmax[0], Is.True); Assert.That(point.GetRandomPt().x <= bmax[0], Is.True);
Assert.That(point.getRandomPt().z >= bmin[1], Is.True); Assert.That(point.GetRandomPt().z >= bmin[1], Is.True);
Assert.That(point.getRandomPt().z <= bmax[1], Is.True); Assert.That(point.GetRandomPt().z <= bmax[1], Is.True);
} }
} }
[Test] [Test]
public void testRandomWithinCircle() public void TestRandomWithinCircle()
{ {
FRand f = new FRand(1); FRand f = new FRand(1);
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
FindRandomPointResult point = query.findRandomPoint(filter, f).result; FindRandomPointResult point = query.FindRandomPoint(filter, f).result;
float radius = 5f; float radius = 5f;
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)
{ {
Result<FindRandomPointResult> result = query.findRandomPointWithinCircle(point.getRandomRef(), point.getRandomPt(), Result<FindRandomPointResult> result = query.FindRandomPointWithinCircle(point.GetRandomRef(), point.GetRandomPt(),
radius, filter, f); radius, filter, f);
Assert.That(result.Failed(), Is.False); Assert.That(result.Failed(), Is.False);
float distance = vDist2D(point.getRandomPt(), result.result.getRandomPt()); float distance = VDist2D(point.GetRandomPt(), result.result.GetRandomPt());
Assert.That(distance <= radius, Is.True); Assert.That(distance <= radius, Is.True);
point = result.result; point = result.result;
} }
} }
[Test] [Test]
public void testPerformance() public void TestPerformance()
{ {
FRand f = new FRand(1); FRand f = new FRand(1);
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
FindRandomPointResult point = query.findRandomPoint(filter, f).result; FindRandomPointResult point = query.FindRandomPoint(filter, f).result;
float radius = 5f; float radius = 5f;
// jvm warmup // jvm warmup
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)
{ {
query.findRandomPointAroundCircle(point.getRandomRef(), point.getRandomPt(), radius, filter, f); query.FindRandomPointAroundCircle(point.GetRandomRef(), point.GetRandomPt(), radius, filter, f);
} }
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)
{ {
query.findRandomPointWithinCircle(point.getRandomRef(), point.getRandomPt(), radius, filter, f); query.FindRandomPointWithinCircle(point.GetRandomRef(), point.GetRandomPt(), radius, filter, f);
} }
long t1 = FrequencyWatch.Ticks; long t1 = FrequencyWatch.Ticks;
for (int i = 0; i < 10000; i++) for (int i = 0; i < 10000; i++)
{ {
query.findRandomPointAroundCircle(point.getRandomRef(), point.getRandomPt(), radius, filter, f); query.FindRandomPointAroundCircle(point.GetRandomRef(), point.GetRandomPt(), radius, filter, f);
} }
long t2 = FrequencyWatch.Ticks; long t2 = FrequencyWatch.Ticks;
for (int i = 0; i < 10000; i++) for (int i = 0; i < 10000; i++)
{ {
query.findRandomPointWithinCircle(point.getRandomRef(), point.getRandomPt(), radius, filter, f); query.FindRandomPointWithinCircle(point.GetRandomRef(), point.GetRandomPt(), radius, filter, f);
} }
long t3 = FrequencyWatch.Ticks; long t3 = FrequencyWatch.Ticks;

View File

@ -40,7 +40,7 @@ public class RecastTestMeshBuilder
private const float m_detailSampleMaxError = 1.0f; private const float m_detailSampleMaxError = 1.0f;
public RecastTestMeshBuilder() : public RecastTestMeshBuilder() :
this(ObjImporter.load(Loader.ToBytes("dungeon.obj")), this(ObjImporter.Load(Loader.ToBytes("dungeon.obj")),
PartitionType.WATERSHED, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_agentMaxSlope, PartitionType.WATERSHED, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_agentMaxSlope,
m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist, m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist,
m_detailSampleMaxError) m_detailSampleMaxError)
@ -55,16 +55,16 @@ public class RecastTestMeshBuilder
RecastConfig cfg = new RecastConfig(m_partitionType, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, RecastConfig cfg = new RecastConfig(m_partitionType, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius,
m_agentMaxClimb, m_agentMaxSlope, m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_agentMaxClimb, m_agentMaxSlope, m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError,
m_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND); m_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, m_geom.getMeshBoundsMin(), m_geom.getMeshBoundsMax()); RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, m_geom.GetMeshBoundsMin(), m_geom.GetMeshBoundsMax());
RecastBuilder rcBuilder = new RecastBuilder(); RecastBuilder rcBuilder = new RecastBuilder();
RecastBuilderResult rcResult = rcBuilder.build(m_geom, bcfg); RecastBuilderResult rcResult = rcBuilder.Build(m_geom, bcfg);
PolyMesh m_pmesh = rcResult.getMesh(); PolyMesh m_pmesh = rcResult.GetMesh();
for (int i = 0; i < m_pmesh.npolys; ++i) for (int i = 0; i < m_pmesh.npolys; ++i)
{ {
m_pmesh.flags[i] = 1; m_pmesh.flags[i] = 1;
} }
PolyMeshDetail m_dmesh = rcResult.getMeshDetail(); PolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
NavMeshDataCreateParams option = new NavMeshDataCreateParams(); NavMeshDataCreateParams option = new NavMeshDataCreateParams();
option.verts = m_pmesh.verts; option.verts = m_pmesh.verts;
option.vertCount = m_pmesh.nverts; option.vertCount = m_pmesh.nverts;
@ -105,10 +105,10 @@ public class RecastTestMeshBuilder
option.offMeshConUserID = new int[1]; option.offMeshConUserID = new int[1];
option.offMeshConUserID[0] = 0x4567; option.offMeshConUserID[0] = 0x4567;
option.offMeshConCount = 1; option.offMeshConCount = 1;
meshData = NavMeshBuilder.createNavMeshData(option); meshData = NavMeshBuilder.CreateNavMeshData(option);
} }
public MeshData getMeshData() public MeshData GetMeshData()
{ {
return meshData; return meshData;
} }

View File

@ -23,12 +23,12 @@ namespace DotRecast.Detour.Test;
public class TestDetourBuilder : DetourBuilder public class TestDetourBuilder : DetourBuilder
{ {
public MeshData build(InputGeomProvider geom, RecastBuilderConfig rcConfig, float agentHeight, float agentRadius, public MeshData Build(InputGeomProvider geom, RecastBuilderConfig rcConfig, float agentHeight, float agentRadius,
float agentMaxClimb, int x, int y, bool applyRecastDemoFlags) float agentMaxClimb, int x, int y, bool applyRecastDemoFlags)
{ {
RecastBuilder rcBuilder = new RecastBuilder(); RecastBuilder rcBuilder = new RecastBuilder();
RecastBuilderResult rcResult = rcBuilder.build(geom, rcConfig); RecastBuilderResult rcResult = rcBuilder.Build(geom, rcConfig);
PolyMesh pmesh = rcResult.getMesh(); PolyMesh pmesh = rcResult.GetMesh();
if (applyRecastDemoFlags) if (applyRecastDemoFlags)
{ {
@ -58,13 +58,13 @@ public class TestDetourBuilder : DetourBuilder
} }
} }
PolyMeshDetail dmesh = rcResult.getMeshDetail(); PolyMeshDetail dmesh = rcResult.GetMeshDetail();
NavMeshDataCreateParams option = getNavMeshCreateParams(rcConfig.cfg, pmesh, dmesh, agentHeight, agentRadius, NavMeshDataCreateParams option = GetNavMeshCreateParams(rcConfig.cfg, pmesh, dmesh, agentHeight, agentRadius,
agentMaxClimb); agentMaxClimb);
return build(option, x, y); return Build(option, x, y);
} }
public NavMeshDataCreateParams getNavMeshCreateParams(RecastConfig rcConfig, PolyMesh pmesh, PolyMeshDetail dmesh, public NavMeshDataCreateParams GetNavMeshCreateParams(RecastConfig rcConfig, PolyMesh pmesh, PolyMeshDetail dmesh,
float agentHeight, float agentRadius, float agentMaxClimb) float agentHeight, float agentRadius, float agentMaxClimb)
{ {
NavMeshDataCreateParams option = new NavMeshDataCreateParams(); NavMeshDataCreateParams option = new NavMeshDataCreateParams();
@ -93,11 +93,11 @@ public class TestDetourBuilder : DetourBuilder
option.ch = rcConfig.ch; option.ch = rcConfig.ch;
option.buildBvTree = true; option.buildBvTree = true;
/* /*
* option.offMeshConVerts = m_geom->getOffMeshConnectionVerts(); option.offMeshConRad = * option.offMeshConVerts = m_geom->GetOffMeshConnectionVerts(); option.offMeshConRad =
* m_geom->getOffMeshConnectionRads(); option.offMeshConDir = m_geom->getOffMeshConnectionDirs(); * m_geom->GetOffMeshConnectionRads(); option.offMeshConDir = m_geom->GetOffMeshConnectionDirs();
* option.offMeshConAreas = m_geom->getOffMeshConnectionAreas(); option.offMeshConFlags = * option.offMeshConAreas = m_geom->GetOffMeshConnectionAreas(); option.offMeshConFlags =
* m_geom->getOffMeshConnectionFlags(); option.offMeshConUserID = m_geom->getOffMeshConnectionId(); * m_geom->GetOffMeshConnectionFlags(); option.offMeshConUserID = m_geom->GetOffMeshConnectionId();
* option.offMeshConCount = m_geom->getOffMeshConnectionCount(); * option.offMeshConCount = m_geom->GetOffMeshConnectionCount();
*/ */
return option; return option;
} }

View File

@ -45,7 +45,7 @@ public class TestTiledNavMeshBuilder
private const int m_tileSize = 32; private const int m_tileSize = 32;
public TestTiledNavMeshBuilder() : public TestTiledNavMeshBuilder() :
this(ObjImporter.load(Loader.ToBytes("dungeon.obj")), this(ObjImporter.Load(Loader.ToBytes("dungeon.obj")),
PartitionType.WATERSHED, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_agentMaxSlope, PartitionType.WATERSHED, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_agentMaxSlope,
m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist, m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist,
m_detailSampleMaxError, m_tileSize) m_detailSampleMaxError, m_tileSize)
@ -59,7 +59,7 @@ public class TestTiledNavMeshBuilder
{ {
// Create empty nav mesh // Create empty nav mesh
NavMeshParams navMeshParams = new NavMeshParams(); NavMeshParams navMeshParams = new NavMeshParams();
navMeshParams.orig = m_geom.getMeshBoundsMin(); navMeshParams.orig = m_geom.GetMeshBoundsMin();
navMeshParams.tileWidth = m_tileSize * m_cellSize; navMeshParams.tileWidth = m_tileSize * m_cellSize;
navMeshParams.tileHeight = m_tileSize * m_cellSize; navMeshParams.tileHeight = m_tileSize * m_cellSize;
navMeshParams.maxTiles = 128; navMeshParams.maxTiles = 128;
@ -67,18 +67,18 @@ public class TestTiledNavMeshBuilder
navMesh = new NavMesh(navMeshParams, 6); navMesh = new NavMesh(navMeshParams, 6);
// Build all tiles // Build all tiles
RecastConfig cfg = new RecastConfig(true, m_tileSize, m_tileSize, RecastConfig.calcBorder(m_agentRadius, m_cellSize), RecastConfig cfg = new RecastConfig(true, m_tileSize, m_tileSize, RecastConfig.CalcBorder(m_agentRadius, m_cellSize),
m_partitionType, m_cellSize, m_cellHeight, m_agentMaxSlope, true, true, true, m_agentHeight, m_agentRadius, m_partitionType, m_cellSize, m_cellHeight, m_agentMaxSlope, true, true, true, m_agentHeight, m_agentRadius,
m_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true, m_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true,
m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND); m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
RecastBuilder rcBuilder = new RecastBuilder(); RecastBuilder rcBuilder = new RecastBuilder();
List<RecastBuilderResult> rcResult = rcBuilder.buildTiles(m_geom, cfg, null); List<RecastBuilderResult> rcResult = rcBuilder.BuildTiles(m_geom, cfg, null);
// Add tiles to nav mesh // Add tiles to nav mesh
foreach (RecastBuilderResult result in rcResult) foreach (RecastBuilderResult result in rcResult)
{ {
PolyMesh pmesh = result.getMesh(); PolyMesh pmesh = result.GetMesh();
if (pmesh.npolys == 0) if (pmesh.npolys == 0)
{ {
continue; continue;
@ -97,7 +97,7 @@ public class TestTiledNavMeshBuilder
option.polyFlags = pmesh.flags; option.polyFlags = pmesh.flags;
option.polyCount = pmesh.npolys; option.polyCount = pmesh.npolys;
option.nvp = pmesh.nvp; option.nvp = pmesh.nvp;
PolyMeshDetail dmesh = result.getMeshDetail(); PolyMeshDetail dmesh = result.GetMeshDetail();
option.detailMeshes = dmesh.meshes; option.detailMeshes = dmesh.meshes;
option.detailVerts = dmesh.verts; option.detailVerts = dmesh.verts;
option.detailVertsCount = dmesh.nverts; option.detailVertsCount = dmesh.nverts;
@ -113,11 +113,11 @@ 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(NavMeshBuilder.createNavMeshData(option), 0, 0); navMesh.AddTile(NavMeshBuilder.CreateNavMeshData(option), 0, 0);
} }
} }
public NavMesh getNavMesh() public NavMesh GetNavMesh()
{ {
return navMesh; return navMesh;
} }

View File

@ -50,19 +50,19 @@ public class TiledFindPathTest
protected NavMesh navmesh; protected NavMesh navmesh;
[SetUp] [SetUp]
public void setUp() public void SetUp()
{ {
navmesh = createNavMesh(); navmesh = CreateNavMesh();
query = new NavMeshQuery(navmesh); query = new NavMeshQuery(navmesh);
} }
protected NavMesh createNavMesh() protected NavMesh CreateNavMesh()
{ {
return new TestTiledNavMeshBuilder().getNavMesh(); return new TestTiledNavMeshBuilder().GetNavMesh();
} }
[Test] [Test]
public void testFindPath() public void TestFindPath()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < START_REFS.Length; i++) for (int i = 0; i < START_REFS.Length; i++)
@ -71,7 +71,7 @@ public class TiledFindPathTest
long endRef = END_REFS[i]; long endRef = END_REFS[i];
Vector3f startPos = START_POS[i]; Vector3f startPos = START_POS[i];
Vector3f endPos = END_POS[i]; Vector3f endPos = END_POS[i];
Result<List<long>> path = query.findPath(startRef, endRef, startPos, endPos, filter); Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter);
Assert.That(path.status, Is.EqualTo(STATUSES[i])); Assert.That(path.status, Is.EqualTo(STATUSES[i]));
Assert.That(path.result.Count, Is.EqualTo(RESULTS[i].Length)); Assert.That(path.result.Count, Is.EqualTo(RESULTS[i].Length));
for (int j = 0; j < RESULTS[i].Length; j++) for (int j = 0; j < RESULTS[i].Length; j++)

View File

@ -41,7 +41,7 @@ public class AbstractTileCacheTest
protected class TestTileCacheMeshProcess : TileCacheMeshProcess protected class TestTileCacheMeshProcess : TileCacheMeshProcess
{ {
public void process(NavMeshDataCreateParams option) public void Process(NavMeshDataCreateParams option)
{ {
for (int i = 0; i < option.polyCount; ++i) for (int i = 0; i < option.polyCount; ++i)
{ {
@ -50,13 +50,13 @@ public class AbstractTileCacheTest
} }
} }
public TileCache getTileCache(InputGeomProvider geom, ByteOrder order, bool cCompatibility) public TileCache GetTileCache(InputGeomProvider geom, ByteOrder order, bool cCompatibility)
{ {
TileCacheParams option = new TileCacheParams(); TileCacheParams option = new TileCacheParams();
int[] twh = Recast.Recast.calcTileCount(geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), m_cellSize, m_tileSize, m_tileSize); int[] twh = Recast.Recast.CalcTileCount(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), m_cellSize, m_tileSize, m_tileSize);
option.ch = m_cellHeight; option.ch = m_cellHeight;
option.cs = m_cellSize; option.cs = m_cellSize;
option.orig = geom.getMeshBoundsMin(); option.orig = geom.GetMeshBoundsMin();
option.height = m_tileSize; option.height = m_tileSize;
option.width = m_tileSize; option.width = m_tileSize;
option.walkableHeight = m_agentHeight; option.walkableHeight = m_agentHeight;
@ -66,14 +66,14 @@ public class AbstractTileCacheTest
option.maxTiles = twh[0] * twh[1] * EXPECTED_LAYERS_PER_TILE; option.maxTiles = twh[0] * twh[1] * EXPECTED_LAYERS_PER_TILE;
option.maxObstacles = 128; option.maxObstacles = 128;
NavMeshParams navMeshParams = new NavMeshParams(); NavMeshParams navMeshParams = new NavMeshParams();
navMeshParams.orig = geom.getMeshBoundsMin(); navMeshParams.orig = geom.GetMeshBoundsMin();
navMeshParams.tileWidth = m_tileSize * m_cellSize; navMeshParams.tileWidth = m_tileSize * m_cellSize;
navMeshParams.tileHeight = m_tileSize * m_cellSize; navMeshParams.tileHeight = m_tileSize * m_cellSize;
navMeshParams.maxTiles = 256; navMeshParams.maxTiles = 256;
navMeshParams.maxPolys = 16384; navMeshParams.maxPolys = 16384;
NavMesh navMesh = new NavMesh(navMeshParams, 6); NavMesh navMesh = new NavMesh(navMeshParams, 6);
TileCache tc = new TileCache(option, new TileCacheStorageParams(order, cCompatibility), navMesh, TileCache tc = new TileCache(option, new TileCacheStorageParams(order, cCompatibility), navMesh,
TileCacheCompressorFactory.get(cCompatibility), new TestTileCacheMeshProcess()); TileCacheCompressorFactory.Get(cCompatibility), new TestTileCacheMeshProcess());
return tc; return tc;
} }
} }

View File

@ -32,28 +32,28 @@ public class TileCacheReaderTest
private readonly TileCacheReader reader = new TileCacheReader(); private readonly TileCacheReader reader = new TileCacheReader();
[Test] [Test]
public void testNavmesh() public void TestNavmesh()
{ {
using var ms = new MemoryStream(Loader.ToBytes("all_tiles_tilecache.bin")); using var ms = new MemoryStream(Loader.ToBytes("all_tiles_tilecache.bin"));
using var @is = new BinaryReader(ms); using var @is = new BinaryReader(ms);
TileCache tc = reader.read(@is, 6, null); TileCache tc = reader.Read(@is, 6, null);
Assert.That(tc.getNavMesh().getMaxTiles(), Is.EqualTo(256)); Assert.That(tc.GetNavMesh().GetMaxTiles(), Is.EqualTo(256));
Assert.That(tc.getNavMesh().getParams().maxPolys, Is.EqualTo(16384)); Assert.That(tc.GetNavMesh().GetParams().maxPolys, Is.EqualTo(16384));
Assert.That(tc.getNavMesh().getParams().tileWidth, Is.EqualTo(14.4f).Within(0.001f)); Assert.That(tc.GetNavMesh().GetParams().tileWidth, Is.EqualTo(14.4f).Within(0.001f));
Assert.That(tc.getNavMesh().getParams().tileHeight, Is.EqualTo(14.4f).Within(0.001f)); Assert.That(tc.GetNavMesh().GetParams().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
Assert.That(tc.getNavMesh().getMaxVertsPerPoly(), Is.EqualTo(6)); Assert.That(tc.GetNavMesh().GetMaxVertsPerPoly(), Is.EqualTo(6));
Assert.That(tc.getParams().cs, Is.EqualTo(0.3f).Within(0.0f)); Assert.That(tc.GetParams().cs, Is.EqualTo(0.3f).Within(0.0f));
Assert.That(tc.getParams().ch, Is.EqualTo(0.2f).Within(0.0f)); Assert.That(tc.GetParams().ch, Is.EqualTo(0.2f).Within(0.0f));
Assert.That(tc.getParams().walkableClimb, Is.EqualTo(0.9f).Within(0.0f)); Assert.That(tc.GetParams().walkableClimb, Is.EqualTo(0.9f).Within(0.0f));
Assert.That(tc.getParams().walkableHeight, Is.EqualTo(2f).Within(0.0f)); Assert.That(tc.GetParams().walkableHeight, Is.EqualTo(2f).Within(0.0f));
Assert.That(tc.getParams().walkableRadius, Is.EqualTo(0.6f).Within(0.0f)); Assert.That(tc.GetParams().walkableRadius, Is.EqualTo(0.6f).Within(0.0f));
Assert.That(tc.getParams().width, Is.EqualTo(48)); Assert.That(tc.GetParams().width, Is.EqualTo(48));
Assert.That(tc.getParams().maxTiles, Is.EqualTo(6 * 7 * 4)); Assert.That(tc.GetParams().maxTiles, Is.EqualTo(6 * 7 * 4));
Assert.That(tc.getParams().maxObstacles, Is.EqualTo(128)); Assert.That(tc.GetParams().maxObstacles, Is.EqualTo(128));
Assert.That(tc.getTileCount(), Is.EqualTo(168)); Assert.That(tc.GetTileCount(), Is.EqualTo(168));
// Tile0: Tris: 1, Verts: 4 Detail Meshed: 1 Detail Verts: 0 Detail Tris: 2 // Tile0: Tris: 1, Verts: 4 Detail Meshed: 1 Detail Verts: 0 Detail Tris: 2
// Verts: -2.269517, 28.710686, 28.710686 // Verts: -2.269517, 28.710686, 28.710686
MeshTile tile = tc.getNavMesh().getTile(0); MeshTile tile = tc.GetNavMesh().GetTile(0);
MeshData data = tile.data; MeshData data = tile.data;
MeshHeader header = data.header; MeshHeader header = data.header;
Assert.That(header.vertCount, Is.EqualTo(4)); Assert.That(header.vertCount, Is.EqualTo(4));
@ -71,7 +71,7 @@ public class TileCacheReaderTest
Assert.That(data.verts[9], Is.EqualTo(28.710686f).Within(0.0001f)); Assert.That(data.verts[9], Is.EqualTo(28.710686f).Within(0.0001f));
// Tile8: Tris: 7, Verts: 10 Detail Meshed: 7 Detail Verts: 0 Detail Tris: 10 // Tile8: Tris: 7, Verts: 10 Detail Meshed: 7 Detail Verts: 0 Detail Tris: 10
// Verts: 0.330483, 43.110687, 43.110687 // Verts: 0.330483, 43.110687, 43.110687
tile = tc.getNavMesh().getTile(8); tile = tc.GetNavMesh().GetTile(8);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Console.WriteLine(data.header.x + " " + data.header.y + " " + data.header.layer); Console.WriteLine(data.header.x + " " + data.header.y + " " + data.header.layer);
@ -93,7 +93,7 @@ public class TileCacheReaderTest
Assert.That(data.verts[9], Is.EqualTo(43.110687f).Within(0.0001f)); Assert.That(data.verts[9], Is.EqualTo(43.110687f).Within(0.0001f));
// Tile16: Tris: 13, Verts: 33 Detail Meshed: 13 Detail Verts: 0 Detail Tris: 25 // Tile16: Tris: 13, Verts: 33 Detail Meshed: 13 Detail Verts: 0 Detail Tris: 25
// Verts: 1.130483, 5.610685, 6.510685 // Verts: 1.130483, 5.610685, 6.510685
tile = tc.getNavMesh().getTile(16); tile = tc.GetNavMesh().GetTile(16);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(33)); Assert.That(header.vertCount, Is.EqualTo(33));
@ -111,7 +111,7 @@ public class TileCacheReaderTest
Assert.That(data.verts[9], Is.EqualTo(6.510685f).Within(0.0001f)); Assert.That(data.verts[9], Is.EqualTo(6.510685f).Within(0.0001f));
// Tile29: Tris: 5, Verts: 15 Detail Meshed: 5 Detail Verts: 0 Detail Tris: 11 // Tile29: Tris: 5, Verts: 15 Detail Meshed: 5 Detail Verts: 0 Detail Tris: 11
// Verts: 10.330483, 10.110685, 10.110685 // Verts: 10.330483, 10.110685, 10.110685
tile = tc.getNavMesh().getTile(29); tile = tc.GetNavMesh().GetTile(29);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(15)); Assert.That(header.vertCount, Is.EqualTo(15));
@ -130,28 +130,28 @@ public class TileCacheReaderTest
} }
[Test] [Test]
public void testDungeon() public void TestDungeon()
{ {
using var ms = new MemoryStream(Loader.ToBytes("dungeon_all_tiles_tilecache.bin")); using var ms = new MemoryStream(Loader.ToBytes("dungeon_all_tiles_tilecache.bin"));
using var @is = new BinaryReader(ms); using var @is = new BinaryReader(ms);
TileCache tc = reader.read(@is, 6, null); TileCache tc = reader.Read(@is, 6, null);
Assert.That(tc.getNavMesh().getMaxTiles(), Is.EqualTo(256)); Assert.That(tc.GetNavMesh().GetMaxTiles(), Is.EqualTo(256));
Assert.That(tc.getNavMesh().getParams().maxPolys, Is.EqualTo(16384)); Assert.That(tc.GetNavMesh().GetParams().maxPolys, Is.EqualTo(16384));
Assert.That(tc.getNavMesh().getParams().tileWidth, Is.EqualTo(14.4f).Within(0.001f)); Assert.That(tc.GetNavMesh().GetParams().tileWidth, Is.EqualTo(14.4f).Within(0.001f));
Assert.That(tc.getNavMesh().getParams().tileHeight, Is.EqualTo(14.4f).Within(0.001f)); Assert.That(tc.GetNavMesh().GetParams().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
Assert.That(tc.getNavMesh().getMaxVertsPerPoly(), Is.EqualTo(6)); Assert.That(tc.GetNavMesh().GetMaxVertsPerPoly(), Is.EqualTo(6));
Assert.That(tc.getParams().cs, Is.EqualTo(0.3f).Within(0.0f)); Assert.That(tc.GetParams().cs, Is.EqualTo(0.3f).Within(0.0f));
Assert.That(tc.getParams().ch, Is.EqualTo(0.2f).Within(0.0f)); Assert.That(tc.GetParams().ch, Is.EqualTo(0.2f).Within(0.0f));
Assert.That(tc.getParams().walkableClimb, Is.EqualTo(0.9f).Within(0.0f)); Assert.That(tc.GetParams().walkableClimb, Is.EqualTo(0.9f).Within(0.0f));
Assert.That(tc.getParams().walkableHeight, Is.EqualTo(2f).Within(0.0f)); Assert.That(tc.GetParams().walkableHeight, Is.EqualTo(2f).Within(0.0f));
Assert.That(tc.getParams().walkableRadius, Is.EqualTo(0.6f).Within(0.0f)); Assert.That(tc.GetParams().walkableRadius, Is.EqualTo(0.6f).Within(0.0f));
Assert.That(tc.getParams().width, Is.EqualTo(48)); Assert.That(tc.GetParams().width, Is.EqualTo(48));
Assert.That(tc.getParams().maxTiles, Is.EqualTo(6 * 7 * 4)); Assert.That(tc.GetParams().maxTiles, Is.EqualTo(6 * 7 * 4));
Assert.That(tc.getParams().maxObstacles, Is.EqualTo(128)); Assert.That(tc.GetParams().maxObstacles, Is.EqualTo(128));
Assert.That(tc.getTileCount(), Is.EqualTo(168)); Assert.That(tc.GetTileCount(), Is.EqualTo(168));
// Tile0: Tris: 8, Verts: 18 Detail Meshed: 8 Detail Verts: 0 Detail Tris: 14 // Tile0: Tris: 8, Verts: 18 Detail Meshed: 8 Detail Verts: 0 Detail Tris: 14
// Verts: 14.997294, 15.484785, 15.484785 // Verts: 14.997294, 15.484785, 15.484785
MeshTile tile = tc.getNavMesh().getTile(0); MeshTile tile = tc.GetNavMesh().GetTile(0);
MeshData data = tile.data; MeshData data = tile.data;
MeshHeader header = data.header; MeshHeader header = data.header;
Assert.That(header.vertCount, Is.EqualTo(18)); Assert.That(header.vertCount, Is.EqualTo(18));
@ -169,7 +169,7 @@ public class TileCacheReaderTest
Assert.That(data.verts[9], Is.EqualTo(15.484785f).Within(0.0001f)); Assert.That(data.verts[9], Is.EqualTo(15.484785f).Within(0.0001f));
// Tile8: Tris: 3, Verts: 8 Detail Meshed: 3 Detail Verts: 0 Detail Tris: 6 // Tile8: Tris: 3, Verts: 8 Detail Meshed: 3 Detail Verts: 0 Detail Tris: 6
// Verts: 13.597294, 17.584785, 17.584785 // Verts: 13.597294, 17.584785, 17.584785
tile = tc.getNavMesh().getTile(8); tile = tc.GetNavMesh().GetTile(8);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(8)); Assert.That(header.vertCount, Is.EqualTo(8));
@ -187,7 +187,7 @@ public class TileCacheReaderTest
Assert.That(data.verts[9], Is.EqualTo(17.584785f).Within(0.0001f)); Assert.That(data.verts[9], Is.EqualTo(17.584785f).Within(0.0001f));
// Tile16: Tris: 10, Verts: 20 Detail Meshed: 10 Detail Verts: 0 Detail Tris: 18 // Tile16: Tris: 10, Verts: 20 Detail Meshed: 10 Detail Verts: 0 Detail Tris: 18
// Verts: 6.197294, -22.315216, -22.315216 // Verts: 6.197294, -22.315216, -22.315216
tile = tc.getNavMesh().getTile(16); tile = tc.GetNavMesh().GetTile(16);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(20)); Assert.That(header.vertCount, Is.EqualTo(20));
@ -205,7 +205,7 @@ public class TileCacheReaderTest
Assert.That(data.verts[9], Is.EqualTo(-22.315216f).Within(0.0001f)); Assert.That(data.verts[9], Is.EqualTo(-22.315216f).Within(0.0001f));
// Tile29: Tris: 1, Verts: 5 Detail Meshed: 1 Detail Verts: 0 Detail Tris: 3 // Tile29: Tris: 1, Verts: 5 Detail Meshed: 1 Detail Verts: 0 Detail Tris: 3
// Verts: 10.197294, 48.484783, 48.484783 // Verts: 10.197294, 48.484783, 48.484783
tile = tc.getNavMesh().getTile(29); tile = tc.GetNavMesh().GetTile(29);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(5)); Assert.That(header.vertCount, Is.EqualTo(5));

View File

@ -35,54 +35,54 @@ public class TileCacheReaderWriterTest : AbstractTileCacheTest
private readonly TileCacheWriter writer = new TileCacheWriter(); private readonly TileCacheWriter writer = new TileCacheWriter();
[Test] [Test]
public void testFastLz() public void TestFastLz()
{ {
testDungeon(false); TestDungeon(false);
testDungeon(true); TestDungeon(true);
} }
[Test] [Test]
public void testLZ4() public void TestLZ4()
{ {
testDungeon(true); TestDungeon(true);
testDungeon(false); TestDungeon(false);
} }
private void testDungeon(bool cCompatibility) private void TestDungeon(bool cCompatibility)
{ {
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("dungeon.obj")); InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom); TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom);
List<byte[]> layers = layerBuilder.build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1); List<byte[]> layers = layerBuilder.Build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1);
TileCache tc = getTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility); TileCache tc = GetTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility);
foreach (byte[] layer in layers) foreach (byte[] layer in layers)
{ {
long refs = tc.addTile(layer, 0); long refs = tc.AddTile(layer, 0);
tc.buildNavMeshTile(refs); tc.BuildNavMeshTile(refs);
} }
using var msout = new MemoryStream(); using var msout = new MemoryStream();
using var baos = new BinaryWriter(msout); using var baos = new BinaryWriter(msout);
writer.write(baos, tc, ByteOrder.LITTLE_ENDIAN, cCompatibility); writer.Write(baos, tc, ByteOrder.LITTLE_ENDIAN, cCompatibility);
using var msis = new MemoryStream(msout.ToArray()); using var msis = new MemoryStream(msout.ToArray());
using var bais = new BinaryReader(msis); using var bais = new BinaryReader(msis);
tc = reader.read(bais, 6, null); tc = reader.Read(bais, 6, null);
Assert.That(tc.getNavMesh().getMaxTiles(), Is.EqualTo(256)); Assert.That(tc.GetNavMesh().GetMaxTiles(), Is.EqualTo(256));
Assert.That(tc.getNavMesh().getParams().maxPolys, Is.EqualTo(16384)); Assert.That(tc.GetNavMesh().GetParams().maxPolys, Is.EqualTo(16384));
Assert.That(tc.getNavMesh().getParams().tileWidth, Is.EqualTo(14.4f).Within(0.001f)); Assert.That(tc.GetNavMesh().GetParams().tileWidth, Is.EqualTo(14.4f).Within(0.001f));
Assert.That(tc.getNavMesh().getParams().tileHeight, Is.EqualTo(14.4f).Within(0.001f)); Assert.That(tc.GetNavMesh().GetParams().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
Assert.That(tc.getNavMesh().getMaxVertsPerPoly(), Is.EqualTo(6)); Assert.That(tc.GetNavMesh().GetMaxVertsPerPoly(), Is.EqualTo(6));
Assert.That(tc.getParams().cs, Is.EqualTo(0.3f).Within(0.0f)); Assert.That(tc.GetParams().cs, Is.EqualTo(0.3f).Within(0.0f));
Assert.That(tc.getParams().ch, Is.EqualTo(0.2f).Within(0.0f)); Assert.That(tc.GetParams().ch, Is.EqualTo(0.2f).Within(0.0f));
Assert.That(tc.getParams().walkableClimb, Is.EqualTo(0.9f).Within(0.0f)); Assert.That(tc.GetParams().walkableClimb, Is.EqualTo(0.9f).Within(0.0f));
Assert.That(tc.getParams().walkableHeight, Is.EqualTo(2f).Within(0.0f)); Assert.That(tc.GetParams().walkableHeight, Is.EqualTo(2f).Within(0.0f));
Assert.That(tc.getParams().walkableRadius, Is.EqualTo(0.6f).Within(0.0f)); Assert.That(tc.GetParams().walkableRadius, Is.EqualTo(0.6f).Within(0.0f));
Assert.That(tc.getParams().width, Is.EqualTo(48)); Assert.That(tc.GetParams().width, Is.EqualTo(48));
Assert.That(tc.getParams().maxTiles, Is.EqualTo(6 * 7 * 4)); Assert.That(tc.GetParams().maxTiles, Is.EqualTo(6 * 7 * 4));
Assert.That(tc.getParams().maxObstacles, Is.EqualTo(128)); Assert.That(tc.GetParams().maxObstacles, Is.EqualTo(128));
Assert.That(tc.getTileCount(), Is.EqualTo(168)); Assert.That(tc.GetTileCount(), Is.EqualTo(168));
// Tile0: Tris: 8, Verts: 18 Detail Meshed: 8 Detail Verts: 0 Detail Tris: 14 // Tile0: Tris: 8, Verts: 18 Detail Meshed: 8 Detail Verts: 0 Detail Tris: 14
MeshTile tile = tc.getNavMesh().getTile(0); MeshTile tile = tc.GetNavMesh().GetTile(0);
MeshData data = tile.data; MeshData data = tile.data;
MeshHeader header = data.header; MeshHeader header = data.header;
Assert.That(header.vertCount, Is.EqualTo(18)); Assert.That(header.vertCount, Is.EqualTo(18));
@ -96,7 +96,7 @@ public class TileCacheReaderWriterTest : AbstractTileCacheTest
Assert.That(data.detailVerts.Length, Is.EqualTo(0)); Assert.That(data.detailVerts.Length, Is.EqualTo(0));
Assert.That(data.detailTris.Length, Is.EqualTo(4 * 14)); Assert.That(data.detailTris.Length, Is.EqualTo(4 * 14));
// Tile8: Tris: 3, Verts: 8 Detail Meshed: 3 Detail Verts: 0 Detail Tris: 6 // Tile8: Tris: 3, Verts: 8 Detail Meshed: 3 Detail Verts: 0 Detail Tris: 6
tile = tc.getNavMesh().getTile(8); tile = tc.GetNavMesh().GetTile(8);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(8)); Assert.That(header.vertCount, Is.EqualTo(8));
@ -110,7 +110,7 @@ public class TileCacheReaderWriterTest : AbstractTileCacheTest
Assert.That(data.detailVerts.Length, Is.EqualTo(0)); Assert.That(data.detailVerts.Length, Is.EqualTo(0));
Assert.That(data.detailTris.Length, Is.EqualTo(4 * 6)); Assert.That(data.detailTris.Length, Is.EqualTo(4 * 6));
// Tile16: Tris: 10, Verts: 20 Detail Meshed: 10 Detail Verts: 0 Detail Tris: 18 // Tile16: Tris: 10, Verts: 20 Detail Meshed: 10 Detail Verts: 0 Detail Tris: 18
tile = tc.getNavMesh().getTile(16); tile = tc.GetNavMesh().GetTile(16);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(20)); Assert.That(header.vertCount, Is.EqualTo(20));
@ -124,7 +124,7 @@ public class TileCacheReaderWriterTest : AbstractTileCacheTest
Assert.That(data.detailVerts.Length, Is.EqualTo(0)); Assert.That(data.detailVerts.Length, Is.EqualTo(0));
Assert.That(data.detailTris.Length, Is.EqualTo(4 * 18)); Assert.That(data.detailTris.Length, Is.EqualTo(4 * 18));
// Tile29: Tris: 1, Verts: 5 Detail Meshed: 1 Detail Verts: 0 Detail Tris: 3 // Tile29: Tris: 1, Verts: 5 Detail Meshed: 1 Detail Verts: 0 Detail Tris: 3
tile = tc.getNavMesh().getTile(29); tile = tc.GetNavMesh().GetTile(29);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(5)); Assert.That(header.vertCount, Is.EqualTo(5));

View File

@ -30,71 +30,71 @@ namespace DotRecast.Detour.TileCache.Test;
public class TempObstaclesTest : AbstractTileCacheTest public class TempObstaclesTest : AbstractTileCacheTest
{ {
[Test] [Test]
public void testDungeon() public void TestDungeon()
{ {
bool cCompatibility = true; bool cCompatibility = true;
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("dungeon.obj")); InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom); TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom);
List<byte[]> layers = layerBuilder.build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1); List<byte[]> layers = layerBuilder.Build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1);
TileCache tc = getTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility); TileCache tc = GetTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility);
foreach (byte[] data in layers) foreach (byte[] data in layers)
{ {
long refs = tc.addTile(data, 0); long refs = tc.AddTile(data, 0);
tc.buildNavMeshTile(refs); tc.BuildNavMeshTile(refs);
} }
List<MeshTile> tiles = tc.getNavMesh().getTilesAt(1, 4); List<MeshTile> tiles = tc.GetNavMesh().GetTilesAt(1, 4);
MeshTile tile = tiles[0]; MeshTile tile = tiles[0];
Assert.That(tile.data.header.vertCount, Is.EqualTo(16)); Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
Assert.That(tile.data.header.polyCount, Is.EqualTo(6)); Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
long o = tc.addObstacle(Vector3f.Of(-1.815208f, 9.998184f, -20.307983f), 1f, 2f); long o = tc.AddObstacle(Vector3f.Of(-1.815208f, 9.998184f, -20.307983f), 1f, 2f);
bool upToDate = tc.update(); bool upToDate = tc.Update();
Assert.That(upToDate, Is.True); Assert.That(upToDate, Is.True);
tiles = tc.getNavMesh().getTilesAt(1, 4); tiles = tc.GetNavMesh().GetTilesAt(1, 4);
tile = tiles[0]; tile = tiles[0];
Assert.That(tile.data.header.vertCount, Is.EqualTo(22)); Assert.That(tile.data.header.vertCount, Is.EqualTo(22));
Assert.That(tile.data.header.polyCount, Is.EqualTo(11)); Assert.That(tile.data.header.polyCount, Is.EqualTo(11));
tc.removeObstacle(o); tc.RemoveObstacle(o);
upToDate = tc.update(); upToDate = tc.Update();
Assert.That(upToDate, Is.True); Assert.That(upToDate, Is.True);
tiles = tc.getNavMesh().getTilesAt(1, 4); tiles = tc.GetNavMesh().GetTilesAt(1, 4);
tile = tiles[0]; tile = tiles[0];
Assert.That(tile.data.header.vertCount, Is.EqualTo(16)); Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
Assert.That(tile.data.header.polyCount, Is.EqualTo(6)); Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
} }
[Test] [Test]
public void testDungeonBox() public void TestDungeonBox()
{ {
bool cCompatibility = true; bool cCompatibility = true;
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("dungeon.obj")); InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom); TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom);
List<byte[]> layers = layerBuilder.build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1); List<byte[]> layers = layerBuilder.Build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1);
TileCache tc = getTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility); TileCache tc = GetTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility);
foreach (byte[] data in layers) foreach (byte[] data in layers)
{ {
long refs = tc.addTile(data, 0); long refs = tc.AddTile(data, 0);
tc.buildNavMeshTile(refs); tc.BuildNavMeshTile(refs);
} }
List<MeshTile> tiles = tc.getNavMesh().getTilesAt(1, 4); List<MeshTile> tiles = tc.GetNavMesh().GetTilesAt(1, 4);
MeshTile tile = tiles[0]; MeshTile tile = tiles[0];
Assert.That(tile.data.header.vertCount, Is.EqualTo(16)); Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
Assert.That(tile.data.header.polyCount, Is.EqualTo(6)); Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
long o = tc.addBoxObstacle( long o = tc.AddBoxObstacle(
Vector3f.Of(-2.315208f, 9.998184f, -20.807983f), Vector3f.Of(-2.315208f, 9.998184f, -20.807983f),
Vector3f.Of(-1.315208f, 11.998184f, -19.807983f) Vector3f.Of(-1.315208f, 11.998184f, -19.807983f)
); );
bool upToDate = tc.update(); bool upToDate = tc.Update();
Assert.That(upToDate, Is.True); Assert.That(upToDate, Is.True);
tiles = tc.getNavMesh().getTilesAt(1, 4); tiles = tc.GetNavMesh().GetTilesAt(1, 4);
tile = tiles[0]; tile = tiles[0];
Assert.That(tile.data.header.vertCount, Is.EqualTo(22)); Assert.That(tile.data.header.vertCount, Is.EqualTo(22));
Assert.That(tile.data.header.polyCount, Is.EqualTo(11)); Assert.That(tile.data.header.polyCount, Is.EqualTo(11));
tc.removeObstacle(o); tc.RemoveObstacle(o);
upToDate = tc.update(); upToDate = tc.Update();
Assert.That(upToDate, Is.True); Assert.That(upToDate, Is.True);
tiles = tc.getNavMesh().getTilesAt(1, 4); tiles = tc.GetNavMesh().GetTilesAt(1, 4);
tile = tiles[0]; tile = tiles[0];
Assert.That(tile.data.header.vertCount, Is.EqualTo(16)); Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
Assert.That(tile.data.header.polyCount, Is.EqualTo(6)); Assert.That(tile.data.header.polyCount, Is.EqualTo(6));

View File

@ -52,35 +52,35 @@ public class TestTileLayerBuilder : AbstractTileLayersBuilder
public TestTileLayerBuilder(InputGeomProvider geom) public TestTileLayerBuilder(InputGeomProvider geom)
{ {
this.geom = geom; this.geom = geom;
rcConfig = new RecastConfig(true, m_tileSize, m_tileSize, RecastConfig.calcBorder(m_agentRadius, m_cellSize), rcConfig = new RecastConfig(true, m_tileSize, m_tileSize, RecastConfig.CalcBorder(m_agentRadius, m_cellSize),
PartitionType.WATERSHED, m_cellSize, m_cellHeight, m_agentMaxSlope, true, true, true, m_agentHeight, PartitionType.WATERSHED, m_cellSize, m_cellHeight, m_agentMaxSlope, true, true, true, m_agentHeight,
m_agentRadius, m_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_agentRadius, m_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly,
true, m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND); true, m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
Vector3f bmin = geom.getMeshBoundsMin(); Vector3f bmin = geom.GetMeshBoundsMin();
Vector3f bmax = geom.getMeshBoundsMax(); Vector3f bmax = geom.GetMeshBoundsMax();
int[] twh = Recast.Recast.calcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize); int[] twh = Recast.Recast.CalcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize);
tw = twh[0]; tw = twh[0];
th = twh[1]; th = twh[1];
} }
public List<byte[]> build(ByteOrder order, bool cCompatibility, int threads) public List<byte[]> Build(ByteOrder order, bool cCompatibility, int threads)
{ {
return build(order, cCompatibility, threads, tw, th); return Build(order, cCompatibility, threads, tw, th);
} }
public int getTw() public int GetTw()
{ {
return tw; return tw;
} }
public int getTh() public int GetTh()
{ {
return th; return th;
} }
protected override List<byte[]> build(int tx, int ty, ByteOrder order, bool cCompatibility) protected override List<byte[]> Build(int tx, int ty, ByteOrder order, bool cCompatibility)
{ {
HeightfieldLayerSet lset = getHeightfieldSet(tx, ty); HeightfieldLayerSet lset = GetHeightfieldSet(tx, ty);
List<byte[]> result = new(); List<byte[]> result = new();
if (lset != null) if (lset != null)
{ {
@ -110,20 +110,20 @@ public class TestTileLayerBuilder : AbstractTileLayersBuilder
header.maxy = layer.maxy; header.maxy = layer.maxy;
header.hmin = layer.hmin; header.hmin = layer.hmin;
header.hmax = layer.hmax; header.hmax = layer.hmax;
result.Add(builder.compressTileCacheLayer(header, layer.heights, layer.areas, layer.cons, order, cCompatibility)); result.Add(builder.CompressTileCacheLayer(header, layer.heights, layer.areas, layer.cons, order, cCompatibility));
} }
} }
return result; return result;
} }
protected HeightfieldLayerSet getHeightfieldSet(int tx, int ty) protected HeightfieldLayerSet GetHeightfieldSet(int tx, int ty)
{ {
RecastBuilder rcBuilder = new RecastBuilder(); RecastBuilder rcBuilder = new RecastBuilder();
Vector3f bmin = geom.getMeshBoundsMin(); Vector3f bmin = geom.GetMeshBoundsMin();
Vector3f bmax = geom.getMeshBoundsMax(); Vector3f bmax = geom.GetMeshBoundsMax();
RecastBuilderConfig cfg = new RecastBuilderConfig(rcConfig, bmin, bmax, tx, ty); RecastBuilderConfig cfg = new RecastBuilderConfig(rcConfig, bmin, bmax, tx, ty);
HeightfieldLayerSet lset = rcBuilder.buildLayers(geom, cfg); HeightfieldLayerSet lset = rcBuilder.BuildLayers(geom, cfg);
return lset; return lset;
} }
} }

View File

@ -39,26 +39,26 @@ public class TileCacheFindPathTest : AbstractTileCacheTest
{ {
using var msis = new MemoryStream(Loader.ToBytes("dungeon_all_tiles_tilecache.bin")); using var msis = new MemoryStream(Loader.ToBytes("dungeon_all_tiles_tilecache.bin"));
using var @is = new BinaryReader(msis); using var @is = new BinaryReader(msis);
TileCache tcC = new TileCacheReader().read(@is, 6, new TestTileCacheMeshProcess()); TileCache tcC = new TileCacheReader().Read(@is, 6, new TestTileCacheMeshProcess());
navmesh = tcC.getNavMesh(); navmesh = tcC.GetNavMesh();
query = new NavMeshQuery(navmesh); query = new NavMeshQuery(navmesh);
} }
[Test] [Test]
public void testFindPath() public void TestFindPath()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
Vector3f extents = Vector3f.Of(2f, 4f, 2f); Vector3f extents = Vector3f.Of(2f, 4f, 2f);
Result<FindNearestPolyResult> findPolyStart = query.findNearestPoly(start, extents, filter); Result<FindNearestPolyResult> findPolyStart = query.FindNearestPoly(start, extents, filter);
Result<FindNearestPolyResult> findPolyEnd = query.findNearestPoly(end, extents, filter); Result<FindNearestPolyResult> findPolyEnd = query.FindNearestPoly(end, extents, filter);
long startRef = findPolyStart.result.getNearestRef(); long startRef = findPolyStart.result.GetNearestRef();
long endRef = findPolyEnd.result.getNearestRef(); long endRef = findPolyEnd.result.GetNearestRef();
Vector3f startPos = findPolyStart.result.getNearestPos(); Vector3f startPos = findPolyStart.result.GetNearestPos();
Vector3f endPos = findPolyEnd.result.getNearestPos(); Vector3f endPos = findPolyEnd.result.GetNearestPos();
Result<List<long>> path = query.findPath(startRef, endRef, startPos, endPos, filter); Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter);
int maxStraightPath = 256; int maxStraightPath = 256;
int options = 0; int options = 0;
Result<List<StraightPathItem>> pathStr = query.findStraightPath(startPos, endPos, path.result, maxStraightPath, options); Result<List<StraightPathItem>> pathStr = query.FindStraightPath(startPos, endPos, path.result, maxStraightPath, options);
Assert.That(pathStr.result.Count, Is.EqualTo(8)); Assert.That(pathStr.result.Count, Is.EqualTo(8));
} }
} }

View File

@ -53,35 +53,35 @@ public class TileCacheNavigationTest : AbstractTileCacheTest
protected NavMeshQuery query; protected NavMeshQuery query;
[SetUp] [SetUp]
public void setUp() public void SetUp()
{ {
bool cCompatibility = true; bool cCompatibility = true;
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("dungeon.obj")); InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom); TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom);
List<byte[]> layers = layerBuilder.build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1); List<byte[]> layers = layerBuilder.Build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1);
TileCache tc = getTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility); TileCache tc = GetTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility);
foreach (byte[] data in layers) foreach (byte[] data in layers)
{ {
tc.addTile(data, 0); tc.AddTile(data, 0);
} }
for (int y = 0; y < layerBuilder.getTh(); ++y) for (int y = 0; y < layerBuilder.GetTh(); ++y)
{ {
for (int x = 0; x < layerBuilder.getTw(); ++x) for (int x = 0; x < layerBuilder.GetTw(); ++x)
{ {
foreach (long refs in tc.getTilesAt(x, y)) foreach (long refs in tc.GetTilesAt(x, y))
{ {
tc.buildNavMeshTile(refs); tc.BuildNavMeshTile(refs);
} }
} }
} }
navmesh = tc.getNavMesh(); navmesh = tc.GetNavMesh();
query = new NavMeshQuery(navmesh); query = new NavMeshQuery(navmesh);
} }
[Test] [Test]
public void testFindPathWithDefaultHeuristic() public void TestFindPathWithDefaultHeuristic()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
@ -90,7 +90,7 @@ public class TileCacheNavigationTest : AbstractTileCacheTest
long endRef = endRefs[i]; long endRef = endRefs[i];
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Vector3f endPos = endPoss[i]; Vector3f endPos = endPoss[i];
Result<List<long>> path = query.findPath(startRef, endRef, startPos, endPos, filter); Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter);
Assert.That(path.status, Is.EqualTo(statuses[i])); Assert.That(path.status, Is.EqualTo(statuses[i]));
Assert.That(path.result.Count, Is.EqualTo(results[i].Length)); Assert.That(path.result.Count, Is.EqualTo(results[i].Length));
for (int j = 0; j < results[i].Length; j++) for (int j = 0; j < results[i].Length; j++)
@ -101,7 +101,7 @@ public class TileCacheNavigationTest : AbstractTileCacheTest
} }
[Test] [Test]
public void testFindPathWithNoHeuristic() public void TestFindPathWithNoHeuristic()
{ {
QueryFilter filter = new DefaultQueryFilter(); QueryFilter filter = new DefaultQueryFilter();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
@ -110,7 +110,7 @@ public class TileCacheNavigationTest : AbstractTileCacheTest
long endRef = endRefs[i]; long endRef = endRefs[i];
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Vector3f endPos = endPoss[i]; Vector3f endPos = endPoss[i];
Result<List<long>> path = query.findPath(startRef, endRef, startPos, endPos, filter, new DefaultQueryHeuristic(0.0f), Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter, new DefaultQueryHeuristic(0.0f),
0, 0); 0, 0);
Assert.That(path.status, Is.EqualTo(statuses[i])); Assert.That(path.status, Is.EqualTo(statuses[i]));
Assert.That(path.result.Count, Is.EqualTo(results[i].Length)); Assert.That(path.result.Count, Is.EqualTo(results[i].Length));

View File

@ -32,68 +32,68 @@ namespace DotRecast.Detour.TileCache.Test;
public class TileCacheTest : AbstractTileCacheTest public class TileCacheTest : AbstractTileCacheTest
{ {
[Test] [Test]
public void testFastLz() public void TestFastLz()
{ {
testDungeon(ByteOrder.LITTLE_ENDIAN, false); TestDungeon(ByteOrder.LITTLE_ENDIAN, false);
testDungeon(ByteOrder.LITTLE_ENDIAN, true); TestDungeon(ByteOrder.LITTLE_ENDIAN, true);
testDungeon(ByteOrder.BIG_ENDIAN, false); TestDungeon(ByteOrder.BIG_ENDIAN, false);
testDungeon(ByteOrder.BIG_ENDIAN, true); TestDungeon(ByteOrder.BIG_ENDIAN, true);
test(ByteOrder.LITTLE_ENDIAN, false); Test(ByteOrder.LITTLE_ENDIAN, false);
test(ByteOrder.LITTLE_ENDIAN, true); Test(ByteOrder.LITTLE_ENDIAN, true);
test(ByteOrder.BIG_ENDIAN, false); Test(ByteOrder.BIG_ENDIAN, false);
test(ByteOrder.BIG_ENDIAN, true); Test(ByteOrder.BIG_ENDIAN, true);
} }
[Test] [Test]
public void testLZ4() public void TestLZ4()
{ {
testDungeon(ByteOrder.LITTLE_ENDIAN, false); TestDungeon(ByteOrder.LITTLE_ENDIAN, false);
testDungeon(ByteOrder.LITTLE_ENDIAN, true); TestDungeon(ByteOrder.LITTLE_ENDIAN, true);
testDungeon(ByteOrder.BIG_ENDIAN, false); TestDungeon(ByteOrder.BIG_ENDIAN, false);
testDungeon(ByteOrder.BIG_ENDIAN, true); TestDungeon(ByteOrder.BIG_ENDIAN, true);
test(ByteOrder.LITTLE_ENDIAN, false); Test(ByteOrder.LITTLE_ENDIAN, false);
test(ByteOrder.LITTLE_ENDIAN, true); Test(ByteOrder.LITTLE_ENDIAN, true);
test(ByteOrder.BIG_ENDIAN, false); Test(ByteOrder.BIG_ENDIAN, false);
test(ByteOrder.BIG_ENDIAN, true); Test(ByteOrder.BIG_ENDIAN, true);
} }
private void testDungeon(ByteOrder order, bool cCompatibility) private void TestDungeon(ByteOrder order, bool cCompatibility)
{ {
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("dungeon.obj")); InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
TileCache tc = getTileCache(geom, order, cCompatibility); TileCache tc = GetTileCache(geom, order, cCompatibility);
TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom); TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom);
List<byte[]> layers = layerBuilder.build(order, cCompatibility, 1); List<byte[]> layers = layerBuilder.Build(order, cCompatibility, 1);
int cacheLayerCount = 0; int cacheLayerCount = 0;
int cacheCompressedSize = 0; int cacheCompressedSize = 0;
int cacheRawSize = 0; int cacheRawSize = 0;
foreach (byte[] layer in layers) foreach (byte[] layer in layers)
{ {
long refs = tc.addTile(layer, 0); long refs = tc.AddTile(layer, 0);
tc.buildNavMeshTile(refs); tc.BuildNavMeshTile(refs);
cacheLayerCount++; cacheLayerCount++;
cacheCompressedSize += layer.Length; cacheCompressedSize += layer.Length;
cacheRawSize += 4 * 48 * 48 + 56; // FIXME cacheRawSize += 4 * 48 * 48 + 56; // FIXME
} }
Console.WriteLine("Compressor: " + tc.getCompressor().GetType().Name + " C Compatibility: " + cCompatibility Console.WriteLine("Compressor: " + tc.GetCompressor().GetType().Name + " C Compatibility: " + cCompatibility
+ " Layers: " + cacheLayerCount + " Raw Size: " + cacheRawSize + " Compressed: " + cacheCompressedSize); + " Layers: " + cacheLayerCount + " Raw Size: " + cacheRawSize + " Compressed: " + cacheCompressedSize);
Assert.That(tc.getNavMesh().getMaxTiles(), Is.EqualTo(256)); Assert.That(tc.GetNavMesh().GetMaxTiles(), Is.EqualTo(256));
Assert.That(tc.getNavMesh().getParams().maxPolys, Is.EqualTo(16384)); Assert.That(tc.GetNavMesh().GetParams().maxPolys, Is.EqualTo(16384));
Assert.That(tc.getNavMesh().getParams().tileWidth, Is.EqualTo(14.4f).Within(0.001f)); Assert.That(tc.GetNavMesh().GetParams().tileWidth, Is.EqualTo(14.4f).Within(0.001f));
Assert.That(tc.getNavMesh().getParams().tileHeight, Is.EqualTo(14.4f).Within(0.001f)); Assert.That(tc.GetNavMesh().GetParams().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
Assert.That(tc.getNavMesh().getMaxVertsPerPoly(), Is.EqualTo(6)); Assert.That(tc.GetNavMesh().GetMaxVertsPerPoly(), Is.EqualTo(6));
Assert.That(tc.getParams().cs, Is.EqualTo(0.3f)); Assert.That(tc.GetParams().cs, Is.EqualTo(0.3f));
Assert.That(tc.getParams().ch, Is.EqualTo(0.2f)); Assert.That(tc.GetParams().ch, Is.EqualTo(0.2f));
Assert.That(tc.getParams().walkableClimb, Is.EqualTo(0.9f)); Assert.That(tc.GetParams().walkableClimb, Is.EqualTo(0.9f));
Assert.That(tc.getParams().walkableHeight, Is.EqualTo(2f)); Assert.That(tc.GetParams().walkableHeight, Is.EqualTo(2f));
Assert.That(tc.getParams().walkableRadius, Is.EqualTo(0.6f)); Assert.That(tc.GetParams().walkableRadius, Is.EqualTo(0.6f));
Assert.That(tc.getParams().width, Is.EqualTo(48)); Assert.That(tc.GetParams().width, Is.EqualTo(48));
Assert.That(tc.getParams().maxTiles, Is.EqualTo(6 * 7 * 4)); Assert.That(tc.GetParams().maxTiles, Is.EqualTo(6 * 7 * 4));
Assert.That(tc.getParams().maxObstacles, Is.EqualTo(128)); Assert.That(tc.GetParams().maxObstacles, Is.EqualTo(128));
Assert.That(tc.getTileCount(), Is.EqualTo(168)); Assert.That(tc.GetTileCount(), Is.EqualTo(168));
// Tile0: Tris: 8, Verts: 18 Detail Meshed: 8 Detail Verts: 0 Detail Tris: 14 // Tile0: Tris: 8, Verts: 18 Detail Meshed: 8 Detail Verts: 0 Detail Tris: 14
MeshTile tile = tc.getNavMesh().getTile(0); MeshTile tile = tc.GetNavMesh().GetTile(0);
MeshData data = tile.data; MeshData data = tile.data;
MeshHeader header = data.header; MeshHeader header = data.header;
Assert.That(header.vertCount, Is.EqualTo(18)); Assert.That(header.vertCount, Is.EqualTo(18));
@ -110,7 +110,7 @@ public class TileCacheTest : AbstractTileCacheTest
Assert.That(data.verts[6], Is.EqualTo(15.484785f).Within(0.0001f)); Assert.That(data.verts[6], Is.EqualTo(15.484785f).Within(0.0001f));
Assert.That(data.verts[9], Is.EqualTo(15.484785f).Within(0.0001f)); Assert.That(data.verts[9], Is.EqualTo(15.484785f).Within(0.0001f));
// Tile8: Tris: 3, Verts: 8 Detail Meshed: 3 Detail Verts: 0 Detail Tris: 6 // Tile8: Tris: 3, Verts: 8 Detail Meshed: 3 Detail Verts: 0 Detail Tris: 6
tile = tc.getNavMesh().getTile(8); tile = tc.GetNavMesh().GetTile(8);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(8)); Assert.That(header.vertCount, Is.EqualTo(8));
@ -124,7 +124,7 @@ public class TileCacheTest : AbstractTileCacheTest
Assert.That(data.detailVerts.Length, Is.EqualTo(0)); Assert.That(data.detailVerts.Length, Is.EqualTo(0));
Assert.That(data.detailTris.Length, Is.EqualTo(4 * 6)); Assert.That(data.detailTris.Length, Is.EqualTo(4 * 6));
// Tile16: Tris: 10, Verts: 20 Detail Meshed: 10 Detail Verts: 0 Detail Tris: 18 // Tile16: Tris: 10, Verts: 20 Detail Meshed: 10 Detail Verts: 0 Detail Tris: 18
tile = tc.getNavMesh().getTile(16); tile = tc.GetNavMesh().GetTile(16);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(20)); Assert.That(header.vertCount, Is.EqualTo(20));
@ -138,7 +138,7 @@ public class TileCacheTest : AbstractTileCacheTest
Assert.That(data.detailVerts.Length, Is.EqualTo(0)); Assert.That(data.detailVerts.Length, Is.EqualTo(0));
Assert.That(data.detailTris.Length, Is.EqualTo(4 * 18)); Assert.That(data.detailTris.Length, Is.EqualTo(4 * 18));
// Tile29: Tris: 1, Verts: 5 Detail Meshed: 1 Detail Verts: 0 Detail Tris: 3 // Tile29: Tris: 1, Verts: 5 Detail Meshed: 1 Detail Verts: 0 Detail Tris: 3
tile = tc.getNavMesh().getTile(29); tile = tc.GetNavMesh().GetTile(29);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(5)); Assert.That(header.vertCount, Is.EqualTo(5));
@ -153,81 +153,81 @@ public class TileCacheTest : AbstractTileCacheTest
Assert.That(data.detailTris.Length, Is.EqualTo(4 * 3)); Assert.That(data.detailTris.Length, Is.EqualTo(4 * 3));
} }
private void test(ByteOrder order, bool cCompatibility) private void Test(ByteOrder order, bool cCompatibility)
{ {
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("nav_test.obj")); InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("nav_test.obj"));
TileCache tc = getTileCache(geom, order, cCompatibility); TileCache tc = GetTileCache(geom, order, cCompatibility);
TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom); TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom);
List<byte[]> layers = layerBuilder.build(order, cCompatibility, 1); List<byte[]> layers = layerBuilder.Build(order, cCompatibility, 1);
int cacheLayerCount = 0; int cacheLayerCount = 0;
int cacheCompressedSize = 0; int cacheCompressedSize = 0;
int cacheRawSize = 0; int cacheRawSize = 0;
foreach (byte[] layer in layers) foreach (byte[] layer in layers)
{ {
long refs = tc.addTile(layer, 0); long refs = tc.AddTile(layer, 0);
tc.buildNavMeshTile(refs); tc.BuildNavMeshTile(refs);
cacheLayerCount++; cacheLayerCount++;
cacheCompressedSize += layer.Length; cacheCompressedSize += layer.Length;
cacheRawSize += 4 * 48 * 48 + 56; cacheRawSize += 4 * 48 * 48 + 56;
} }
Console.WriteLine("Compressor: " + tc.getCompressor().GetType().Name + " C Compatibility: " + cCompatibility Console.WriteLine("Compressor: " + tc.GetCompressor().GetType().Name + " C Compatibility: " + cCompatibility
+ " Layers: " + cacheLayerCount + " Raw Size: " + cacheRawSize + " Compressed: " + cacheCompressedSize); + " Layers: " + cacheLayerCount + " Raw Size: " + cacheRawSize + " Compressed: " + cacheCompressedSize);
} }
[Test] [Test]
public void testPerformance() public void TestPerformance()
{ {
int threads = 4; int threads = 4;
ByteOrder order = ByteOrder.LITTLE_ENDIAN; ByteOrder order = ByteOrder.LITTLE_ENDIAN;
bool cCompatibility = false; bool cCompatibility = false;
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("dungeon.obj")); InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom); TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
layerBuilder.build(order, cCompatibility, 1); layerBuilder.Build(order, cCompatibility, 1);
layerBuilder.build(order, cCompatibility, threads); layerBuilder.Build(order, cCompatibility, threads);
} }
long t1 = FrequencyWatch.Ticks; long t1 = FrequencyWatch.Ticks;
List<byte[]> layers = null; List<byte[]> layers = null;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
layers = layerBuilder.build(order, cCompatibility, 1); layers = layerBuilder.Build(order, cCompatibility, 1);
} }
long t2 = FrequencyWatch.Ticks; long t2 = FrequencyWatch.Ticks;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
layers = layerBuilder.build(order, cCompatibility, threads); layers = layerBuilder.Build(order, cCompatibility, threads);
} }
long t3 = FrequencyWatch.Ticks; long t3 = FrequencyWatch.Ticks;
Console.WriteLine(" Time ST : " + (t2 - t1) / TimeSpan.TicksPerMillisecond); Console.WriteLine(" Time ST : " + (t2 - t1) / TimeSpan.TicksPerMillisecond);
Console.WriteLine(" Time MT : " + (t3 - t2) / TimeSpan.TicksPerMillisecond); Console.WriteLine(" Time MT : " + (t3 - t2) / TimeSpan.TicksPerMillisecond);
TileCache tc = getTileCache(geom, order, cCompatibility); TileCache tc = GetTileCache(geom, order, cCompatibility);
foreach (byte[] layer in layers) foreach (byte[] layer in layers)
{ {
long refs = tc.addTile(layer, 0); long refs = tc.AddTile(layer, 0);
tc.buildNavMeshTile(refs); tc.BuildNavMeshTile(refs);
} }
Assert.That(tc.getNavMesh().getMaxTiles(), Is.EqualTo(256)); Assert.That(tc.GetNavMesh().GetMaxTiles(), Is.EqualTo(256));
Assert.That(tc.getNavMesh().getParams().maxPolys, Is.EqualTo(16384)); Assert.That(tc.GetNavMesh().GetParams().maxPolys, Is.EqualTo(16384));
Assert.That(tc.getNavMesh().getParams().tileWidth, Is.EqualTo(14.4f).Within(0.001f)); Assert.That(tc.GetNavMesh().GetParams().tileWidth, Is.EqualTo(14.4f).Within(0.001f));
Assert.That(tc.getNavMesh().getParams().tileHeight, Is.EqualTo(14.4f).Within(0.001f)); Assert.That(tc.GetNavMesh().GetParams().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
Assert.That(tc.getNavMesh().getMaxVertsPerPoly(), Is.EqualTo(6)); Assert.That(tc.GetNavMesh().GetMaxVertsPerPoly(), Is.EqualTo(6));
Assert.That(tc.getParams().cs, Is.EqualTo(0.3f)); Assert.That(tc.GetParams().cs, Is.EqualTo(0.3f));
Assert.That(tc.getParams().ch, Is.EqualTo(0.2f)); Assert.That(tc.GetParams().ch, Is.EqualTo(0.2f));
Assert.That(tc.getParams().walkableClimb, Is.EqualTo(0.9f)); Assert.That(tc.GetParams().walkableClimb, Is.EqualTo(0.9f));
Assert.That(tc.getParams().walkableHeight, Is.EqualTo(2f)); Assert.That(tc.GetParams().walkableHeight, Is.EqualTo(2f));
Assert.That(tc.getParams().walkableRadius, Is.EqualTo(0.6f)); Assert.That(tc.GetParams().walkableRadius, Is.EqualTo(0.6f));
Assert.That(tc.getParams().width, Is.EqualTo(48)); Assert.That(tc.GetParams().width, Is.EqualTo(48));
Assert.That(tc.getParams().maxTiles, Is.EqualTo(6 * 7 * 4)); Assert.That(tc.GetParams().maxTiles, Is.EqualTo(6 * 7 * 4));
Assert.That(tc.getParams().maxObstacles, Is.EqualTo(128)); Assert.That(tc.GetParams().maxObstacles, Is.EqualTo(128));
Assert.That(tc.getTileCount(), Is.EqualTo(168)); Assert.That(tc.GetTileCount(), Is.EqualTo(168));
// Tile0: Tris: 8, Verts: 18 Detail Meshed: 8 Detail Verts: 0 Detail Tris: 14 // Tile0: Tris: 8, Verts: 18 Detail Meshed: 8 Detail Verts: 0 Detail Tris: 14
MeshTile tile = tc.getNavMesh().getTile(0); MeshTile tile = tc.GetNavMesh().GetTile(0);
MeshData data = tile.data; MeshData data = tile.data;
MeshHeader header = data.header; MeshHeader header = data.header;
Assert.That(header.vertCount, Is.EqualTo(18)); Assert.That(header.vertCount, Is.EqualTo(18));
@ -244,7 +244,7 @@ public class TileCacheTest : AbstractTileCacheTest
Assert.That(data.verts[6], Is.EqualTo(15.484785f).Within(0.0001f)); Assert.That(data.verts[6], Is.EqualTo(15.484785f).Within(0.0001f));
Assert.That(data.verts[9], Is.EqualTo(15.484785f).Within(0.0001f)); Assert.That(data.verts[9], Is.EqualTo(15.484785f).Within(0.0001f));
// Tile8: Tris: 3, Verts: 8 Detail Meshed: 3 Detail Verts: 0 Detail Tris: 6 // Tile8: Tris: 3, Verts: 8 Detail Meshed: 3 Detail Verts: 0 Detail Tris: 6
tile = tc.getNavMesh().getTile(8); tile = tc.GetNavMesh().GetTile(8);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(8)); Assert.That(header.vertCount, Is.EqualTo(8));
@ -258,7 +258,7 @@ public class TileCacheTest : AbstractTileCacheTest
Assert.That(data.detailVerts.Length, Is.EqualTo(0)); Assert.That(data.detailVerts.Length, Is.EqualTo(0));
Assert.That(data.detailTris.Length, Is.EqualTo(4 * 6)); Assert.That(data.detailTris.Length, Is.EqualTo(4 * 6));
// Tile16: Tris: 10, Verts: 20 Detail Meshed: 10 Detail Verts: 0 Detail Tris: 18 // Tile16: Tris: 10, Verts: 20 Detail Meshed: 10 Detail Verts: 0 Detail Tris: 18
tile = tc.getNavMesh().getTile(16); tile = tc.GetNavMesh().GetTile(16);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(20)); Assert.That(header.vertCount, Is.EqualTo(20));
@ -272,7 +272,7 @@ public class TileCacheTest : AbstractTileCacheTest
Assert.That(data.detailVerts.Length, Is.EqualTo(0)); Assert.That(data.detailVerts.Length, Is.EqualTo(0));
Assert.That(data.detailTris.Length, Is.EqualTo(4 * 18)); Assert.That(data.detailTris.Length, Is.EqualTo(4 * 18));
// Tile29: Tris: 1, Verts: 5 Detail Meshed: 1 Detail Verts: 0 Detail Tris: 3 // Tile29: Tris: 1, Verts: 5 Detail Meshed: 1 Detail Verts: 0 Detail Tris: 3
tile = tc.getNavMesh().getTile(29); tile = tc.GetNavMesh().GetTile(29);
data = tile.data; data = tile.data;
header = data.header; header = data.header;
Assert.That(header.vertCount, Is.EqualTo(5)); Assert.That(header.vertCount, Is.EqualTo(5));

View File

@ -48,15 +48,15 @@ public class RecastLayersTest
private const int m_tileSize = 48; private const int m_tileSize = 48;
[Test] [Test]
public void testDungeon2() public void TestDungeon2()
{ {
} }
[Test] [Test]
public void testDungeon() public void TestDungeon()
{ {
HeightfieldLayerSet lset = build("dungeon.obj", 3, 2); HeightfieldLayerSet lset = Build("dungeon.obj", 3, 2);
Assert.That(lset.layers.Length, Is.EqualTo(1)); Assert.That(lset.layers.Length, Is.EqualTo(1));
Assert.That(lset.layers[0].width, Is.EqualTo(48)); Assert.That(lset.layers[0].width, Is.EqualTo(48));
Assert.That(lset.layers[0].hmin, Is.EqualTo(51)); Assert.That(lset.layers[0].hmin, Is.EqualTo(51));
@ -72,9 +72,9 @@ public class RecastLayersTest
} }
[Test] [Test]
public void test() public void Test()
{ {
HeightfieldLayerSet lset = build("nav_test.obj", 3, 2); HeightfieldLayerSet lset = Build("nav_test.obj", 3, 2);
Assert.That(lset.layers.Length, Is.EqualTo(3)); Assert.That(lset.layers.Length, Is.EqualTo(3));
Assert.That(lset.layers[0].width, Is.EqualTo(48)); Assert.That(lset.layers[0].width, Is.EqualTo(48));
Assert.That(lset.layers[0].hmin, Is.EqualTo(13)); Assert.That(lset.layers[0].hmin, Is.EqualTo(13));
@ -114,9 +114,9 @@ public class RecastLayersTest
} }
[Test] [Test]
public void test2() public void Test2()
{ {
HeightfieldLayerSet lset = build("nav_test.obj", 2, 4); HeightfieldLayerSet lset = Build("nav_test.obj", 2, 4);
Assert.That(lset.layers.Length, Is.EqualTo(2)); Assert.That(lset.layers.Length, Is.EqualTo(2));
Assert.That(lset.layers[0].width, Is.EqualTo(48)); Assert.That(lset.layers[0].width, Is.EqualTo(48));
Assert.That(lset.layers[0].hmin, Is.EqualTo(13)); Assert.That(lset.layers[0].hmin, Is.EqualTo(13));
@ -143,16 +143,16 @@ public class RecastLayersTest
Assert.That(lset.layers[1].cons[1600], Is.EqualTo(0)); Assert.That(lset.layers[1].cons[1600], Is.EqualTo(0));
} }
private HeightfieldLayerSet build(string filename, int x, int y) private HeightfieldLayerSet Build(string filename, int x, int y)
{ {
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes(filename)); InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes(filename));
RecastBuilder builder = new RecastBuilder(); RecastBuilder builder = new RecastBuilder();
RecastConfig cfg = new RecastConfig(true, m_tileSize, m_tileSize, RecastConfig.calcBorder(m_agentRadius, m_cellSize), RecastConfig cfg = new RecastConfig(true, m_tileSize, m_tileSize, RecastConfig.CalcBorder(m_agentRadius, m_cellSize),
m_partitionType, m_cellSize, m_cellHeight, m_agentMaxSlope, true, true, true, m_agentHeight, m_agentRadius, m_partitionType, m_cellSize, m_cellHeight, m_agentMaxSlope, true, true, true, m_agentHeight, m_agentRadius,
m_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true, m_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true,
m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND); m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), x, y); RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), x, y);
HeightfieldLayerSet lset = builder.buildLayers(geom, bcfg); HeightfieldLayerSet lset = builder.BuildLayers(geom, bcfg);
return lset; return lset;
} }
} }

View File

@ -46,60 +46,60 @@ public class RecastSoloMeshTest
private PartitionType m_partitionType = PartitionType.WATERSHED; private PartitionType m_partitionType = PartitionType.WATERSHED;
[Test] [Test]
public void testPerformance() public void TestPerformance()
{ {
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
testBuild("dungeon.obj", PartitionType.WATERSHED, 52, 16, 15, 223, 118, 118, 513, 291); TestBuild("dungeon.obj", PartitionType.WATERSHED, 52, 16, 15, 223, 118, 118, 513, 291);
testBuild("dungeon.obj", PartitionType.MONOTONE, 0, 17, 16, 210, 100, 100, 453, 264); TestBuild("dungeon.obj", PartitionType.MONOTONE, 0, 17, 16, 210, 100, 100, 453, 264);
testBuild("dungeon.obj", PartitionType.LAYERS, 0, 5, 5, 203, 97, 97, 446, 266); TestBuild("dungeon.obj", PartitionType.LAYERS, 0, 5, 5, 203, 97, 97, 446, 266);
} }
} }
[Test] [Test]
public void testDungeonWatershed() public void TestDungeonWatershed()
{ {
testBuild("dungeon.obj", PartitionType.WATERSHED, 52, 16, 15, 223, 118, 118, 513, 291); TestBuild("dungeon.obj", PartitionType.WATERSHED, 52, 16, 15, 223, 118, 118, 513, 291);
} }
[Test] [Test]
public void testDungeonMonotone() public void TestDungeonMonotone()
{ {
testBuild("dungeon.obj", PartitionType.MONOTONE, 0, 17, 16, 210, 100, 100, 453, 264); TestBuild("dungeon.obj", PartitionType.MONOTONE, 0, 17, 16, 210, 100, 100, 453, 264);
} }
[Test] [Test]
public void testDungeonLayers() public void TestDungeonLayers()
{ {
testBuild("dungeon.obj", PartitionType.LAYERS, 0, 5, 5, 203, 97, 97, 446, 266); TestBuild("dungeon.obj", PartitionType.LAYERS, 0, 5, 5, 203, 97, 97, 446, 266);
} }
[Test] [Test]
public void testWatershed() public void TestWatershed()
{ {
testBuild("nav_test.obj", PartitionType.WATERSHED, 60, 48, 47, 349, 153, 153, 802, 558); TestBuild("nav_test.obj", PartitionType.WATERSHED, 60, 48, 47, 349, 153, 153, 802, 558);
} }
[Test] [Test]
public void testMonotone() public void TestMonotone()
{ {
testBuild("nav_test.obj", PartitionType.MONOTONE, 0, 50, 49, 340, 185, 185, 871, 557); TestBuild("nav_test.obj", PartitionType.MONOTONE, 0, 50, 49, 340, 185, 185, 871, 557);
} }
[Test] [Test]
public void testLayers() public void TestLayers()
{ {
testBuild("nav_test.obj", PartitionType.LAYERS, 0, 19, 32, 312, 150, 150, 764, 521); TestBuild("nav_test.obj", PartitionType.LAYERS, 0, 19, 32, 312, 150, 150, 764, 521);
} }
public void testBuild(string filename, PartitionType partitionType, int expDistance, int expRegions, public void TestBuild(string filename, PartitionType partitionType, int expDistance, int expRegions,
int expContours, int expVerts, int expPolys, int expDetMeshes, int expDetVerts, int expDetTris) int expContours, int expVerts, int expPolys, int expDetMeshes, int expDetVerts, int expDetTris)
{ {
m_partitionType = partitionType; m_partitionType = partitionType;
InputGeomProvider geomProvider = ObjImporter.load(Loader.ToBytes(filename)); InputGeomProvider geomProvider = ObjImporter.Load(Loader.ToBytes(filename));
long time = FrequencyWatch.Ticks; long time = FrequencyWatch.Ticks;
Vector3f bmin = geomProvider.getMeshBoundsMin(); Vector3f bmin = geomProvider.GetMeshBoundsMin();
Vector3f bmax = geomProvider.getMeshBoundsMax(); Vector3f bmax = geomProvider.GetMeshBoundsMax();
Telemetry m_ctx = new Telemetry(); Telemetry m_ctx = new Telemetry();
// //
// Step 1. Initialize build config. // Step 1. Initialize build config.
@ -117,10 +117,10 @@ public class RecastSoloMeshTest
// Allocate voxel heightfield where we rasterize our input data to. // Allocate voxel heightfield where we rasterize our input data to.
Heightfield m_solid = new Heightfield(bcfg.width, bcfg.height, bcfg.bmin, bcfg.bmax, cfg.cs, cfg.ch, cfg.borderSize); Heightfield m_solid = new Heightfield(bcfg.width, bcfg.height, bcfg.bmin, bcfg.bmax, cfg.cs, cfg.ch, cfg.borderSize);
foreach (TriMesh geom in geomProvider.meshes()) foreach (TriMesh geom in geomProvider.Meshes())
{ {
float[] verts = geom.getVerts(); float[] verts = geom.GetVerts();
int[] tris = geom.getTris(); int[] tris = geom.GetTris();
int ntris = tris.Length / 3; int ntris = tris.Length / 3;
// Allocate array that can hold triangle area types. // Allocate array that can hold triangle area types.
@ -133,9 +133,9 @@ public class RecastSoloMeshTest
// If your input data is multiple meshes, you can transform them here, // If your input data is multiple meshes, you can transform them here,
// calculate // calculate
// the are type for each of the meshes and rasterize them. // the are type for each of the meshes and rasterize them.
int[] m_triareas = Recast.markWalkableTriangles(m_ctx, cfg.walkableSlopeAngle, verts, tris, ntris, int[] m_triareas = Recast.MarkWalkableTriangles(m_ctx, cfg.walkableSlopeAngle, verts, tris, ntris,
cfg.walkableAreaMod); cfg.walkableAreaMod);
RecastRasterization.rasterizeTriangles(m_solid, verts, tris, m_triareas, ntris, cfg.walkableClimb, m_ctx); RecastRasterization.RasterizeTriangles(m_solid, verts, tris, m_triareas, ntris, cfg.walkableClimb, m_ctx);
// //
// Step 3. Filter walkables surfaces. // Step 3. Filter walkables surfaces.
// //
@ -144,9 +144,9 @@ public class RecastSoloMeshTest
// Once all geometry is rasterized, we do initial pass of filtering to // Once all geometry is rasterized, we do initial pass of filtering to
// remove unwanted overhangs caused by the conservative rasterization // remove unwanted overhangs caused by the conservative rasterization
// as well as filter spans where the character cannot possibly stand. // as well as filter spans where the character cannot possibly stand.
RecastFilter.filterLowHangingWalkableObstacles(m_ctx, cfg.walkableClimb, m_solid); RecastFilter.FilterLowHangingWalkableObstacles(m_ctx, cfg.walkableClimb, m_solid);
RecastFilter.filterLedgeSpans(m_ctx, cfg.walkableHeight, cfg.walkableClimb, m_solid); RecastFilter.FilterLedgeSpans(m_ctx, cfg.walkableHeight, cfg.walkableClimb, m_solid);
RecastFilter.filterWalkableLowHeightSpans(m_ctx, cfg.walkableHeight, m_solid); RecastFilter.FilterWalkableLowHeightSpans(m_ctx, cfg.walkableHeight, m_solid);
// //
// Step 4. Partition walkable surface to simple regions. // Step 4. Partition walkable surface to simple regions.
@ -155,16 +155,16 @@ public class RecastSoloMeshTest
// Compact the heightfield so that it is faster to handle from now on. // Compact the heightfield so that it is faster to handle from now on.
// This will result more cache coherent data as well as the neighbours // This will result more cache coherent data as well as the neighbours
// between walkable cells will be calculated. // between walkable cells will be calculated.
CompactHeightfield m_chf = RecastCompact.buildCompactHeightfield(m_ctx, cfg.walkableHeight, cfg.walkableClimb, CompactHeightfield m_chf = RecastCompact.BuildCompactHeightfield(m_ctx, cfg.walkableHeight, cfg.walkableClimb,
m_solid); m_solid);
// Erode the walkable area by agent radius. // Erode the walkable area by agent radius.
RecastArea.erodeWalkableArea(m_ctx, cfg.walkableRadius, m_chf); RecastArea.ErodeWalkableArea(m_ctx, cfg.walkableRadius, m_chf);
// (Optional) Mark areas. // (Optional) Mark areas.
/* /*
* ConvexVolume vols = m_geom->getConvexVolumes(); for (int i = 0; i < m_geom->getConvexVolumeCount(); ++i) * ConvexVolume vols = m_geom->GetConvexVolumes(); for (int i = 0; i < m_geom->GetConvexVolumeCount(); ++i)
* rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned * RcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned
* char)vols[i].area, *m_chf); * char)vols[i].area, *m_chf);
*/ */
@ -211,20 +211,20 @@ public class RecastSoloMeshTest
{ {
// Prepare for region partitioning, by calculating distance field // Prepare for region partitioning, by calculating distance field
// along the walkable surface. // along the walkable surface.
RecastRegion.buildDistanceField(m_ctx, m_chf); RecastRegion.BuildDistanceField(m_ctx, m_chf);
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
RecastRegion.buildRegions(m_ctx, m_chf, cfg.minRegionArea, cfg.mergeRegionArea); RecastRegion.BuildRegions(m_ctx, m_chf, cfg.minRegionArea, cfg.mergeRegionArea);
} }
else if (m_partitionType == PartitionType.MONOTONE) else if (m_partitionType == PartitionType.MONOTONE)
{ {
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
// Monotone partitioning does not need distancefield. // Monotone partitioning does not need distancefield.
RecastRegion.buildRegionsMonotone(m_ctx, m_chf, cfg.minRegionArea, cfg.mergeRegionArea); RecastRegion.BuildRegionsMonotone(m_ctx, m_chf, cfg.minRegionArea, cfg.mergeRegionArea);
} }
else else
{ {
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
RecastRegion.buildLayerRegions(m_ctx, m_chf, cfg.minRegionArea); RecastRegion.BuildLayerRegions(m_ctx, m_chf, cfg.minRegionArea);
} }
Assert.That(m_chf.maxDistance, Is.EqualTo(expDistance), "maxDistance"); Assert.That(m_chf.maxDistance, Is.EqualTo(expDistance), "maxDistance");
@ -234,7 +234,7 @@ public class RecastSoloMeshTest
// //
// Create contours. // Create contours.
ContourSet m_cset = RecastContour.buildContours(m_ctx, m_chf, cfg.maxSimplificationError, cfg.maxEdgeLen, ContourSet m_cset = RecastContour.BuildContours(m_ctx, m_chf, cfg.maxSimplificationError, cfg.maxEdgeLen,
RecastConstants.RC_CONTOUR_TESS_WALL_EDGES); RecastConstants.RC_CONTOUR_TESS_WALL_EDGES);
Assert.That(m_cset.conts.Count, Is.EqualTo(expContours), "Contours"); Assert.That(m_cset.conts.Count, Is.EqualTo(expContours), "Contours");
@ -243,7 +243,7 @@ public class RecastSoloMeshTest
// //
// Build polygon navmesh from the contours. // Build polygon navmesh from the contours.
PolyMesh m_pmesh = RecastMesh.buildPolyMesh(m_ctx, m_cset, cfg.maxVertsPerPoly); PolyMesh m_pmesh = RecastMesh.BuildPolyMesh(m_ctx, m_cset, cfg.maxVertsPerPoly);
Assert.That(m_pmesh.nverts, Is.EqualTo(expVerts), "Mesh Verts"); Assert.That(m_pmesh.nverts, Is.EqualTo(expVerts), "Mesh Verts");
Assert.That(m_pmesh.npolys, Is.EqualTo(expPolys), "Mesh Polys"); Assert.That(m_pmesh.npolys, Is.EqualTo(expPolys), "Mesh Polys");
@ -252,7 +252,7 @@ public class RecastSoloMeshTest
// on each polygon. // on each polygon.
// //
PolyMeshDetail m_dmesh = RecastMeshDetail.buildPolyMeshDetail(m_ctx, m_pmesh, m_chf, cfg.detailSampleDist, PolyMeshDetail m_dmesh = RecastMeshDetail.BuildPolyMeshDetail(m_ctx, m_pmesh, m_chf, cfg.detailSampleDist,
cfg.detailSampleMaxError); cfg.detailSampleMaxError);
Assert.That(m_dmesh.nmeshes, Is.EqualTo(expDetMeshes), "Mesh Detail Meshes"); Assert.That(m_dmesh.nmeshes, Is.EqualTo(expDetMeshes), "Mesh Detail Meshes");
Assert.That(m_dmesh.nverts, Is.EqualTo(expDetVerts), "Mesh Detail Verts"); Assert.That(m_dmesh.nverts, Is.EqualTo(expDetVerts), "Mesh Detail Verts");
@ -260,15 +260,15 @@ public class RecastSoloMeshTest
long time2 = FrequencyWatch.Ticks; long time2 = FrequencyWatch.Ticks;
Console.WriteLine(filename + " : " + partitionType + " " + (time2 - time) / TimeSpan.TicksPerMillisecond + " ms"); Console.WriteLine(filename + " : " + partitionType + " " + (time2 - time) / TimeSpan.TicksPerMillisecond + " ms");
Console.WriteLine(" " + (time3 - time) / TimeSpan.TicksPerMillisecond + " ms"); Console.WriteLine(" " + (time3 - time) / TimeSpan.TicksPerMillisecond + " ms");
saveObj(filename.Substring(0, filename.LastIndexOf('.')) + "_" + partitionType + "_detail.obj", m_dmesh); SaveObj(filename.Substring(0, filename.LastIndexOf('.')) + "_" + partitionType + "_detail.obj", m_dmesh);
saveObj(filename.Substring(0, filename.LastIndexOf('.')) + "_" + partitionType + ".obj", m_pmesh); SaveObj(filename.Substring(0, filename.LastIndexOf('.')) + "_" + partitionType + ".obj", m_pmesh);
foreach (var (key, millis) in m_ctx.ToList()) foreach (var (key, millis) in m_ctx.ToList())
{ {
Console.WriteLine($"{key} : {millis} ms"); Console.WriteLine($"{key} : {millis} ms");
} }
} }
private void saveObj(string filename, PolyMesh mesh) private void SaveObj(string filename, PolyMesh mesh)
{ {
try try
{ {
@ -308,7 +308,7 @@ public class RecastSoloMeshTest
} }
} }
private void saveObj(string filename, PolyMeshDetail dmesh) private void SaveObj(string filename, PolyMeshDetail dmesh)
{ {
try try
{ {

View File

@ -26,7 +26,7 @@ using static RecastConstants;
public class RecastTest public class RecastTest
{ {
[Test] [Test]
public void testClearUnwalkableTriangles() public void TestClearUnwalkableTriangles()
{ {
float walkableSlopeAngle = 45; float walkableSlopeAngle = 45;
float[] verts = { 0, 0, 0, 1, 0, 0, 0, 0, -1 }; float[] verts = { 0, 0, 0, 1, 0, 0, 0, 0, -1 };
@ -38,18 +38,18 @@ public class RecastTest
Telemetry ctx = new Telemetry(); Telemetry ctx = new Telemetry();
{ {
int[] areas = { 42 }; int[] areas = { 42 };
Recast.clearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, unwalkable_tri, nt, areas); Recast.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, unwalkable_tri, nt, areas);
Assert.That(areas[0], Is.EqualTo(RC_NULL_AREA), "Sets area ID of unwalkable triangle to RC_NULL_AREA"); Assert.That(areas[0], Is.EqualTo(RC_NULL_AREA), "Sets area ID of unwalkable triangle to RC_NULL_AREA");
} }
{ {
int[] areas = { 42 }; int[] areas = { 42 };
Recast.clearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas); Recast.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas);
Assert.That(areas[0], Is.EqualTo(42), "Does not modify walkable triangle aread ID's"); Assert.That(areas[0], Is.EqualTo(42), "Does not modify walkable triangle aread ID's");
} }
{ {
int[] areas = { 42 }; int[] areas = { 42 };
walkableSlopeAngle = 0; walkableSlopeAngle = 0;
Recast.clearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas); Recast.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas);
Assert.That(areas[0], Is.EqualTo(RC_NULL_AREA), "Slopes equal to the max slope are considered unwalkable."); Assert.That(areas[0], Is.EqualTo(RC_NULL_AREA), "Slopes equal to the max slope are considered unwalkable.");
} }
} }

View File

@ -53,70 +53,70 @@ public class RecastTileMeshTest
private const int m_tileSize = 32; private const int m_tileSize = 32;
[Test] [Test]
public void testDungeon() public void TestDungeon()
{ {
testBuild("dungeon.obj"); TestBuild("dungeon.obj");
} }
public void testBuild(string filename) public void TestBuild(string filename)
{ {
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes(filename)); InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes(filename));
RecastBuilder builder = new RecastBuilder(); RecastBuilder builder = new RecastBuilder();
RecastConfig cfg = new RecastConfig(true, m_tileSize, m_tileSize, RecastConfig.calcBorder(m_agentRadius, m_cellSize), RecastConfig cfg = new RecastConfig(true, m_tileSize, m_tileSize, RecastConfig.CalcBorder(m_agentRadius, m_cellSize),
m_partitionType, m_cellSize, m_cellHeight, m_agentMaxSlope, true, true, true, m_agentHeight, m_agentRadius, m_partitionType, m_cellSize, m_cellHeight, m_agentMaxSlope, true, true, true, m_agentHeight, m_agentRadius,
m_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true, m_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true,
m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND); m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), 7, 8); RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 7, 8);
RecastBuilderResult rcResult = builder.build(geom, bcfg); RecastBuilderResult rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(1)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1));
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(5)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5));
bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), 6, 9); bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 6, 9);
rcResult = builder.build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(2)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(7)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(7));
bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), 2, 9); bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 9);
rcResult = builder.build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(2)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(9)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(9));
bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), 4, 3); bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 4, 3);
rcResult = builder.build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(3)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(3));
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(6)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(6));
bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), 2, 8); bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 8);
rcResult = builder.build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(5)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(5));
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(17)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(17));
bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), 0, 8); bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 0, 8);
rcResult = builder.build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(6)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(6));
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(15)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(15));
} }
[Test] [Test]
public void testPerformance() public void TestPerformance()
{ {
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("dungeon.obj")); InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
RecastBuilder builder = new RecastBuilder(); RecastBuilder builder = new RecastBuilder();
RecastConfig cfg = new RecastConfig(true, m_tileSize, m_tileSize, RecastConfig.calcBorder(m_agentRadius, m_cellSize), RecastConfig cfg = new RecastConfig(true, m_tileSize, m_tileSize, RecastConfig.CalcBorder(m_agentRadius, m_cellSize),
m_partitionType, m_cellSize, m_cellHeight, m_agentMaxSlope, true, true, true, m_agentHeight, m_agentRadius, m_partitionType, m_cellSize, m_cellHeight, m_agentMaxSlope, true, true, true, m_agentHeight, m_agentRadius,
m_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true, m_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true,
m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND); m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
build(geom, builder, cfg, 1, true); Build(geom, builder, cfg, 1, true);
build(geom, builder, cfg, 4, true); Build(geom, builder, cfg, 4, true);
} }
long t1 = FrequencyWatch.Ticks; long t1 = FrequencyWatch.Ticks;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
build(geom, builder, cfg, 1, false); Build(geom, builder, cfg, 1, false);
} }
long t2 = FrequencyWatch.Ticks; long t2 = FrequencyWatch.Ticks;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
build(geom, builder, cfg, 4, false); Build(geom, builder, cfg, 4, false);
} }
long t3 = FrequencyWatch.Ticks; long t3 = FrequencyWatch.Ticks;
@ -124,37 +124,37 @@ public class RecastTileMeshTest
Console.WriteLine(" Time MT : " + (t3 - t2) / TimeSpan.TicksPerMillisecond); Console.WriteLine(" Time MT : " + (t3 - t2) / TimeSpan.TicksPerMillisecond);
} }
private void build(InputGeomProvider geom, RecastBuilder builder, RecastConfig cfg, int threads, bool validate) private void Build(InputGeomProvider geom, RecastBuilder builder, RecastConfig cfg, int threads, bool validate)
{ {
CancellationTokenSource cts = new CancellationTokenSource(); CancellationTokenSource cts = new CancellationTokenSource();
List<RecastBuilderResult> tiles = new(); List<RecastBuilderResult> tiles = new();
var task = builder.buildTilesAsync(geom, cfg, threads, tiles, Task.Factory, cts.Token); var task = builder.BuildTilesAsync(geom, cfg, threads, tiles, Task.Factory, cts.Token);
if (validate) if (validate)
{ {
RecastBuilderResult rcResult = getTile(tiles, 7, 8); RecastBuilderResult rcResult = GetTile(tiles, 7, 8);
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(1)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1));
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(5)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5));
rcResult = getTile(tiles, 6, 9); rcResult = GetTile(tiles, 6, 9);
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(2)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(7)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(7));
rcResult = getTile(tiles, 2, 9); rcResult = GetTile(tiles, 2, 9);
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(2)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(9)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(9));
rcResult = getTile(tiles, 4, 3); rcResult = GetTile(tiles, 4, 3);
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(3)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(3));
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(6)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(6));
rcResult = getTile(tiles, 2, 8); rcResult = GetTile(tiles, 2, 8);
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(5)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(5));
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(17)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(17));
rcResult = getTile(tiles, 0, 8); rcResult = GetTile(tiles, 0, 8);
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(6)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(6));
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(15)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(15));
} }
try try
{ {
cts.Cancel(); cts.Cancel();
//executor.awaitTermination(1000, TimeUnit.HOURS); //executor.AwaitTermination(1000, TimeUnit.HOURS);
} }
catch (Exception e) catch (Exception e)
{ {
@ -162,7 +162,7 @@ public class RecastTileMeshTest
} }
} }
private RecastBuilderResult getTile(List<RecastBuilderResult> tiles, int x, int z) private RecastBuilderResult GetTile(List<RecastBuilderResult> tiles, int x, int z)
{ {
return tiles.FirstOrDefault(tile => tile.tileX == x && tile.tileZ == z); return tiles.FirstOrDefault(tile => tile.tileX == x && tile.tileZ == z);
} }