forked from bit/DotRecastNetSim
C# style function name
This commit is contained in:
parent
bef429e5dc
commit
ded8f33ac1
|
@ -6,12 +6,12 @@ namespace DotRecast.Core
|
|||
{
|
||||
private volatile int _location;
|
||||
|
||||
public bool set(bool v)
|
||||
public bool Set(bool v)
|
||||
{
|
||||
return 0 != Interlocked.Exchange(ref _location, v ? 1 : 0);
|
||||
}
|
||||
|
||||
public bool get()
|
||||
public bool Get()
|
||||
{
|
||||
return 0 != _location;
|
||||
}
|
||||
|
|
|
@ -19,34 +19,34 @@ namespace DotRecast.Core
|
|||
_position = 0;
|
||||
}
|
||||
|
||||
public ByteOrder order()
|
||||
public ByteOrder Order()
|
||||
{
|
||||
return _order;
|
||||
}
|
||||
|
||||
public void order(ByteOrder order)
|
||||
public void Order(ByteOrder order)
|
||||
{
|
||||
_order = order;
|
||||
}
|
||||
|
||||
public int limit()
|
||||
public int Limit()
|
||||
{
|
||||
return _bytes.Length - _position;
|
||||
}
|
||||
|
||||
public int remaining()
|
||||
public int Remaining()
|
||||
{
|
||||
int rem = limit();
|
||||
int rem = Limit();
|
||||
return rem > 0 ? rem : 0;
|
||||
}
|
||||
|
||||
|
||||
public void position(int pos)
|
||||
public void Position(int pos)
|
||||
{
|
||||
_position = pos;
|
||||
}
|
||||
|
||||
public int position()
|
||||
public int Position()
|
||||
{
|
||||
return _position;
|
||||
}
|
||||
|
@ -59,13 +59,13 @@ namespace DotRecast.Core
|
|||
return _bytes.AsSpan(nextPos, length);
|
||||
}
|
||||
|
||||
public byte get()
|
||||
public byte Get()
|
||||
{
|
||||
var span = ReadBytes(1);
|
||||
return span[0];
|
||||
}
|
||||
|
||||
public short getShort()
|
||||
public short GetShort()
|
||||
{
|
||||
var span = ReadBytes(2);
|
||||
if (_order == ByteOrder.BIG_ENDIAN)
|
||||
|
@ -79,7 +79,7 @@ namespace DotRecast.Core
|
|||
}
|
||||
|
||||
|
||||
public int getInt()
|
||||
public int GetInt()
|
||||
{
|
||||
var span = ReadBytes(4);
|
||||
if (_order == ByteOrder.BIG_ENDIAN)
|
||||
|
@ -92,7 +92,7 @@ namespace DotRecast.Core
|
|||
}
|
||||
}
|
||||
|
||||
public float getFloat()
|
||||
public float GetFloat()
|
||||
{
|
||||
var span = ReadBytes(4);
|
||||
if (_order == ByteOrder.BIG_ENDIAN && BitConverter.IsLittleEndian)
|
||||
|
@ -107,7 +107,7 @@ namespace DotRecast.Core
|
|||
return BitConverter.ToSingle(span);
|
||||
}
|
||||
|
||||
public long getLong()
|
||||
public long GetLong()
|
||||
{
|
||||
var span = ReadBytes(8);
|
||||
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)
|
||||
// {
|
||||
|
@ -134,7 +134,7 @@ namespace DotRecast.Core
|
|||
// ?
|
||||
}
|
||||
|
||||
public void putInt(int v)
|
||||
public void PutInt(int v)
|
||||
{
|
||||
// ?
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace DotRecast.Core
|
|||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace DotRecast.Core
|
|||
// Calculates convex hull on xz-plane of points on 'pts',
|
||||
// stores the indices of the resulting hull in 'out' and
|
||||
// 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;
|
||||
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 b = Vector3f.Of(pts[hull * 3], pts[hull * 3 + 1], pts[hull * 3 + 2]);
|
||||
if (cmppt(a, b))
|
||||
if (Cmppt(a, b))
|
||||
{
|
||||
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 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]);
|
||||
if (hull == endpt || left(a, b, c))
|
||||
if (hull == endpt || Left(a, b, c))
|
||||
{
|
||||
endpt = j;
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ namespace DotRecast.Core
|
|||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -91,7 +91,7 @@ namespace DotRecast.Core
|
|||
}
|
||||
|
||||
// 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 v1 = b.z - a.z;
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace DotRecast.Core
|
|||
r = new Random((int)seed); // TODO : 랜덤 시드 확인 필요
|
||||
}
|
||||
|
||||
public float frand()
|
||||
public float Frand()
|
||||
{
|
||||
return (float)r.NextDouble();
|
||||
}
|
||||
|
|
|
@ -24,20 +24,20 @@ namespace DotRecast.Core
|
|||
{
|
||||
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;
|
||||
Vector3f ab = vSub(b, a);
|
||||
Vector3f ac = vSub(c, a);
|
||||
Vector3f qp = vSub(sp, sq);
|
||||
Vector3f ab = VSub(b, a);
|
||||
Vector3f ac = VSub(c, a);
|
||||
Vector3f qp = VSub(sp, sq);
|
||||
|
||||
// Compute triangle normal. Can be precalculated or cached if
|
||||
// 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
|
||||
// away from triangle, so exit early
|
||||
float d = vDot(qp, norm);
|
||||
float d = VDot(qp, norm);
|
||||
if (d <= 0.0f)
|
||||
{
|
||||
return null;
|
||||
|
@ -46,8 +46,8 @@ namespace DotRecast.Core
|
|||
// Compute intersection t value of pq with plane of triangle. A ray
|
||||
// intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay
|
||||
// dividing by d until intersection has been found to pierce triangle
|
||||
Vector3f ap = vSub(sp, a);
|
||||
float t = vDot(ap, norm);
|
||||
Vector3f ap = VSub(sp, a);
|
||||
float t = VDot(ap, norm);
|
||||
if (t < 0.0f)
|
||||
{
|
||||
return null;
|
||||
|
@ -59,14 +59,14 @@ namespace DotRecast.Core
|
|||
}
|
||||
|
||||
// Compute barycentric coordinate components and test if within bounds
|
||||
Vector3f e = vCross(qp, ap);
|
||||
v = vDot(ac, e);
|
||||
Vector3f e = VCross(qp, ap);
|
||||
v = VDot(ac, e);
|
||||
if (v < 0.0f || v > d)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
w = -vDot(ab, e);
|
||||
w = -VDot(ab, e);
|
||||
if (w < 0.0f || v + w > d)
|
||||
{
|
||||
return null;
|
||||
|
@ -78,7 +78,7 @@ namespace DotRecast.Core
|
|||
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;
|
||||
|
||||
|
|
|
@ -26,9 +26,9 @@ namespace DotRecast.Core
|
|||
public static class RecastMath
|
||||
{
|
||||
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 dy = v2[i + 1] - v1.y;
|
||||
|
@ -36,7 +36,7 @@ namespace DotRecast.Core
|
|||
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 dy = v2.y - v1.y;
|
||||
|
@ -44,7 +44,7 @@ namespace DotRecast.Core
|
|||
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 dy = v[i + 1] - v[j + 1];
|
||||
|
@ -52,7 +52,7 @@ namespace DotRecast.Core
|
|||
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();
|
||||
dest.x = v1.y * v2.z - v1.z * v2.y;
|
||||
|
@ -61,22 +61,22 @@ namespace DotRecast.Core
|
|||
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;
|
||||
}
|
||||
|
||||
public static float sqr(float f)
|
||||
public static float Sqr(float f)
|
||||
{
|
||||
return f * f;
|
||||
}
|
||||
|
||||
public static float getPathLen(float[] path, int npath)
|
||||
public static float GetPathLen(float[] path, int npath)
|
||||
{
|
||||
float totd = 0;
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ namespace DotRecast.Core
|
|||
/// @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] 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();
|
||||
dest.x = v1.x + v2.x * s;
|
||||
|
@ -119,7 +119,7 @@ namespace DotRecast.Core
|
|||
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();
|
||||
dest.x = v1[0] + v2.x * s;
|
||||
|
@ -136,7 +136,7 @@ namespace DotRecast.Core
|
|||
/// @param[in] v1 The starting vector.
|
||||
/// @param[in] v2 The destination vector.
|
||||
/// @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();
|
||||
dest.x = verts[v1 + 0] + (verts[v2 + 0] - verts[v1 + 0]) * t;
|
||||
|
@ -145,7 +145,7 @@ namespace DotRecast.Core
|
|||
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();
|
||||
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();
|
||||
dest.x = v1.get(0) - v2.get(0);
|
||||
dest.y = v1.get(1) - v2.get(1);
|
||||
dest.z = v1.get(2) - v2.get(2);
|
||||
dest.x = v1.Get(0) - v2.Get(0);
|
||||
dest.y = v1.Get(1) - v2.Get(1);
|
||||
dest.z = v1.Get(2) - v2.Get(2);
|
||||
return dest;
|
||||
}
|
||||
|
||||
public static Vector3f vSub(Vector3f v1, Vector3f v2)
|
||||
public static Vector3f VSub(Vector3f v1, Vector3f v2)
|
||||
{
|
||||
Vector3f dest = new Vector3f();
|
||||
dest.x = v1.x - v2.x;
|
||||
|
@ -173,17 +173,17 @@ namespace DotRecast.Core
|
|||
return dest;
|
||||
}
|
||||
|
||||
public static Vector3f vSub(Vector3f v1, VectorPtr v2)
|
||||
public static Vector3f VSub(Vector3f v1, VectorPtr v2)
|
||||
{
|
||||
Vector3f dest = new Vector3f();
|
||||
dest.x = v1.x - v2.get(0);
|
||||
dest.y = v1.y - v2.get(1);
|
||||
dest.z = v1.z - v2.get(2);
|
||||
dest.x = v1.x - v2.Get(0);
|
||||
dest.y = v1.y - v2.Get(1);
|
||||
dest.z = v1.z - v2.Get(2);
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
public static Vector3f vSub(Vector3f v1, float[] v2)
|
||||
public static Vector3f VSub(Vector3f v1, float[] v2)
|
||||
{
|
||||
Vector3f dest = new Vector3f();
|
||||
dest.x = v1.x - v2[0];
|
||||
|
@ -192,7 +192,7 @@ namespace DotRecast.Core
|
|||
return dest;
|
||||
}
|
||||
|
||||
public static Vector3f vAdd(Vector3f v1, Vector3f v2)
|
||||
public static Vector3f VAdd(Vector3f v1, Vector3f v2)
|
||||
{
|
||||
Vector3f dest = new Vector3f();
|
||||
dest.x = v1.x + v2.x;
|
||||
|
@ -201,42 +201,42 @@ namespace DotRecast.Core
|
|||
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.y = b;
|
||||
@out.z = c;
|
||||
}
|
||||
|
||||
public static void vCopy(float[] @out, Vector3f @in)
|
||||
public static void VCopy(float[] @out, Vector3f @in)
|
||||
{
|
||||
@out[0] = @in.x;
|
||||
@out[1] = @in.y;
|
||||
@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.y = @in[1];
|
||||
@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.y = @in[i + 1];
|
||||
@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[1] = Math.Min(@out[1], @in[i + 1]);
|
||||
@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.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[1] = Math.Max(@out[1], @in[i + 1]);
|
||||
@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.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] v2 A point. [(x, y, z)]
|
||||
/// @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 dy = v2[1] - v1[1];
|
||||
|
@ -271,7 +271,7 @@ namespace DotRecast.Core
|
|||
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 dy = v2[1] - v1.y;
|
||||
|
@ -279,7 +279,7 @@ namespace DotRecast.Core
|
|||
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 dy = v2.y - v1.y;
|
||||
|
@ -293,7 +293,7 @@ namespace DotRecast.Core
|
|||
/// @param[in] v1 A point. [(x, y, z)]
|
||||
/// @param[in] v2 A point. [(x, y, z)]
|
||||
/// @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 dy = v2[1] - v1[1];
|
||||
|
@ -306,29 +306,29 @@ namespace DotRecast.Core
|
|||
/// Derives the square of the scalar length of the vector. (len * len)
|
||||
/// @param[in] v The vector. [(x, y, z)]
|
||||
/// @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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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 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
|
||||
/// ignored.
|
||||
public static float vDist2D(float[] v1, float[] v2)
|
||||
public static float VDist2D(float[] v1, float[] v2)
|
||||
{
|
||||
float dx = v2[0] - v1[0];
|
||||
float dz = v2[2] - v1[2];
|
||||
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 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 dz = v2[2] - v1[2];
|
||||
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 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 dz = verts[i + 2] - p.z;
|
||||
|
@ -383,9 +383,9 @@ namespace DotRecast.Core
|
|||
|
||||
/// Normalizes the vector.
|
||||
/// @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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
v.x *= d;
|
||||
|
@ -413,26 +413,26 @@ namespace DotRecast.Core
|
|||
///
|
||||
/// Basically, this function will return true if the specified points are
|
||||
/// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -444,18 +444,18 @@ namespace DotRecast.Core
|
|||
///
|
||||
/// The vectors are projected onto the xz-plane, so the y-values are
|
||||
/// 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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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];
|
||||
}
|
||||
|
@ -467,12 +467,12 @@ namespace DotRecast.Core
|
|||
///
|
||||
/// The vectors are projected onto the xz-plane, so the y-values are
|
||||
/// 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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -487,7 +487,7 @@ namespace DotRecast.Core
|
|||
/// @param[in] b Vertex B. [(x, y, z)]
|
||||
/// @param[in] c Vertex C. [(x, y, z)]
|
||||
/// @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 abz = verts[b + 2] - verts[a + 2];
|
||||
|
@ -496,7 +496,7 @@ namespace DotRecast.Core
|
|||
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 abz = b[2] - a[2];
|
||||
|
@ -505,7 +505,7 @@ namespace DotRecast.Core
|
|||
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 abz = b.z - a.z;
|
||||
|
@ -514,7 +514,7 @@ namespace DotRecast.Core
|
|||
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 abz = b[2] - a.z;
|
||||
|
@ -532,7 +532,7 @@ namespace DotRecast.Core
|
|||
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
||||
/// @return True if the two AABB's overlap.
|
||||
/// @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;
|
||||
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)]
|
||||
/// @return True if the two AABB's overlap.
|
||||
/// @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;
|
||||
overlap = (amin[0]> bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||
|
@ -557,7 +557,7 @@ namespace DotRecast.Core
|
|||
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;
|
||||
overlap = (amin.x > bmax.x || amax.x < bmin.x) ? false : overlap;
|
||||
|
@ -566,7 +566,7 @@ namespace DotRecast.Core
|
|||
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 pqz = q.z - p.z;
|
||||
|
@ -593,11 +593,11 @@ namespace DotRecast.Core
|
|||
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 v1 = vSub(b, a);
|
||||
Vector3f v2 = vSub(p, a);
|
||||
Vector3f v0 = VSub(c, a);
|
||||
Vector3f v1 = VSub(b, a);
|
||||
Vector3f v2 = VSub(p, a);
|
||||
|
||||
// Compute scaled barycentric coordinates
|
||||
float denom = v0.x * v1.z - v0.z * v1.x;
|
||||
|
@ -629,7 +629,7 @@ namespace DotRecast.Core
|
|||
/// @par
|
||||
///
|
||||
/// 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?
|
||||
int i, j;
|
||||
|
@ -648,7 +648,7 @@ namespace DotRecast.Core
|
|||
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?
|
||||
int i, j;
|
||||
|
@ -663,7 +663,7 @@ namespace DotRecast.Core
|
|||
c = !c;
|
||||
}
|
||||
|
||||
Tuple<float, float> edet = distancePtSegSqr2D(pt, verts, vj, vi);
|
||||
Tuple<float, float> edet = DistancePtSegSqr2D(pt, verts, vj, vi);
|
||||
ed[j] = edet.Item1;
|
||||
et[j] = edet.Item2;
|
||||
}
|
||||
|
@ -671,13 +671,13 @@ namespace DotRecast.Core
|
|||
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;
|
||||
rmin = rmax = vDot2D(axis, poly, 0);
|
||||
rmin = rmax = VDot2D(axis, poly, 0);
|
||||
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);
|
||||
rmax = Math.Max(rmax, d);
|
||||
}
|
||||
|
@ -685,7 +685,7 @@ namespace DotRecast.Core
|
|||
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;
|
||||
}
|
||||
|
@ -695,7 +695,7 @@ namespace DotRecast.Core
|
|||
/// @par
|
||||
///
|
||||
/// 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++)
|
||||
{
|
||||
|
@ -704,9 +704,9 @@ namespace DotRecast.Core
|
|||
|
||||
Vector3f n = Vector3f.Of(polya[vb + 2] - polya[va + 2], 0, -(polya[vb + 0] - polya[va + 0]));
|
||||
|
||||
float[] aminmax = projectPoly(n, polya, npolya);
|
||||
float[] bminmax = projectPoly(n, polyb, npolyb);
|
||||
if (!overlapRange(aminmax[0], aminmax[1], bminmax[0], bminmax[1], eps))
|
||||
float[] aminmax = ProjectPoly(n, polya, npolya);
|
||||
float[] bminmax = ProjectPoly(n, polyb, npolyb);
|
||||
if (!OverlapRange(aminmax[0], aminmax[1], bminmax[0], bminmax[1], eps))
|
||||
{
|
||||
// Found separating axis
|
||||
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]));
|
||||
|
||||
float[] aminmax = projectPoly(n, polya, npolya);
|
||||
float[] bminmax = projectPoly(n, polyb, npolyb);
|
||||
if (!overlapRange(aminmax[0], aminmax[1], bminmax[0], bminmax[1], eps))
|
||||
float[] aminmax = ProjectPoly(n, polya, npolya);
|
||||
float[] bminmax = ProjectPoly(n, polyb, npolyb);
|
||||
if (!OverlapRange(aminmax[0], aminmax[1], bminmax[0], bminmax[1], eps))
|
||||
{
|
||||
// Found separating axis
|
||||
return false;
|
||||
|
@ -734,13 +734,13 @@ namespace DotRecast.Core
|
|||
|
||||
// Returns a random point in a convex polygon.
|
||||
// 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
|
||||
float areasum = 0.0f;
|
||||
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]);
|
||||
}
|
||||
|
||||
|
@ -779,7 +779,7 @@ namespace DotRecast.Core
|
|||
};
|
||||
}
|
||||
|
||||
public static int nextPow2(int v)
|
||||
public static int NextPow2(int v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
|
@ -791,7 +791,7 @@ namespace DotRecast.Core
|
|||
return v;
|
||||
}
|
||||
|
||||
public static int ilog2(int v)
|
||||
public static int Ilog2(int v)
|
||||
{
|
||||
int r;
|
||||
int shift;
|
||||
|
@ -819,20 +819,20 @@ namespace DotRecast.Core
|
|||
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();
|
||||
float EPS = 0.000001f;
|
||||
var dir = vSub(p1, p0);
|
||||
var dir = VSub(p1, p0);
|
||||
|
||||
var p0v = p0;
|
||||
for (int i = 0, j = nverts - 1; i < nverts; j = i++)
|
||||
{
|
||||
VectorPtr vpj = new VectorPtr(verts, j * 3);
|
||||
var edge = vSub(new VectorPtr(verts, i * 3), vpj);
|
||||
var diff = vSub(p0v, vpj);
|
||||
float n = vPerp2D(edge, diff);
|
||||
float d = vPerp2D(dir, edge);
|
||||
var edge = VSub(new VectorPtr(verts, i * 3), vpj);
|
||||
var diff = VSub(p0v, vpj);
|
||||
float n = VPerp2D(edge, diff);
|
||||
float d = VPerp2D(dir, edge);
|
||||
if (Math.Abs(d) < EPS)
|
||||
{
|
||||
// S is nearly parallel to this edge
|
||||
|
@ -881,7 +881,7 @@ namespace DotRecast.Core
|
|||
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 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 pqz = verts[q + 2] - verts[p + 2];
|
||||
|
@ -936,38 +936,38 @@ namespace DotRecast.Core
|
|||
return Tuple.Create(dx * dx + dz * dz, t);
|
||||
}
|
||||
|
||||
public static int oppositeTile(int side)
|
||||
public static int OppositeTile(int side)
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 v = vSub(bq, bp);
|
||||
Vector3f w = vSub(ap, bp);
|
||||
float d = vperpXZ(u, v);
|
||||
Vector3f u = VSub(aq, ap);
|
||||
Vector3f v = VSub(bq, bp);
|
||||
Vector3f w = VSub(ap, bp);
|
||||
float d = VperpXZ(u, v);
|
||||
if (Math.Abs(d) < 1e-6f)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
float s = vperpXZ(v, w) / d;
|
||||
float t = vperpXZ(u, w) / d;
|
||||
float s = VperpXZ(v, w) / d;
|
||||
float t = VperpXZ(u, w) / d;
|
||||
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();
|
||||
@out.x = @in.x * scale;
|
||||
|
@ -981,24 +981,24 @@ namespace DotRecast.Core
|
|||
/// @param[in] v A point. [(x, y, z)]
|
||||
/// @return True if all of the point's components are finite, i.e. not NaN
|
||||
/// 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]);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/// Checks that the specified vector's 2D components are finite.
|
||||
/// @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]);
|
||||
}
|
||||
|
||||
public static bool vIsFinite2D(Vector3f v)
|
||||
public static bool VIsFinite2D(Vector3f v)
|
||||
{
|
||||
return float.IsFinite(v.x) && float.IsFinite(v.z);
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace DotRecast.Core
|
|||
this.index = index;
|
||||
}
|
||||
|
||||
public float get(int offset)
|
||||
public float Get(int offset)
|
||||
{
|
||||
return array[index + offset];
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -135,35 +135,35 @@ namespace DotRecast.Detour.Crowd
|
|||
animation = new CrowdAgentAnimation();
|
||||
}
|
||||
|
||||
public void integrate(float dt)
|
||||
public void Integrate(float dt)
|
||||
{
|
||||
// Fake dynamic constraint.
|
||||
float maxDelta = option.maxAcceleration * dt;
|
||||
Vector3f dv = vSub(nvel, vel);
|
||||
float ds = vLen(dv);
|
||||
Vector3f dv = VSub(nvel, vel);
|
||||
float ds = VLen(dv);
|
||||
if (ds > maxDelta)
|
||||
dv = vScale(dv, maxDelta / ds);
|
||||
vel = vAdd(vel, dv);
|
||||
dv = VScale(dv, maxDelta / ds);
|
||||
vel = VAdd(vel, dv);
|
||||
|
||||
// Integrate
|
||||
if (vLen(vel) > 0.0001f)
|
||||
npos = vMad(npos, vel, dt);
|
||||
if (VLen(vel) > 0.0001f)
|
||||
npos = VMad(npos, vel, dt);
|
||||
else
|
||||
vel = Vector3f.Zero;
|
||||
}
|
||||
|
||||
public bool overOffmeshConnection(float radius)
|
||||
public bool OverOffmeshConnection(float radius)
|
||||
{
|
||||
if (0 == corners.Count)
|
||||
return false;
|
||||
|
||||
bool offMeshConnection = ((corners[corners.Count - 1].getFlags()
|
||||
bool offMeshConnection = ((corners[corners.Count - 1].GetFlags()
|
||||
& NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|
||||
? true
|
||||
: false;
|
||||
if (offMeshConnection)
|
||||
{
|
||||
float distSq = vDist2DSqr(npos, corners[corners.Count - 1].getPos());
|
||||
float distSq = VDist2DSqr(npos, corners[corners.Count - 1].GetPos());
|
||||
if (distSq < radius * radius)
|
||||
return true;
|
||||
}
|
||||
|
@ -171,62 +171,62 @@ namespace DotRecast.Detour.Crowd
|
|||
return false;
|
||||
}
|
||||
|
||||
public float getDistanceToGoal(float range)
|
||||
public float GetDistanceToGoal(float range)
|
||||
{
|
||||
if (0 == corners.Count)
|
||||
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)
|
||||
return Math.Min(vDist2D(npos, corners[corners.Count - 1].getPos()), range);
|
||||
return Math.Min(VDist2D(npos, corners[corners.Count - 1].GetPos()), range);
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
public Vector3f calcSmoothSteerDirection()
|
||||
public Vector3f CalcSmoothSteerDirection()
|
||||
{
|
||||
Vector3f dir = new Vector3f();
|
||||
if (0 < corners.Count)
|
||||
{
|
||||
int ip0 = 0;
|
||||
int ip1 = Math.Min(1, corners.Count - 1);
|
||||
var p0 = corners[ip0].getPos();
|
||||
var p1 = corners[ip1].getPos();
|
||||
var p0 = corners[ip0].GetPos();
|
||||
var p1 = corners[ip1].GetPos();
|
||||
|
||||
var dir0 = vSub(p0, npos);
|
||||
var dir1 = vSub(p1, npos);
|
||||
var dir0 = VSub(p0, npos);
|
||||
var dir1 = VSub(p1, npos);
|
||||
dir0.y = 0;
|
||||
dir1.y = 0;
|
||||
|
||||
float len0 = vLen(dir0);
|
||||
float len1 = vLen(dir1);
|
||||
float len0 = VLen(dir0);
|
||||
float len1 = VLen(dir1);
|
||||
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.y = 0;
|
||||
dir.z = dir0.z - dir1.z * len0 * 0.5f;
|
||||
|
||||
vNormalize(ref dir);
|
||||
VNormalize(ref dir);
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
public Vector3f calcStraightSteerDirection()
|
||||
public Vector3f CalcStraightSteerDirection()
|
||||
{
|
||||
Vector3f dir = new Vector3f();
|
||||
if (0 < corners.Count)
|
||||
{
|
||||
dir = vSub(corners[0].getPos(), npos);
|
||||
dir = VSub(corners[0].GetPos(), npos);
|
||||
dir.y = 0;
|
||||
vNormalize(ref dir);
|
||||
VNormalize(ref dir);
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
public void setTarget(long refs, Vector3f pos)
|
||||
public void SetTarget(long refs, Vector3f pos)
|
||||
{
|
||||
targetRef = refs;
|
||||
targetPos = pos;
|
||||
|
|
|
@ -54,11 +54,11 @@ namespace DotRecast.Detour.Crowd
|
|||
public const int DT_CROWD_SEPARATION = 4;
|
||||
public const int DT_CROWD_OPTIMIZE_VIS = 8;
|
||||
|
||||
/// < Use #dtPathCorridor::optimizePathVisibility() to optimize
|
||||
/// < Use #dtPathCorridor::OptimizePathVisibility() to optimize
|
||||
/// the agent path.
|
||||
public const int DT_CROWD_OPTIMIZE_TOPO = 16;
|
||||
|
||||
/// < Use dtPathCorridor::optimizePathTopology() to optimize
|
||||
/// < Use dtPathCorridor::OptimizePathTopology() to optimize
|
||||
/// the agent path.
|
||||
/// Flags that impact steering behavior. (See: #UpdateFlags)
|
||||
public int updateFlags;
|
||||
|
|
|
@ -32,44 +32,44 @@ namespace DotRecast.Detour.Crowd
|
|||
private readonly Dictionary<string, long> _executionTimings = new Dictionary<string, long>();
|
||||
private readonly Dictionary<string, List<long>> _executionTimingSamples = new Dictionary<string, List<long>>();
|
||||
|
||||
public float maxTimeToEnqueueRequest()
|
||||
public float MaxTimeToEnqueueRequest()
|
||||
{
|
||||
return _maxTimeToEnqueueRequest;
|
||||
}
|
||||
|
||||
public float maxTimeToFindPath()
|
||||
public float MaxTimeToFindPath()
|
||||
{
|
||||
return _maxTimeToFindPath;
|
||||
}
|
||||
|
||||
public Dictionary<string, long> executionTimings()
|
||||
public Dictionary<string, long> ExecutionTimings()
|
||||
{
|
||||
return _executionTimings;
|
||||
}
|
||||
|
||||
public void start()
|
||||
public void Start()
|
||||
{
|
||||
_maxTimeToEnqueueRequest = 0;
|
||||
_maxTimeToFindPath = 0;
|
||||
_executionTimings.Clear();
|
||||
}
|
||||
|
||||
public void recordMaxTimeToEnqueueRequest(float time)
|
||||
public void RecordMaxTimeToEnqueueRequest(float time)
|
||||
{
|
||||
_maxTimeToEnqueueRequest = Math.Max(_maxTimeToEnqueueRequest, time);
|
||||
}
|
||||
|
||||
public void recordMaxTimeToFindPath(float time)
|
||||
public void RecordMaxTimeToFindPath(float time)
|
||||
{
|
||||
_maxTimeToFindPath = Math.Max(_maxTimeToFindPath, time);
|
||||
}
|
||||
|
||||
public void start(string name)
|
||||
public void Start(string name)
|
||||
{
|
||||
_executionTimings.Add(name, FrequencyWatch.Ticks);
|
||||
}
|
||||
|
||||
public void stop(string name)
|
||||
public void Stop(string name)
|
||||
{
|
||||
long duration = FrequencyWatch.Ticks - _executionTimings[name];
|
||||
if (!_executionTimingSamples.TryGetValue(name, out var s))
|
||||
|
|
|
@ -49,14 +49,14 @@ namespace DotRecast.Detour.Crowd
|
|||
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_polys.Clear();
|
||||
m_segs.Clear();
|
||||
}
|
||||
|
||||
protected void addSegment(float dist, SegmentVert s)
|
||||
protected void AddSegment(float dist, SegmentVert s)
|
||||
{
|
||||
// Insert neighbour based on the distance.
|
||||
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)
|
||||
{
|
||||
reset();
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
m_center = pos;
|
||||
// First query non-overlapping polygons.
|
||||
Result<FindLocalNeighbourhoodResult> res = navquery.findLocalNeighbourhood(refs, pos, collisionQueryRange,
|
||||
Result<FindLocalNeighbourhoodResult> res = navquery.FindLocalNeighbourhood(refs, pos, collisionQueryRange,
|
||||
filter);
|
||||
if (res.Succeeded())
|
||||
{
|
||||
m_polys = res.result.getRefs();
|
||||
m_polys = res.result.GetRefs();
|
||||
m_segs.Clear();
|
||||
// Secondly, store all polygon edges.
|
||||
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())
|
||||
{
|
||||
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.
|
||||
Tuple<float, float> distseg = distancePtSegSqr2D(pos, s, 0, 3);
|
||||
if (distseg.Item1 > sqr(collisionQueryRange))
|
||||
Tuple<float, float> distseg = DistancePtSegSqr2D(pos, s, 0, 3);
|
||||
if (distseg.Item1 > Sqr(collisionQueryRange))
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -148,7 +148,7 @@ namespace DotRecast.Detour.Crowd
|
|||
// Check that all polygons still pass query filter.
|
||||
foreach (long refs in m_polys)
|
||||
{
|
||||
if (!navquery.isValidPolyRef(refs, filter))
|
||||
if (!navquery.IsValidPolyRef(refs, filter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -157,17 +157,17 @@ namespace DotRecast.Detour.Crowd
|
|||
return true;
|
||||
}
|
||||
|
||||
public Vector3f getCenter()
|
||||
public Vector3f GetCenter()
|
||||
{
|
||||
return m_center;
|
||||
}
|
||||
|
||||
public Vector3f[] getSegment(int j)
|
||||
public Vector3f[] GetSegment(int j)
|
||||
{
|
||||
return m_segs[j].s;
|
||||
}
|
||||
|
||||
public int getSegmentCount()
|
||||
public int GetSegmentCount()
|
||||
{
|
||||
return m_segs.Count;
|
||||
}
|
||||
|
|
|
@ -98,13 +98,13 @@ namespace DotRecast.Detour.Crowd
|
|||
}
|
||||
}
|
||||
|
||||
public void reset()
|
||||
public void Reset()
|
||||
{
|
||||
m_ncircles = 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)
|
||||
return;
|
||||
|
@ -116,7 +116,7 @@ namespace DotRecast.Detour.Crowd
|
|||
cir.dvel = dvel;
|
||||
}
|
||||
|
||||
public void addSegment(Vector3f p, Vector3f q)
|
||||
public void AddSegment(Vector3f p, Vector3f q)
|
||||
{
|
||||
if (m_nsegments >= m_maxSegments)
|
||||
return;
|
||||
|
@ -126,27 +126,27 @@ namespace DotRecast.Detour.Crowd
|
|||
seg.q = q;
|
||||
}
|
||||
|
||||
public int getObstacleCircleCount()
|
||||
public int GetObstacleCircleCount()
|
||||
{
|
||||
return m_ncircles;
|
||||
}
|
||||
|
||||
public ObstacleCircle getObstacleCircle(int i)
|
||||
public ObstacleCircle GetObstacleCircle(int i)
|
||||
{
|
||||
return m_circles[i];
|
||||
}
|
||||
|
||||
public int getObstacleSegmentCount()
|
||||
public int GetObstacleSegmentCount()
|
||||
{
|
||||
return m_nsegments;
|
||||
}
|
||||
|
||||
public ObstacleSegment getObstacleSegment(int i)
|
||||
public ObstacleSegment GetObstacleSegment(int i)
|
||||
{
|
||||
return m_segments[i];
|
||||
}
|
||||
|
||||
private void prepare(Vector3f pos, Vector3f dvel)
|
||||
private void Prepare(Vector3f pos, Vector3f dvel)
|
||||
{
|
||||
// Prepare obstacles
|
||||
for (int i = 0; i < m_ncircles; ++i)
|
||||
|
@ -159,11 +159,11 @@ namespace DotRecast.Detour.Crowd
|
|||
|
||||
Vector3f orig = new Vector3f();
|
||||
Vector3f dv = new Vector3f();
|
||||
cir.dp = vSub(pb, pa);
|
||||
vNormalize(ref cir.dp);
|
||||
dv = vSub(cir.dvel, dvel);
|
||||
cir.dp = VSub(pb, pa);
|
||||
VNormalize(ref cir.dp);
|
||||
dv = VSub(cir.dvel, dvel);
|
||||
|
||||
float a = triArea2D(orig, cir.dp, dv);
|
||||
float a = TriArea2D(orig, cir.dp, dv);
|
||||
if (a < 0.01f)
|
||||
{
|
||||
cir.np.x = -cir.dp.z;
|
||||
|
@ -182,23 +182,23 @@ namespace DotRecast.Detour.Crowd
|
|||
|
||||
// Precalc if the agent is really close to the segment.
|
||||
float r = 0.01f;
|
||||
Tuple<float, float> dt = distancePtSegSqr2D(pos, seg.p, seg.q);
|
||||
seg.touch = dt.Item1 < sqr(r);
|
||||
Tuple<float, float> dt = DistancePtSegSqr2D(pos, seg.p, seg.q);
|
||||
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;
|
||||
Vector3f s = vSub(c1, c0);
|
||||
Vector3f s = VSub(c1, c0);
|
||||
float r = r0 + r1;
|
||||
float c = vDot2D(s, s) - r * r;
|
||||
float a = vDot2D(v, v);
|
||||
float c = VDot2D(s, s) - r * r;
|
||||
float a = VDot2D(v, v);
|
||||
if (a < EPS)
|
||||
return new SweepCircleCircleResult(false, 0f, 0f); // not moving
|
||||
|
||||
// Overlap, calc time to exit.
|
||||
float b = vDot2D(v, s);
|
||||
float b = VDot2D(v, s);
|
||||
float d = b * b - a * c;
|
||||
if (d < 0.0f)
|
||||
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);
|
||||
}
|
||||
|
||||
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 w = vSub(ap, bp);
|
||||
float d = vPerp2D(u, v);
|
||||
Vector3f v = VSub(bq, bp);
|
||||
Vector3f w = VSub(ap, bp);
|
||||
float d = VPerp2D(u, v);
|
||||
if (Math.Abs(d) < 1e-6f)
|
||||
return new IsectRaySegResult(false, 0f);
|
||||
|
||||
d = 1.0f / d;
|
||||
float t = vPerp2D(v, w) * d;
|
||||
float t = VPerp2D(v, w) * d;
|
||||
if (t < 0 || t > 1)
|
||||
return new IsectRaySegResult(false, 0f);
|
||||
|
||||
float s = vPerp2D(u, w) * d;
|
||||
float s = VPerp2D(u, w) * d;
|
||||
if (s < 0 || s > 1)
|
||||
return new IsectRaySegResult(false, 0f);
|
||||
|
||||
|
@ -237,12 +237,12 @@ namespace DotRecast.Detour.Crowd
|
|||
* @param minPenalty
|
||||
* 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)
|
||||
{
|
||||
// penalty for straying away from the desired and current velocities
|
||||
float vpen = m_params.weightDesVel * (vDist2D(vcand, dvel) * m_invVmax);
|
||||
float vcpen = m_params.weightCurVel * (vDist2D(vcand, vel) * m_invVmax);
|
||||
float vpen = m_params.weightDesVel * (VDist2D(vcand, dvel) * 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
|
||||
// (see how the penalty is calculated below to understnad)
|
||||
|
@ -261,15 +261,15 @@ namespace DotRecast.Detour.Crowd
|
|||
ObstacleCircle cir = m_circles[i];
|
||||
|
||||
// RVO
|
||||
Vector3f vab = vScale(vcand, 2);
|
||||
vab = vSub(vab, vel);
|
||||
vab = vSub(vab, cir.vel);
|
||||
Vector3f vab = VScale(vcand, 2);
|
||||
vab = VSub(vab, vel);
|
||||
vab = VSub(vab, cir.vel);
|
||||
|
||||
// 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++;
|
||||
|
||||
SweepCircleCircleResult sres = sweepCircleCircle(pos, rad, vab, cir.p, cir.rad);
|
||||
SweepCircleCircleResult sres = SweepCircleCircle(pos, rad, vab, cir.p, cir.rad);
|
||||
if (!sres.intersection)
|
||||
continue;
|
||||
float htmin = sres.htmin, htmax = sres.htmax;
|
||||
|
@ -301,19 +301,19 @@ namespace DotRecast.Detour.Crowd
|
|||
if (seg.touch)
|
||||
{
|
||||
// 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();
|
||||
snorm.x = -sdir.z;
|
||||
snorm.z = sdir.x;
|
||||
// If the velocity is pointing towards the segment, no collision.
|
||||
if (vDot2D(snorm, vcand) < 0.0f)
|
||||
if (VDot2D(snorm, vcand) < 0.0f)
|
||||
continue;
|
||||
// Else immediate collision.
|
||||
htmin = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ires = isectRaySeg(pos, vcand, seg.p, seg.q);
|
||||
var ires = IsectRaySeg(pos, vcand, seg.p, seg.q);
|
||||
if (!ires.result)
|
||||
continue;
|
||||
|
||||
|
@ -342,15 +342,15 @@ namespace DotRecast.Detour.Crowd
|
|||
float penalty = vpen + vcpen + spen + tpen;
|
||||
// Store different penalties for debug viewing
|
||||
if (debug != null)
|
||||
debug.addSample(vcand, cs, penalty, vpen, vcpen, spen, tpen);
|
||||
debug.AddSample(vcand, cs, penalty, vpen, vcpen, spen, tpen);
|
||||
|
||||
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)
|
||||
{
|
||||
prepare(pos, dvel);
|
||||
Prepare(pos, dvel);
|
||||
m_params = option;
|
||||
m_invHorizTime = 1.0f / m_params.horizTime;
|
||||
m_vmax = vmax;
|
||||
|
@ -359,7 +359,7 @@ namespace DotRecast.Detour.Crowd
|
|||
Vector3f nvel = Vector3f.Zero;
|
||||
|
||||
if (debug != null)
|
||||
debug.reset();
|
||||
debug.Reset();
|
||||
|
||||
float cvx = dvel.x * 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)
|
||||
{
|
||||
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;
|
||||
|
||||
float penalty = processSample(vcand, cs, pos, rad, vel, dvel, minPenalty, debug);
|
||||
float penalty = ProcessSample(vcand, cs, pos, rad, vel, dvel, minPenalty, debug);
|
||||
ns++;
|
||||
if (penalty < minPenalty)
|
||||
{
|
||||
|
@ -393,7 +393,7 @@ namespace DotRecast.Detour.Crowd
|
|||
}
|
||||
|
||||
// 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]);
|
||||
if (d == 0)
|
||||
|
@ -404,7 +404,7 @@ namespace DotRecast.Detour.Crowd
|
|||
}
|
||||
|
||||
// vector normalization that ignores the y-component.
|
||||
Vector3f dtRotate2D(float[] v, float ang)
|
||||
Vector3f DtRotate2D(float[] v, float ang)
|
||||
{
|
||||
Vector3f dest = new Vector3f();
|
||||
float c = (float)Math.Cos(ang);
|
||||
|
@ -417,10 +417,10 @@ namespace DotRecast.Detour.Crowd
|
|||
|
||||
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)
|
||||
{
|
||||
prepare(pos, dvel);
|
||||
Prepare(pos, dvel);
|
||||
m_params = option;
|
||||
m_invHorizTime = 1.0f / m_params.horizTime;
|
||||
m_vmax = vmax;
|
||||
|
@ -429,7 +429,7 @@ namespace DotRecast.Detour.Crowd
|
|||
Vector3f nvel = Vector3f.Zero;
|
||||
|
||||
if (debug != null)
|
||||
debug.reset();
|
||||
debug.Reset();
|
||||
|
||||
// Build sampling pattern aligned to desired velocity.
|
||||
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 depth = m_params.adaptiveDepth;
|
||||
|
||||
int nd = clamp(ndivs, 1, DT_MAX_PATTERN_DIVS);
|
||||
int nr = clamp(nrings, 1, DT_MAX_PATTERN_RINGS);
|
||||
int nd = Clamp(ndivs, 1, DT_MAX_PATTERN_DIVS);
|
||||
int nr = Clamp(nrings, 1, DT_MAX_PATTERN_RINGS);
|
||||
float da = (1.0f / nd) * DT_PI * 2;
|
||||
float ca = (float)Math.Cos(da);
|
||||
float sa = (float)Math.Sin(da);
|
||||
|
||||
// desired direction
|
||||
float[] ddir = new float[6];
|
||||
vCopy(ddir, dvel);
|
||||
dtNormalize2D(ddir);
|
||||
Vector3f rotated = dtRotate2D(ddir, da * 0.5f); // rotated by da/2
|
||||
VCopy(ddir, dvel);
|
||||
DtNormalize2D(ddir);
|
||||
Vector3f rotated = DtRotate2D(ddir, da * 0.5f); // rotated by da/2
|
||||
ddir[3] = rotated.x;
|
||||
ddir[4] = rotated.y;
|
||||
ddir[5] = rotated.z;
|
||||
|
@ -493,7 +493,7 @@ namespace DotRecast.Detour.Crowd
|
|||
// Start sampling.
|
||||
float cr = vmax * (1.0f - m_params.velBias);
|
||||
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;
|
||||
for (int k = 0; k < depth; ++k)
|
||||
{
|
||||
|
@ -504,11 +504,11 @@ namespace DotRecast.Detour.Crowd
|
|||
for (int i = 0; i < npat; ++i)
|
||||
{
|
||||
Vector3f vcand = new Vector3f();
|
||||
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))
|
||||
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))
|
||||
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++;
|
||||
if (penalty < minPenalty)
|
||||
{
|
||||
|
|
|
@ -30,17 +30,17 @@ namespace DotRecast.Detour.Crowd
|
|||
/**
|
||||
* 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
|
||||
* locomotion.
|
||||
*
|
||||
* Example of a common use case:
|
||||
*
|
||||
* -# 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
|
||||
* #findCorners() to plan movement. (This handles dynamic path straightening.) -# Use #movePosition() to feed agent
|
||||
* -# 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
|
||||
* #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
|
||||
* #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.
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* #optimizePathTopology() and #optimizePathVisibility() methods.
|
||||
* #OptimizePathTopology() and #OptimizePathVisibility() methods.
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
|
@ -70,7 +70,7 @@ namespace DotRecast.Detour.Crowd
|
|||
private Vector3f m_target = new Vector3f();
|
||||
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 furthestVisited = -1;
|
||||
|
@ -115,7 +115,7 @@ namespace DotRecast.Detour.Crowd
|
|||
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 furthestVisited = -1;
|
||||
|
@ -152,7 +152,7 @@ namespace DotRecast.Detour.Crowd
|
|||
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 furthestVisited = -1;
|
||||
|
@ -207,7 +207,7 @@ namespace DotRecast.Detour.Crowd
|
|||
* @param pos
|
||||
* 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.Add(refs);
|
||||
|
@ -215,7 +215,7 @@ namespace DotRecast.Detour.Crowd
|
|||
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.)
|
||||
|
@ -234,10 +234,10 @@ namespace DotRecast.Detour.Crowd
|
|||
* @param[in] navquery The query object used to build the corridor.
|
||||
* @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>();
|
||||
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())
|
||||
{
|
||||
path = result.result;
|
||||
|
@ -245,8 +245,8 @@ namespace DotRecast.Detour.Crowd
|
|||
int start = 0;
|
||||
foreach (StraightPathItem spi in path)
|
||||
{
|
||||
if ((spi.getFlags() & NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0
|
||||
|| vDist2DSqr(spi.getPos(), m_pos) > MIN_TARGET_DIST)
|
||||
if ((spi.GetFlags() & NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0
|
||||
|| VDist2DSqr(spi.GetPos(), m_pos) > MIN_TARGET_DIST)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ namespace DotRecast.Detour.Crowd
|
|||
for (int i = start; i < path.Count; 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;
|
||||
break;
|
||||
|
@ -299,10 +299,10 @@ namespace DotRecast.Detour.Crowd
|
|||
* @param filter
|
||||
* 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.
|
||||
float dist = vDist2D(m_pos, next);
|
||||
float dist = VDist2D(m_pos, next);
|
||||
|
||||
// If too close to the goal, do not try to optimize.
|
||||
if (dist < 0.01f)
|
||||
|
@ -315,15 +315,15 @@ namespace DotRecast.Detour.Crowd
|
|||
dist = Math.Min(dist + 0.01f, pathOptimizationRange);
|
||||
|
||||
// Adjust ray length.
|
||||
var delta = vSub(next, m_pos);
|
||||
Vector3f goal = vMad(m_pos, delta, pathOptimizationRange / dist);
|
||||
var delta = VSub(next, m_pos);
|
||||
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.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.
|
||||
*
|
||||
*/
|
||||
public bool optimizePathTopology(NavMeshQuery navquery, QueryFilter filter, int maxIterations)
|
||||
public bool OptimizePathTopology(NavMeshQuery navquery, QueryFilter filter, int maxIterations)
|
||||
{
|
||||
if (m_path.Count < 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
navquery.initSlicedFindPath(m_path[0], m_path[m_path.Count - 1], m_pos, m_target, filter, 0);
|
||||
navquery.updateSlicedFindPath(maxIterations);
|
||||
Result<List<long>> fpr = navquery.finalizeSlicedFindPathPartial(m_path);
|
||||
navquery.InitSlicedFindPath(m_path[0], m_path[m_path.Count - 1], m_pos, m_target, filter, 0);
|
||||
navquery.UpdateSlicedFindPath(maxIterations);
|
||||
Result<List<long>> fpr = navquery.FinalizeSlicedFindPathPartial(m_path);
|
||||
|
||||
if (fpr.Succeeded() && fpr.result.Count > 0)
|
||||
{
|
||||
m_path = mergeCorridorStartShortcut(m_path, fpr.result);
|
||||
m_path = MergeCorridorStartShortcut(m_path, fpr.result);
|
||||
return true;
|
||||
}
|
||||
|
||||
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.
|
||||
long prevRef = 0, polyRef = m_path[0];
|
||||
|
@ -387,8 +387,8 @@ namespace DotRecast.Detour.Crowd
|
|||
refs[0] = prevRef;
|
||||
refs[1] = polyRef;
|
||||
|
||||
NavMesh nav = navquery.getAttachedNavMesh();
|
||||
var startEnd = nav.getOffMeshConnectionPolyEndPoints(refs[0], refs[1]);
|
||||
NavMesh nav = navquery.GetAttachedNavMesh();
|
||||
var startEnd = nav.GetOffMeshConnectionPolyEndPoints(refs[0], refs[1]);
|
||||
if (startEnd.Succeeded())
|
||||
{
|
||||
m_pos = startEnd.result.Item2;
|
||||
|
@ -423,16 +423,16 @@ namespace DotRecast.Detour.Crowd
|
|||
* @param filter
|
||||
* 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.
|
||||
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())
|
||||
{
|
||||
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.
|
||||
m_pos = masResult.result.getResultPos();
|
||||
Result<float> hr = navquery.getPolyHeight(m_path[0], masResult.result.getResultPos());
|
||||
m_pos = masResult.result.GetResultPos();
|
||||
Result<float> hr = navquery.GetPolyHeight(m_path[0], masResult.result.GetResultPos());
|
||||
if (hr.Succeeded())
|
||||
{
|
||||
m_pos.y = hr.result;
|
||||
|
@ -461,20 +461,20 @@ namespace DotRecast.Detour.Crowd
|
|||
* @param filter
|
||||
* 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.
|
||||
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())
|
||||
{
|
||||
m_path = mergeCorridorEndMoved(m_path, masResult.result.getVisited());
|
||||
m_path = MergeCorridorEndMoved(m_path, masResult.result.GetVisited());
|
||||
// TODO: should we do that?
|
||||
// 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;
|
||||
*/
|
||||
m_target = masResult.result.getResultPos();
|
||||
m_target = masResult.result.GetResultPos();
|
||||
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
|
||||
* 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
|
||||
* The target location within the last polygon of the path. [(x, y, z)]
|
||||
* @param path
|
||||
* The path corridor.
|
||||
*/
|
||||
public void setCorridor(Vector3f target, List<long> path)
|
||||
public void SetCorridor(Vector3f target, List<long> path)
|
||||
{
|
||||
m_target = target;
|
||||
m_path = new List<long>(path);
|
||||
}
|
||||
|
||||
public void fixPathStart(long safeRef, Vector3f safePos)
|
||||
public void FixPathStart(long safeRef, Vector3f safePos)
|
||||
{
|
||||
m_pos = safePos;
|
||||
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.
|
||||
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++;
|
||||
}
|
||||
|
@ -528,7 +528,7 @@ namespace DotRecast.Detour.Crowd
|
|||
if (n == 0)
|
||||
{
|
||||
// The first polyref is bad, use current safe values.
|
||||
vCopy(ref m_pos, safePos);
|
||||
VCopy(ref m_pos, safePos);
|
||||
m_path.Clear();
|
||||
m_path.Add(safeRef);
|
||||
}
|
||||
|
@ -539,7 +539,7 @@ namespace DotRecast.Detour.Crowd
|
|||
}
|
||||
|
||||
// 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())
|
||||
{
|
||||
m_target = result.result;
|
||||
|
@ -559,13 +559,13 @@ namespace DotRecast.Detour.Crowd
|
|||
* The filter to apply to the operation.
|
||||
* @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.
|
||||
int n = Math.Min(m_path.Count, maxLookAhead);
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (!navquery.isValidPolyRef(m_path[i], filter))
|
||||
if (!navquery.IsValidPolyRef(m_path[i], filter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -579,7 +579,7 @@ namespace DotRecast.Detour.Crowd
|
|||
*
|
||||
* @return The current position within the corridor.
|
||||
*/
|
||||
public Vector3f getPos()
|
||||
public Vector3f GetPos()
|
||||
{
|
||||
return m_pos;
|
||||
}
|
||||
|
@ -589,7 +589,7 @@ namespace DotRecast.Detour.Crowd
|
|||
*
|
||||
* @return The current target within the corridor.
|
||||
*/
|
||||
public Vector3f getTarget()
|
||||
public Vector3f GetTarget()
|
||||
{
|
||||
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.)
|
||||
*/
|
||||
public long getFirstPoly()
|
||||
public long GetFirstPoly()
|
||||
{
|
||||
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.)
|
||||
*/
|
||||
public long getLastPoly()
|
||||
public long GetLastPoly()
|
||||
{
|
||||
return 0 == m_path.Count ? 0 : m_path[m_path.Count - 1];
|
||||
}
|
||||
|
@ -617,7 +617,7 @@ namespace DotRecast.Detour.Crowd
|
|||
/**
|
||||
* The corridor's path.
|
||||
*/
|
||||
public List<long> getPath()
|
||||
public List<long> GetPath()
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
@ -627,7 +627,7 @@ namespace DotRecast.Detour.Crowd
|
|||
*
|
||||
* @return The number of polygons in the current corridor path.
|
||||
*/
|
||||
public int getPathCount()
|
||||
public int GetPathCount()
|
||||
{
|
||||
return m_path.Count;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace DotRecast.Detour.Crowd
|
|||
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
|
||||
// consumed.
|
||||
|
@ -54,32 +54,32 @@ namespace DotRecast.Detour.Crowd
|
|||
if (q.result.status == null)
|
||||
{
|
||||
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.
|
||||
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;
|
||||
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.path = path.result;
|
||||
}
|
||||
|
||||
if (!(q.result.status.isFailed() || q.result.status.isSuccess()))
|
||||
if (!(q.result.status.IsFailed() || q.result.status.IsSuccess()))
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -49,12 +49,12 @@ namespace DotRecast.Detour.Crowd.Tracking
|
|||
m_tpen = new float[m_maxSamples];
|
||||
}
|
||||
|
||||
public void reset()
|
||||
public void Reset()
|
||||
{
|
||||
m_nsamples = 0;
|
||||
}
|
||||
|
||||
void normalizeArray(float[] arr, int n)
|
||||
void NormalizeArray(float[] arr, int n)
|
||||
{
|
||||
// Normalize penaly range.
|
||||
float minPen = float.MaxValue;
|
||||
|
@ -68,19 +68,19 @@ namespace DotRecast.Detour.Crowd.Tracking
|
|||
float penRange = maxPen - minPen;
|
||||
float s = penRange > 0.001f ? (1.0f / penRange) : 1;
|
||||
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_vpen, m_nsamples);
|
||||
normalizeArray(m_vcpen, m_nsamples);
|
||||
normalizeArray(m_spen, m_nsamples);
|
||||
normalizeArray(m_tpen, m_nsamples);
|
||||
NormalizeArray(m_pen, m_nsamples);
|
||||
NormalizeArray(m_vpen, m_nsamples);
|
||||
NormalizeArray(m_vcpen, m_nsamples);
|
||||
NormalizeArray(m_spen, 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)
|
||||
return;
|
||||
|
@ -96,12 +96,12 @@ namespace DotRecast.Detour.Crowd.Tracking
|
|||
m_nsamples++;
|
||||
}
|
||||
|
||||
public int getSampleCount()
|
||||
public int GetSampleCount()
|
||||
{
|
||||
return m_nsamples;
|
||||
}
|
||||
|
||||
public Vector3f getSampleVelocity(int i)
|
||||
public Vector3f GetSampleVelocity(int i)
|
||||
{
|
||||
Vector3f vel = new Vector3f();
|
||||
vel.x = m_vel[i * 3];
|
||||
|
@ -110,32 +110,32 @@ namespace DotRecast.Detour.Crowd.Tracking
|
|||
return vel;
|
||||
}
|
||||
|
||||
public float getSampleSize(int i)
|
||||
public float GetSampleSize(int i)
|
||||
{
|
||||
return m_ssize[i];
|
||||
}
|
||||
|
||||
public float getSamplePenalty(int i)
|
||||
public float GetSamplePenalty(int i)
|
||||
{
|
||||
return m_pen[i];
|
||||
}
|
||||
|
||||
public float getSampleDesiredVelocityPenalty(int i)
|
||||
public float GetSampleDesiredVelocityPenalty(int i)
|
||||
{
|
||||
return m_vpen[i];
|
||||
}
|
||||
|
||||
public float getSampleCurrentVelocityPenalty(int i)
|
||||
public float GetSampleCurrentVelocityPenalty(int i)
|
||||
{
|
||||
return m_vcpen[i];
|
||||
}
|
||||
|
||||
public float getSamplePreferredSidePenalty(int i)
|
||||
public float GetSamplePreferredSidePenalty(int i)
|
||||
{
|
||||
return m_spen[i];
|
||||
}
|
||||
|
||||
public float getSampleCollisionTimePenalty(int i)
|
||||
public float GetSampleCollisionTimePenalty(int i)
|
||||
{
|
||||
return m_tpen[i];
|
||||
}
|
||||
|
|
|
@ -34,14 +34,14 @@ namespace DotRecast.Detour.Dynamic
|
|||
_affectedTiles = affectedTiles;
|
||||
}
|
||||
|
||||
public ICollection<DynamicTile> affectedTiles()
|
||||
public ICollection<DynamicTile> AffectedTiles()
|
||||
{
|
||||
return _affectedTiles;
|
||||
}
|
||||
|
||||
public void process(DynamicTile tile)
|
||||
public void Process(DynamicTile tile)
|
||||
{
|
||||
tile.addCollider(colliderId, collider);
|
||||
tile.AddCollider(colliderId, collider);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,11 +33,11 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
this._bounds = bounds;
|
||||
}
|
||||
|
||||
public float[] bounds()
|
||||
public float[] Bounds()
|
||||
{
|
||||
return _bounds;
|
||||
}
|
||||
|
||||
public abstract void rasterize(Heightfield hf, Telemetry telemetry);
|
||||
public abstract void Rasterize(Heightfield hf, Telemetry telemetry);
|
||||
}
|
||||
}
|
|
@ -28,13 +28,13 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
private readonly Vector3f[] halfEdges;
|
||||
|
||||
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.halfEdges = halfEdges;
|
||||
}
|
||||
|
||||
private static float[] bounds(Vector3f center, Vector3f[] halfEdges)
|
||||
private static float[] Bounds(Vector3f center, Vector3f[] halfEdges)
|
||||
{
|
||||
float[] bounds = new float[]
|
||||
{
|
||||
|
@ -60,13 +60,13 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
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);
|
||||
}
|
||||
|
||||
public static Vector3f[] getHalfEdges(Vector3f up, Vector3f forward, Vector3f extent)
|
||||
public static Vector3f[] GetHalfEdges(Vector3f up, Vector3f forward, Vector3f extent)
|
||||
{
|
||||
Vector3f[] halfEdges =
|
||||
{
|
||||
|
@ -74,11 +74,11 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
Vector3f.Of(up.x, up.y, up.z),
|
||||
Vector3f.Zero
|
||||
};
|
||||
RecastVectors.normalize(ref halfEdges[1]);
|
||||
RecastVectors.cross(ref halfEdges[0], up, forward);
|
||||
RecastVectors.normalize(ref halfEdges[0]);
|
||||
RecastVectors.cross(ref halfEdges[2], halfEdges[0], up);
|
||||
RecastVectors.normalize(ref halfEdges[2]);
|
||||
RecastVectors.Normalize(ref halfEdges[1]);
|
||||
RecastVectors.Cross(ref halfEdges[0], up, forward);
|
||||
RecastVectors.Normalize(ref halfEdges[0]);
|
||||
RecastVectors.Cross(ref halfEdges[2], halfEdges[0], up);
|
||||
RecastVectors.Normalize(ref halfEdges[2]);
|
||||
halfEdges[0].x *= extent.x;
|
||||
halfEdges[0].y *= extent.x;
|
||||
halfEdges[0].z *= extent.x;
|
||||
|
|
|
@ -29,20 +29,20 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
private readonly float radius;
|
||||
|
||||
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.end = end;
|
||||
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);
|
||||
}
|
||||
|
||||
private static float[] bounds(Vector3f start, Vector3f end, float radius)
|
||||
private static float[] Bounds(Vector3f start, Vector3f end, float radius)
|
||||
{
|
||||
return new float[]
|
||||
{
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
{
|
||||
public interface Collider
|
||||
{
|
||||
float[] bounds();
|
||||
void rasterize(Heightfield hf, Telemetry telemetry);
|
||||
float[] Bounds();
|
||||
void Rasterize(Heightfield hf, Telemetry telemetry);
|
||||
}
|
||||
}
|
|
@ -31,21 +31,21 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
public CompositeCollider(List<Collider> colliders)
|
||||
{
|
||||
this.colliders = colliders;
|
||||
_bounds = bounds(colliders);
|
||||
_bounds = Bounds(colliders);
|
||||
}
|
||||
|
||||
public CompositeCollider(params Collider[] colliders)
|
||||
{
|
||||
this.colliders = colliders.ToList();
|
||||
_bounds = bounds(this.colliders);
|
||||
_bounds = Bounds(this.colliders);
|
||||
}
|
||||
|
||||
public float[] bounds()
|
||||
public float[] Bounds()
|
||||
{
|
||||
return _bounds;
|
||||
}
|
||||
|
||||
private static float[] bounds(List<Collider> colliders)
|
||||
private static float[] Bounds(List<Collider> colliders)
|
||||
{
|
||||
float[] bounds = new float[]
|
||||
{
|
||||
|
@ -54,7 +54,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
};
|
||||
foreach (Collider collider in colliders)
|
||||
{
|
||||
float[] b = collider.bounds();
|
||||
float[] b = collider.Bounds();
|
||||
bounds[0] = Math.Min(bounds[0], b[0]);
|
||||
bounds[1] = Math.Min(bounds[1], b[1]);
|
||||
bounds[2] = Math.Min(bounds[2], b[2]);
|
||||
|
@ -66,10 +66,10 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
return bounds;
|
||||
}
|
||||
|
||||
public void rasterize(Heightfield hf, Telemetry telemetry)
|
||||
public void Rasterize(Heightfield hf, Telemetry telemetry)
|
||||
{
|
||||
foreach (var c in colliders)
|
||||
c.rasterize(hf, telemetry);
|
||||
c.Rasterize(hf, telemetry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
private readonly int[] triangles;
|
||||
|
||||
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.triangles = triangles;
|
||||
|
@ -40,9 +40,9 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,20 +29,20 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
private readonly float radius;
|
||||
|
||||
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.end = end;
|
||||
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);
|
||||
}
|
||||
|
||||
private static float[] bounds(Vector3f start, Vector3f end, float radius)
|
||||
private static float[] Bounds(Vector3f start, Vector3f end, float radius)
|
||||
{
|
||||
return new float[]
|
||||
{
|
||||
|
|
|
@ -28,19 +28,19 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
private readonly float radius;
|
||||
|
||||
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.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);
|
||||
}
|
||||
|
||||
private static float[] bounds(Vector3f center, float radius)
|
||||
private static float[] Bounds(Vector3f center, float radius)
|
||||
{
|
||||
return new float[]
|
||||
{
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
private readonly int[] triangles;
|
||||
|
||||
public TrimeshCollider(float[] vertices, int[] triangles, int area, float flagMergeThreshold) :
|
||||
base(area, flagMergeThreshold, computeBounds(vertices))
|
||||
base(area, flagMergeThreshold, ComputeBounds(vertices))
|
||||
{
|
||||
this.vertices = vertices;
|
||||
this.triangles = triangles;
|
||||
|
@ -40,7 +40,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
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] };
|
||||
for (int i = 3; i < vertices.Length; i += 3)
|
||||
|
@ -56,11 +56,11 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
|||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,14 +68,14 @@ namespace DotRecast.Detour.Dynamic
|
|||
navMeshParams.maxPolys = 0x8000;
|
||||
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();
|
||||
}
|
||||
|
||||
public NavMesh navMesh()
|
||||
public NavMesh NavMesh()
|
||||
{
|
||||
return _navMesh;
|
||||
}
|
||||
|
@ -83,64 +83,64 @@ namespace DotRecast.Detour.Dynamic
|
|||
/**
|
||||
* 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();
|
||||
updateQueue.Add(new AddColliderQueueItem(cid, collider, getTiles(collider.bounds())));
|
||||
updateQueue.Add(new AddColliderQueueItem(cid, collider, GetTiles(collider.Bounds())));
|
||||
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
|
||||
*/
|
||||
public void build()
|
||||
public void Build()
|
||||
{
|
||||
processQueue();
|
||||
rebuild(_tiles.Values);
|
||||
ProcessQueue();
|
||||
Rebuild(_tiles.Values);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
rebuild(dynamicTile);
|
||||
return updateNavMesh();
|
||||
Rebuild(dynamicTile);
|
||||
return UpdateNavMesh();
|
||||
}
|
||||
|
||||
private HashSet<DynamicTile> processQueue()
|
||||
private HashSet<DynamicTile> ProcessQueue()
|
||||
{
|
||||
var items = consumeQueue();
|
||||
var items = ConsumeQueue();
|
||||
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>();
|
||||
while (updateQueue.TryTake(out var item))
|
||||
|
@ -151,38 +151,38 @@ namespace DotRecast.Detour.Dynamic
|
|||
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}
|
||||
*/
|
||||
public Task<bool> build(TaskFactory executor)
|
||||
public Task<bool> Build(TaskFactory executor)
|
||||
{
|
||||
processQueue();
|
||||
return rebuild(_tiles.Values, executor);
|
||||
ProcessQueue();
|
||||
return Rebuild(_tiles.Values, executor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
return Task.WhenAll(tasks).ContinueWith(k => updateNavMesh());
|
||||
var tasks = tiles.Select(tile => executor.StartNew(() => Rebuild(tile))).ToArray();
|
||||
return Task.WhenAll(tasks).ContinueWith(k => UpdateNavMesh());
|
||||
}
|
||||
|
||||
private ICollection<DynamicTile> getTiles(float[] bounds)
|
||||
private ICollection<DynamicTile> GetTiles(float[] bounds)
|
||||
{
|
||||
if (bounds == null)
|
||||
{
|
||||
|
@ -198,7 +198,7 @@ namespace DotRecast.Detour.Dynamic
|
|||
{
|
||||
for (int x = minx; x <= maxx; ++x)
|
||||
{
|
||||
DynamicTile tile = getTileAt(x, z);
|
||||
DynamicTile tile = GetTileAt(x, z);
|
||||
if (tile != null)
|
||||
{
|
||||
tiles.Add(tile);
|
||||
|
@ -209,25 +209,25 @@ namespace DotRecast.Detour.Dynamic
|
|||
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();
|
||||
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)
|
||||
{
|
||||
NavMesh navMesh = new NavMesh(navMeshParams, MAX_VERTS_PER_POLY);
|
||||
foreach (var t in _tiles.Values)
|
||||
t.addTo(navMesh);
|
||||
t.AddTo(navMesh);
|
||||
|
||||
this._navMesh = navMesh;
|
||||
dirty = false;
|
||||
|
@ -237,24 +237,24 @@ namespace DotRecast.Detour.Dynamic
|
|||
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
|
||||
: null;
|
||||
}
|
||||
|
||||
private long lookupKey(long x, long z)
|
||||
private long LookupKey(long x, long z)
|
||||
{
|
||||
return (z << 32) | x;
|
||||
}
|
||||
|
||||
public List<VoxelTile> voxelTiles()
|
||||
public List<VoxelTile> VoxelTiles()
|
||||
{
|
||||
return _tiles.Values.Select(t => t.voxelTile).ToList();
|
||||
}
|
||||
|
||||
public List<RecastBuilderResult> recastResults()
|
||||
public List<RecastBuilderResult> RecastResults()
|
||||
{
|
||||
return _tiles.Values.Select(t => t.recastResult).ToList();
|
||||
}
|
||||
|
|
|
@ -42,31 +42,31 @@ namespace DotRecast.Detour.Dynamic
|
|||
this.voxelTile = voxelTile;
|
||||
}
|
||||
|
||||
public bool build(RecastBuilder builder, DynamicNavMeshConfig config, Telemetry telemetry)
|
||||
public bool Build(RecastBuilder builder, DynamicNavMeshConfig config, Telemetry telemetry)
|
||||
{
|
||||
if (dirty)
|
||||
{
|
||||
Heightfield heightfield = buildHeightfield(config, telemetry);
|
||||
RecastBuilderResult r = buildRecast(builder, config, voxelTile, heightfield, telemetry);
|
||||
NavMeshDataCreateParams option = navMeshCreateParams(voxelTile.tileX, voxelTile.tileZ, voxelTile.cellSize,
|
||||
Heightfield heightfield = BuildHeightfield(config, telemetry);
|
||||
RecastBuilderResult r = BuildRecast(builder, config, voxelTile, heightfield, telemetry);
|
||||
NavMeshDataCreateParams option = NavMeshCreateParams(voxelTile.tileX, voxelTile.tileZ, voxelTile.cellSize,
|
||||
voxelTile.cellHeight, config, r);
|
||||
meshData = NavMeshBuilder.createNavMeshData(option);
|
||||
meshData = NavMeshBuilder.CreateNavMeshData(option);
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
Heightfield heightfield = checkpoint != null ? checkpoint.heightfield : voxelTile.heightfield();
|
||||
Heightfield heightfield = checkpoint != null ? checkpoint.heightfield : voxelTile.Heightfield();
|
||||
foreach (var (cid, c) in colliders)
|
||||
{
|
||||
if (!rasterizedColliders.Contains(cid))
|
||||
{
|
||||
heightfield.bmax.y = Math.Max(heightfield.bmax.y, c.bounds()[4] + heightfield.ch * 2);
|
||||
c.rasterize(heightfield, telemetry);
|
||||
heightfield.bmax.y = Math.Max(heightfield.bmax.y, c.Bounds()[4] + heightfield.ch * 2);
|
||||
c.Rasterize(heightfield, telemetry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ namespace DotRecast.Detour.Dynamic
|
|||
return heightfield;
|
||||
}
|
||||
|
||||
private RecastBuilderResult buildRecast(RecastBuilder builder, DynamicNavMeshConfig config, VoxelTile vt,
|
||||
private RecastBuilderResult BuildRecast(RecastBuilder builder, DynamicNavMeshConfig config, VoxelTile vt,
|
||||
Heightfield heightfield, Telemetry telemetry)
|
||||
{
|
||||
RecastConfig rcConfig = new RecastConfig(config.useTiles, config.tileSizeX, config.tileSizeZ, vt.borderSize,
|
||||
|
@ -87,7 +87,7 @@ namespace DotRecast.Detour.Dynamic
|
|||
config.maxEdgeLen, config.maxSimplificationError,
|
||||
Math.Min(DynamicNavMesh.MAX_VERTS_PER_POLY, config.vertsPerPoly), true, config.detailSampleDistance,
|
||||
config.detailSampleMaxError, null);
|
||||
RecastBuilderResult r = builder.build(vt.tileX, vt.tileZ, null, rcConfig, heightfield, telemetry);
|
||||
RecastBuilderResult r = builder.Build(vt.tileX, vt.tileZ, null, rcConfig, heightfield, telemetry);
|
||||
if (config.keepIntermediateResults)
|
||||
{
|
||||
recastResult = r;
|
||||
|
@ -96,18 +96,18 @@ namespace DotRecast.Detour.Dynamic
|
|||
return r;
|
||||
}
|
||||
|
||||
public void addCollider(long cid, Collider collider)
|
||||
public void AddCollider(long cid, Collider collider)
|
||||
{
|
||||
colliders[cid] = collider;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
public bool containsCollider(long cid)
|
||||
public bool ContainsCollider(long cid)
|
||||
{
|
||||
return colliders.ContainsKey(cid);
|
||||
}
|
||||
|
||||
public void removeCollider(long colliderId)
|
||||
public void RemoveCollider(long colliderId)
|
||||
{
|
||||
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)
|
||||
{
|
||||
PolyMesh m_pmesh = rcResult.getMesh();
|
||||
PolyMeshDetail m_dmesh = rcResult.getMeshDetail();
|
||||
PolyMesh m_pmesh = rcResult.GetMesh();
|
||||
PolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
|
||||
NavMeshDataCreateParams option = new NavMeshDataCreateParams();
|
||||
for (int i = 0; i < m_pmesh.npolys; ++i)
|
||||
{
|
||||
|
@ -164,15 +164,15 @@ namespace DotRecast.Detour.Dynamic
|
|||
return option;
|
||||
}
|
||||
|
||||
public void addTo(NavMesh navMesh)
|
||||
public void AddTo(NavMesh navMesh)
|
||||
{
|
||||
if (meshData != null)
|
||||
{
|
||||
id = navMesh.addTile(meshData, 0, 0);
|
||||
id = navMesh.AddTile(meshData, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
navMesh.removeTile(id);
|
||||
navMesh.RemoveTile(id);
|
||||
id = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,10 +30,10 @@ namespace DotRecast.Detour.Dynamic
|
|||
public DynamicTileCheckpoint(Heightfield heightfield, ISet<long> 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,
|
||||
source.ch, source.borderSize);
|
||||
|
|
|
@ -22,39 +22,39 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
{
|
||||
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)
|
||||
| (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)
|
||||
| (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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -24,17 +24,17 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
{
|
||||
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));
|
||||
}
|
||||
|
||||
public byte[] compress(byte[] data)
|
||||
public byte[] Compress(byte[] data)
|
||||
{
|
||||
byte[] compressed = LZ4Pickler.Pickle(data, LZ4Level.L12_MAX);
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -56,12 +56,12 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
public float[] bounds = new float[6];
|
||||
public readonly List<VoxelTile> tiles = new List<VoxelTile>();
|
||||
|
||||
public void addTile(VoxelTile tile)
|
||||
public void AddTile(VoxelTile 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,
|
||||
AreaModification walkbableAreaMod, bool buildMeshDetail, float detailSampleDist, float detailSampleMaxError)
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
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();
|
||||
f.version = 1;
|
||||
|
@ -102,19 +102,19 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
};
|
||||
foreach (RecastBuilderResult r in results)
|
||||
{
|
||||
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[1] = Math.Min(f.bounds[1], r.getSolidHeightfield().bmin.y);
|
||||
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[4] = Math.Max(f.bounds[4], r.getSolidHeightfield().bmax.y);
|
||||
f.bounds[5] = Math.Max(f.bounds[5], r.getSolidHeightfield().bmax.z);
|
||||
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[1] = Math.Min(f.bounds[1], r.GetSolidHeightfield().bmin.y);
|
||||
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[4] = Math.Max(f.bounds[4], r.GetSolidHeightfield().bmax.y);
|
||||
f.bounds[5] = Math.Max(f.bounds[5], r.GetSolidHeightfield().bmax.z);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
public static VoxelFile from(DynamicNavMesh mesh)
|
||||
public static VoxelFile From(DynamicNavMesh mesh)
|
||||
{
|
||||
VoxelFile f = new VoxelFile();
|
||||
f.version = 1;
|
||||
|
@ -144,9 +144,9 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity,
|
||||
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.bounds[0] = Math.Min(f.bounds[0], vt.boundsMin.x);
|
||||
f.bounds[1] = Math.Min(f.bounds[1], vt.boundsMin.y);
|
||||
|
|
|
@ -26,40 +26,40 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
{
|
||||
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();
|
||||
int magic = buf.getInt();
|
||||
int magic = buf.GetInt();
|
||||
if (magic != VoxelFile.MAGIC)
|
||||
{
|
||||
magic = IOUtils.swapEndianness(magic);
|
||||
magic = IOUtils.SwapEndianness(magic);
|
||||
if (magic != VoxelFile.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 compression = (file.version & VoxelFile.VERSION_COMPRESSION_MASK) == VoxelFile.VERSION_COMPRESSION_LZ4;
|
||||
file.walkableRadius = buf.getFloat();
|
||||
file.walkableHeight = buf.getFloat();
|
||||
file.walkableClimb = buf.getFloat();
|
||||
file.walkableSlopeAngle = buf.getFloat();
|
||||
file.cellSize = buf.getFloat();
|
||||
file.maxSimplificationError = buf.getFloat();
|
||||
file.maxEdgeLen = buf.getFloat();
|
||||
file.minRegionArea = (int)buf.getFloat();
|
||||
file.walkableRadius = buf.GetFloat();
|
||||
file.walkableHeight = buf.GetFloat();
|
||||
file.walkableClimb = buf.GetFloat();
|
||||
file.walkableSlopeAngle = buf.GetFloat();
|
||||
file.cellSize = buf.GetFloat();
|
||||
file.maxSimplificationError = buf.GetFloat();
|
||||
file.maxEdgeLen = buf.GetFloat();
|
||||
file.minRegionArea = (int)buf.GetFloat();
|
||||
if (!isExportedFromAstar)
|
||||
{
|
||||
file.regionMergeArea = buf.getFloat();
|
||||
file.vertsPerPoly = buf.getInt();
|
||||
file.buildMeshDetail = buf.get() != 0;
|
||||
file.detailSampleDistance = buf.getFloat();
|
||||
file.detailSampleMaxError = buf.getFloat();
|
||||
file.regionMergeArea = buf.GetFloat();
|
||||
file.vertsPerPoly = buf.GetInt();
|
||||
file.buildMeshDetail = buf.Get() != 0;
|
||||
file.detailSampleDistance = buf.GetFloat();
|
||||
file.detailSampleMaxError = buf.GetFloat();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -70,18 +70,18 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
file.detailSampleMaxError = file.maxSimplificationError * 0.8f;
|
||||
}
|
||||
|
||||
file.useTiles = buf.get() != 0;
|
||||
file.tileSizeX = buf.getInt();
|
||||
file.tileSizeZ = buf.getInt();
|
||||
file.rotation.x = buf.getFloat();
|
||||
file.rotation.y = buf.getFloat();
|
||||
file.rotation.z = buf.getFloat();
|
||||
file.bounds[0] = buf.getFloat();
|
||||
file.bounds[1] = buf.getFloat();
|
||||
file.bounds[2] = buf.getFloat();
|
||||
file.bounds[3] = buf.getFloat();
|
||||
file.bounds[4] = buf.getFloat();
|
||||
file.bounds[5] = buf.getFloat();
|
||||
file.useTiles = buf.Get() != 0;
|
||||
file.tileSizeX = buf.GetInt();
|
||||
file.tileSizeZ = buf.GetInt();
|
||||
file.rotation.x = buf.GetFloat();
|
||||
file.rotation.y = buf.GetFloat();
|
||||
file.rotation.z = buf.GetFloat();
|
||||
file.bounds[0] = buf.GetFloat();
|
||||
file.bounds[1] = buf.GetFloat();
|
||||
file.bounds[2] = buf.GetFloat();
|
||||
file.bounds[3] = buf.GetFloat();
|
||||
file.bounds[4] = buf.GetFloat();
|
||||
file.bounds[5] = buf.GetFloat();
|
||||
if (isExportedFromAstar)
|
||||
{
|
||||
// bounds are saved as center + size
|
||||
|
@ -93,22 +93,22 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
file.bounds[5] += file.bounds[2];
|
||||
}
|
||||
|
||||
int tileCount = buf.getInt();
|
||||
int tileCount = buf.GetInt();
|
||||
for (int tile = 0; tile < tileCount; tile++)
|
||||
{
|
||||
int tileX = buf.getInt();
|
||||
int tileZ = buf.getInt();
|
||||
int width = buf.getInt();
|
||||
int depth = buf.getInt();
|
||||
int borderSize = buf.getInt();
|
||||
int tileX = buf.GetInt();
|
||||
int tileZ = buf.GetInt();
|
||||
int width = buf.GetInt();
|
||||
int depth = buf.GetInt();
|
||||
int borderSize = buf.GetInt();
|
||||
Vector3f boundsMin = new Vector3f();
|
||||
boundsMin.x = buf.getFloat();
|
||||
boundsMin.y = buf.getFloat();
|
||||
boundsMin.z = buf.getFloat();
|
||||
boundsMin.x = buf.GetFloat();
|
||||
boundsMin.y = buf.GetFloat();
|
||||
boundsMin.z = buf.GetFloat();
|
||||
Vector3f boundsMax = new Vector3f();
|
||||
boundsMax.x = buf.getFloat();
|
||||
boundsMax.y = buf.getFloat();
|
||||
boundsMax.z = buf.getFloat();
|
||||
boundsMax.x = buf.GetFloat();
|
||||
boundsMax.y = buf.GetFloat();
|
||||
boundsMax.z = buf.GetFloat();
|
||||
if (isExportedFromAstar)
|
||||
{
|
||||
// bounds are local
|
||||
|
@ -120,20 +120,20 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
boundsMax.z += file.bounds[2];
|
||||
}
|
||||
|
||||
float cellSize = buf.getFloat();
|
||||
float cellHeight = buf.getFloat();
|
||||
int voxelSize = buf.getInt();
|
||||
int position = buf.position();
|
||||
float cellSize = buf.GetFloat();
|
||||
float cellHeight = buf.GetFloat();
|
||||
int voxelSize = buf.GetInt();
|
||||
int position = buf.Position();
|
||||
byte[] bytes = buf.ReadBytes(voxelSize).ToArray();
|
||||
if (compression)
|
||||
{
|
||||
bytes = compressor.decompress(bytes);
|
||||
bytes = compressor.Decompress(bytes);
|
||||
}
|
||||
|
||||
ByteBuffer data = new ByteBuffer(bytes);
|
||||
data.order(buf.order());
|
||||
file.addTile(new VoxelTile(tileX, tileZ, width, depth, boundsMin, boundsMax, cellSize, cellHeight, borderSize, data));
|
||||
buf.position(position + voxelSize);
|
||||
data.Order(buf.Order());
|
||||
file.AddTile(new VoxelTile(tileX, tileZ, width, depth, boundsMin, boundsMax, cellSize, cellHeight, borderSize, data));
|
||||
buf.Position(position + voxelSize);
|
||||
}
|
||||
|
||||
return file;
|
||||
|
|
|
@ -26,69 +26,69 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
{
|
||||
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.VERSION_EXPORTER_RECAST4J | (compression ? VoxelFile.VERSION_COMPRESSION_LZ4 : 0), byteOrder);
|
||||
write(stream, f.walkableRadius, byteOrder);
|
||||
write(stream, f.walkableHeight, byteOrder);
|
||||
write(stream, f.walkableClimb, byteOrder);
|
||||
write(stream, f.walkableSlopeAngle, byteOrder);
|
||||
write(stream, f.cellSize, byteOrder);
|
||||
write(stream, f.maxSimplificationError, byteOrder);
|
||||
write(stream, f.maxEdgeLen, byteOrder);
|
||||
write(stream, f.minRegionArea, byteOrder);
|
||||
write(stream, f.regionMergeArea, byteOrder);
|
||||
write(stream, f.vertsPerPoly, byteOrder);
|
||||
write(stream, f.buildMeshDetail);
|
||||
write(stream, f.detailSampleDistance, byteOrder);
|
||||
write(stream, f.detailSampleMaxError, byteOrder);
|
||||
write(stream, f.useTiles);
|
||||
write(stream, f.tileSizeX, byteOrder);
|
||||
write(stream, f.tileSizeZ, byteOrder);
|
||||
write(stream, f.rotation.x, byteOrder);
|
||||
write(stream, f.rotation.y, byteOrder);
|
||||
write(stream, f.rotation.z, byteOrder);
|
||||
write(stream, f.bounds[0], byteOrder);
|
||||
write(stream, f.bounds[1], byteOrder);
|
||||
write(stream, f.bounds[2], byteOrder);
|
||||
write(stream, f.bounds[3], byteOrder);
|
||||
write(stream, f.bounds[4], byteOrder);
|
||||
write(stream, f.bounds[5], byteOrder);
|
||||
write(stream, f.tiles.Count, byteOrder);
|
||||
Write(stream, VoxelFile.MAGIC, byteOrder);
|
||||
Write(stream, VoxelFile.VERSION_EXPORTER_RECAST4J | (compression ? VoxelFile.VERSION_COMPRESSION_LZ4 : 0), byteOrder);
|
||||
Write(stream, f.walkableRadius, byteOrder);
|
||||
Write(stream, f.walkableHeight, byteOrder);
|
||||
Write(stream, f.walkableClimb, byteOrder);
|
||||
Write(stream, f.walkableSlopeAngle, byteOrder);
|
||||
Write(stream, f.cellSize, byteOrder);
|
||||
Write(stream, f.maxSimplificationError, byteOrder);
|
||||
Write(stream, f.maxEdgeLen, byteOrder);
|
||||
Write(stream, f.minRegionArea, byteOrder);
|
||||
Write(stream, f.regionMergeArea, byteOrder);
|
||||
Write(stream, f.vertsPerPoly, byteOrder);
|
||||
Write(stream, f.buildMeshDetail);
|
||||
Write(stream, f.detailSampleDistance, byteOrder);
|
||||
Write(stream, f.detailSampleMaxError, byteOrder);
|
||||
Write(stream, f.useTiles);
|
||||
Write(stream, f.tileSizeX, byteOrder);
|
||||
Write(stream, f.tileSizeZ, byteOrder);
|
||||
Write(stream, f.rotation.x, byteOrder);
|
||||
Write(stream, f.rotation.y, byteOrder);
|
||||
Write(stream, f.rotation.z, byteOrder);
|
||||
Write(stream, f.bounds[0], byteOrder);
|
||||
Write(stream, f.bounds[1], byteOrder);
|
||||
Write(stream, f.bounds[2], byteOrder);
|
||||
Write(stream, f.bounds[3], byteOrder);
|
||||
Write(stream, f.bounds[4], byteOrder);
|
||||
Write(stream, f.bounds[5], byteOrder);
|
||||
Write(stream, f.tiles.Count, byteOrder);
|
||||
foreach (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.tileZ, byteOrder);
|
||||
write(stream, tile.width, byteOrder);
|
||||
write(stream, tile.depth, byteOrder);
|
||||
write(stream, tile.borderSize, byteOrder);
|
||||
write(stream, tile.boundsMin.x, byteOrder);
|
||||
write(stream, tile.boundsMin.y, byteOrder);
|
||||
write(stream, tile.boundsMin.z, byteOrder);
|
||||
write(stream, tile.boundsMax.x, byteOrder);
|
||||
write(stream, tile.boundsMax.y, byteOrder);
|
||||
write(stream, tile.boundsMax.z, byteOrder);
|
||||
write(stream, tile.cellSize, byteOrder);
|
||||
write(stream, tile.cellHeight, byteOrder);
|
||||
Write(stream, tile.tileX, byteOrder);
|
||||
Write(stream, tile.tileZ, byteOrder);
|
||||
Write(stream, tile.width, byteOrder);
|
||||
Write(stream, tile.depth, byteOrder);
|
||||
Write(stream, tile.borderSize, byteOrder);
|
||||
Write(stream, tile.boundsMin.x, byteOrder);
|
||||
Write(stream, tile.boundsMin.y, byteOrder);
|
||||
Write(stream, tile.boundsMin.z, byteOrder);
|
||||
Write(stream, tile.boundsMax.x, byteOrder);
|
||||
Write(stream, tile.boundsMax.y, byteOrder);
|
||||
Write(stream, tile.boundsMax.z, byteOrder);
|
||||
Write(stream, tile.cellSize, byteOrder);
|
||||
Write(stream, tile.cellHeight, byteOrder);
|
||||
byte[] bytes = tile.spanData;
|
||||
if (compression)
|
||||
{
|
||||
bytes = compressor.compress(bytes);
|
||||
bytes = compressor.Compress(bytes);
|
||||
}
|
||||
|
||||
write(stream, bytes.Length, byteOrder);
|
||||
Write(stream, bytes.Length, byteOrder);
|
||||
stream.Write(bytes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
this.cellSize = cellSize;
|
||||
this.cellHeight = cellHeight;
|
||||
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)
|
||||
|
@ -62,15 +62,15 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
cellSize = heightfield.cs;
|
||||
cellHeight = heightfield.ch;
|
||||
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);
|
||||
int position = 0;
|
||||
|
@ -79,16 +79,16 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
Span prev = null;
|
||||
int spanCount = ByteUtils.getShortBE(spanData, position);
|
||||
int spanCount = ByteUtils.GetShortBE(spanData, position);
|
||||
position += 2;
|
||||
for (int s = 0; s < spanCount; s++)
|
||||
{
|
||||
Span span = new Span();
|
||||
span.smin = ByteUtils.getIntBE(spanData, position);
|
||||
span.smin = ByteUtils.GetIntBE(spanData, position);
|
||||
position += 4;
|
||||
span.smax = ByteUtils.getIntBE(spanData, position);
|
||||
span.smax = ByteUtils.GetIntBE(spanData, position);
|
||||
position += 4;
|
||||
span.area = ByteUtils.getIntBE(spanData, position);
|
||||
span.area = ByteUtils.GetIntBE(spanData, position);
|
||||
position += 4;
|
||||
if (prev == null)
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
return hf;
|
||||
}
|
||||
|
||||
private Heightfield heightfieldLE()
|
||||
private Heightfield HeightfieldLE()
|
||||
{
|
||||
Heightfield hf = new Heightfield(width, depth, boundsMin, boundsMax, cellSize, cellHeight, borderSize);
|
||||
int position = 0;
|
||||
|
@ -116,16 +116,16 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
Span prev = null;
|
||||
int spanCount = ByteUtils.getShortLE(spanData, position);
|
||||
int spanCount = ByteUtils.GetShortLE(spanData, position);
|
||||
position += 2;
|
||||
for (int s = 0; s < spanCount; s++)
|
||||
{
|
||||
Span span = new Span();
|
||||
span.smin = ByteUtils.getIntLE(spanData, position);
|
||||
span.smin = ByteUtils.GetIntLE(spanData, position);
|
||||
position += 4;
|
||||
span.smax = ByteUtils.getIntLE(spanData, position);
|
||||
span.smax = ByteUtils.GetIntLE(spanData, position);
|
||||
position += 4;
|
||||
span.area = ByteUtils.getIntLE(spanData, position);
|
||||
span.area = ByteUtils.GetIntLE(spanData, position);
|
||||
position += 4;
|
||||
if (prev == null)
|
||||
{
|
||||
|
@ -144,7 +144,7 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
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 totalCount = 0;
|
||||
|
@ -168,13 +168,13 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
{
|
||||
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];
|
||||
while (span != null)
|
||||
{
|
||||
position = ByteUtils.putInt(span.smin, data, position, order);
|
||||
position = ByteUtils.putInt(span.smax, data, position, order);
|
||||
position = ByteUtils.putInt(span.area, data, position, order);
|
||||
position = ByteUtils.PutInt(span.smin, data, position, order);
|
||||
position = ByteUtils.PutInt(span.smax, data, position, order);
|
||||
position = ByteUtils.PutInt(span.area, data, position, order);
|
||||
span = span.next;
|
||||
}
|
||||
}
|
||||
|
@ -183,30 +183,30 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
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;
|
||||
if (buf.order() == order)
|
||||
if (buf.Order() == order)
|
||||
{
|
||||
data = buf.ReadBytes(buf.limit()).ToArray();
|
||||
data = buf.ReadBytes(buf.Limit()).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
data = new byte[buf.limit()];
|
||||
data = new byte[buf.Limit()];
|
||||
int l = width * height;
|
||||
int position = 0;
|
||||
for (int i = 0; i < l; i++)
|
||||
{
|
||||
int count = buf.getShort();
|
||||
ByteUtils.putShort(count, data, position, order);
|
||||
int count = buf.GetShort();
|
||||
ByteUtils.PutShort(count, data, position, order);
|
||||
position += 2;
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
ByteUtils.putInt(buf.getInt(), data, position, order);
|
||||
ByteUtils.PutInt(buf.GetInt(), data, position, order);
|
||||
position += 4;
|
||||
ByteUtils.putInt(buf.getInt(), data, position, order);
|
||||
ByteUtils.PutInt(buf.GetInt(), data, position, order);
|
||||
position += 4;
|
||||
ByteUtils.putInt(buf.getInt(), data, position, order);
|
||||
ByteUtils.PutInt(buf.GetInt(), data, position, order);
|
||||
position += 4;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,14 +31,14 @@ namespace DotRecast.Detour.Dynamic
|
|||
this._affectedTiles = affectedTiles;
|
||||
}
|
||||
|
||||
public ICollection<DynamicTile> affectedTiles()
|
||||
public ICollection<DynamicTile> AffectedTiles()
|
||||
{
|
||||
return _affectedTiles;
|
||||
}
|
||||
|
||||
public void process(DynamicTile tile)
|
||||
public void Process(DynamicTile tile)
|
||||
{
|
||||
tile.removeCollider(colliderId);
|
||||
tile.RemoveCollider(colliderId);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,8 +22,8 @@ namespace DotRecast.Detour.Dynamic
|
|||
{
|
||||
public interface UpdateQueueItem
|
||||
{
|
||||
ICollection<DynamicTile> affectedTiles();
|
||||
ICollection<DynamicTile> AffectedTiles();
|
||||
|
||||
void process(DynamicTile tile);
|
||||
void Process(DynamicTile tile);
|
||||
}
|
||||
}
|
|
@ -47,12 +47,12 @@ namespace DotRecast.Detour.Dynamic
|
|||
*
|
||||
* @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 relStartZ = start.z - origin.z;
|
||||
|
@ -79,7 +79,7 @@ namespace DotRecast.Detour.Dynamic
|
|||
float t = 0;
|
||||
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)
|
||||
{
|
||||
return hit;
|
||||
|
@ -107,7 +107,7 @@ namespace DotRecast.Detour.Dynamic
|
|||
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);
|
||||
if (null != hf)
|
||||
|
|
|
@ -23,15 +23,15 @@ namespace DotRecast.Detour.Extras
|
|||
{
|
||||
public class BVTreeBuilder
|
||||
{
|
||||
public void build(MeshData data)
|
||||
public void Build(MeshData data)
|
||||
{
|
||||
data.bvTree = new BVNode[data.header.polyCount * 2];
|
||||
data.header.bvNodeCount = data.bvTree.Length == 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];
|
||||
for (int i = 0; i < data.header.polyCount; i++)
|
||||
|
@ -41,23 +41,23 @@ namespace DotRecast.Detour.Extras
|
|||
it.i = i;
|
||||
Vector3f bmin = new Vector3f();
|
||||
Vector3f bmax = new Vector3f();
|
||||
vCopy(ref bmin, data.verts, data.polys[i].verts[0] * 3);
|
||||
vCopy(ref bmax, 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);
|
||||
for (int j = 1; j < data.polys[i].vertCount; j++)
|
||||
{
|
||||
vMin(ref bmin, data.verts, data.polys[i].verts[j] * 3);
|
||||
vMax(ref bmax, 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);
|
||||
}
|
||||
|
||||
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[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[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.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[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[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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,22 +7,22 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
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)
|
||||
{
|
||||
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));
|
||||
sampleGroundSegment(heightFunc, es.start, ngsamples);
|
||||
SampleGroundSegment(heightFunc, es.start, ngsamples);
|
||||
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];
|
||||
|
||||
|
@ -32,7 +32,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
|
||||
GroundSample s = new GroundSample();
|
||||
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);
|
||||
s.p.x = pt.x;
|
||||
s.p.y = height.Item2;
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
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()
|
||||
{
|
||||
x = lerp(start.x, end.x, Math.Min(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))
|
||||
x = Lerp(start.x, end.x, Math.Min(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))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
public class EdgeExtractor
|
||||
{
|
||||
public Edge[] extractEdges(PolyMesh mesh)
|
||||
public Edge[] ExtractEdges(PolyMesh mesh)
|
||||
{
|
||||
List<Edge> edges = new List<Edge>();
|
||||
if (mesh != null)
|
||||
|
|
|
@ -17,11 +17,11 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
public EdgeSampler(Edge edge, Trajectory trajectory)
|
||||
{
|
||||
this.trajectory = trajectory;
|
||||
ax = vSub(edge.sq, edge.sp);
|
||||
vNormalize(ref ax);
|
||||
vSet(ref az, ax.z, 0, -ax.x);
|
||||
vNormalize(ref az);
|
||||
vSet(ref ay, 0, 1, 0);
|
||||
ax = VSub(edge.sq, edge.sp);
|
||||
VNormalize(ref ax);
|
||||
VSet(ref az, ax.z, 0, -ax.x);
|
||||
VNormalize(ref az);
|
||||
VSet(ref ay, 0, 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,16 +5,16 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
class EdgeSamplerFactory
|
||||
{
|
||||
public EdgeSampler get(JumpLinkBuilderConfig acfg, JumpLinkType type, Edge edge)
|
||||
public EdgeSampler Get(JumpLinkBuilderConfig acfg, JumpLinkType type, Edge edge)
|
||||
{
|
||||
EdgeSampler es = null;
|
||||
switch (type.Bit)
|
||||
{
|
||||
case JumpLinkType.EDGE_JUMP_BIT:
|
||||
es = initEdgeJumpSampler(acfg, edge);
|
||||
es = InitEdgeJumpSampler(acfg, edge);
|
||||
break;
|
||||
case JumpLinkType.EDGE_CLIMB_DOWN_BIT:
|
||||
es = initClimbDownSampler(acfg, edge);
|
||||
es = InitClimbDownSampler(acfg, edge);
|
||||
break;
|
||||
case JumpLinkType.EDGE_JUMP_OVER_BIT:
|
||||
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));
|
||||
es.start.height = acfg.agentClimb * 2;
|
||||
Vector3f offset = new Vector3f();
|
||||
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.q, edge.sq, offset);
|
||||
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.q, edge.sq, offset);
|
||||
|
||||
float dx = acfg.endDistance - 2 * acfg.agentRadius;
|
||||
float cs = acfg.cellSize;
|
||||
|
@ -42,43 +42,43 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
float v = (float)j / (float)(nsamples - 1);
|
||||
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();
|
||||
end.height = acfg.heightRange;
|
||||
vadd(ref end.p, edge.sp, offset);
|
||||
vadd(ref end.q, edge.sq, offset);
|
||||
Vadd(ref end.p, edge.sp, offset);
|
||||
Vadd(ref end.q, edge.sq, offset);
|
||||
es.end.Add(end);
|
||||
}
|
||||
|
||||
return es;
|
||||
}
|
||||
|
||||
private EdgeSampler initClimbDownSampler(JumpLinkBuilderConfig acfg, Edge edge)
|
||||
private EdgeSampler InitClimbDownSampler(JumpLinkBuilderConfig acfg, Edge edge)
|
||||
{
|
||||
EdgeSampler es = new EdgeSampler(edge, new ClimbTrajectory());
|
||||
es.start.height = acfg.agentClimb * 2;
|
||||
Vector3f offset = new Vector3f();
|
||||
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.q, edge.sq, offset);
|
||||
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.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();
|
||||
end.height = acfg.heightRange;
|
||||
vadd(ref end.p, edge.sp, offset);
|
||||
vadd(ref end.q, edge.sq, offset);
|
||||
Vadd(ref end.p, edge.sp, offset);
|
||||
Vadd(ref end.q, edge.sq, offset);
|
||||
es.end.Add(end);
|
||||
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[1] = v1[1] + v2[1];
|
||||
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.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[1] = ax[1] * pt[0] + ay[1] * 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.y = ax.y * pt.x + ay.y * pt.y;
|
||||
|
|
|
@ -4,6 +4,6 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
public interface GroundSampler
|
||||
{
|
||||
void sample(JumpLinkBuilderConfig acfg, RecastBuilderResult result, EdgeSampler es);
|
||||
void Sample(JumpLinkBuilderConfig acfg, RecastBuilderResult result, EdgeSampler es);
|
||||
}
|
||||
}
|
|
@ -21,10 +21,10 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
public JumpLinkBuilder(IList<RecastBuilderResult> 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>();
|
||||
for (int tile = 0; tile < results.Count; tile++)
|
||||
|
@ -32,24 +32,24 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
Edge[] edges = this.edges[tile];
|
||||
foreach (Edge edge in edges)
|
||||
{
|
||||
links.AddRange(processEdge(acfg, results[tile], type, edge));
|
||||
links.AddRange(ProcessEdge(acfg, results[tile], type, edge));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
groundSampler.sample(acfg, result, es);
|
||||
trajectorySampler.sample(acfg, result.getSolidHeightfield(), es);
|
||||
JumpSegment[] jumpSegments = jumpSegmentBuilder.build(acfg, es);
|
||||
return buildJumpLinks(acfg, es, jumpSegments);
|
||||
EdgeSampler es = edgeSamplerFactory.Get(acfg, type, edge);
|
||||
groundSampler.Sample(acfg, result, es);
|
||||
trajectorySampler.Sample(acfg, result.GetSolidHeightfield(), es);
|
||||
JumpSegment[] jumpSegments = jumpSegmentBuilder.Build(acfg, es);
|
||||
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>();
|
||||
foreach (JumpSegment js in jumpSegments)
|
||||
|
@ -59,7 +59,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
GroundSegment end = es.end[js.groundSegment];
|
||||
Vector3f ep = end.gsamples[js.startSample].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)
|
||||
{
|
||||
JumpLink link = new JumpLink();
|
||||
|
@ -72,12 +72,12 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
for (int j = 0; j < link.nspine; ++j)
|
||||
{
|
||||
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 + 1] = p.y;
|
||||
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 + 1] = p.y;
|
||||
link.spine1[j * 3 + 2] = p.z;
|
||||
|
@ -88,7 +88,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
return links;
|
||||
}
|
||||
|
||||
public List<Edge[]> getEdges()
|
||||
public List<Edge[]> GetEdges()
|
||||
{
|
||||
return edges;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
class JumpSegmentBuilder
|
||||
{
|
||||
public JumpSegment[] build(JumpLinkBuilderConfig acfg, EdgeSampler es)
|
||||
public JumpSegment[] Build(JumpLinkBuilderConfig acfg, EdgeSampler es)
|
||||
{
|
||||
int n = es.end[0].gsamples.Length;
|
||||
int[][] sampleGrid = ArrayUtils.Of<int>(n, es.end.Count);
|
||||
|
@ -35,7 +35,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
var queue = new Queue<int[]>();
|
||||
queue.Enqueue(new int[] { i, j });
|
||||
fill(es, sampleGrid, queue, acfg.agentClimb, region);
|
||||
Fill(es, sampleGrid, queue, acfg.agentClimb, region);
|
||||
region++;
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
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))
|
||||
{
|
||||
|
@ -97,28 +97,28 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
float h = p.p.y;
|
||||
if (i < sampleGrid.Length - 1)
|
||||
{
|
||||
addNeighbour(es, queue, agentClimb, h, i + 1, j);
|
||||
AddNeighbour(es, queue, agentClimb, h, i + 1, j);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
addNeighbour(es, queue, agentClimb, h, i, j + 1);
|
||||
AddNeighbour(es, queue, agentClimb, h, i, j + 1);
|
||||
}
|
||||
|
||||
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];
|
||||
if (q.validTrajectory && Math.Abs(q.p.y - h) < agentClimb)
|
||||
|
|
|
@ -12,17 +12,17 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
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
|
||||
{
|
||||
x = lerp(start.x, end.x, u),
|
||||
y = interpolateHeight(start.y, end.y, u),
|
||||
z = lerp(start.z, end.z, u)
|
||||
x = Lerp(start.x, end.x, u),
|
||||
y = InterpolateHeight(start.y, end.y, 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)
|
||||
{
|
||||
|
|
|
@ -11,48 +11,48 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
|
||||
private class NoOpFilter : QueryFilter
|
||||
{
|
||||
public bool passFilter(long refs, MeshTile tile, Poly poly)
|
||||
public bool PassFilter(long refs, MeshTile tile, Poly poly)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
sampleGround(acfg, es, (pt, h) => getNavMeshHeight(navMeshQuery, pt, acfg.cellSize, h));
|
||||
NavMeshQuery navMeshQuery = CreateNavMesh(result, acfg.agentRadius, acfg.agentHeight, acfg.agentClimb);
|
||||
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();
|
||||
option.verts = r.getMesh().verts;
|
||||
option.vertCount = r.getMesh().nverts;
|
||||
option.polys = r.getMesh().polys;
|
||||
option.polyAreas = r.getMesh().areas;
|
||||
option.polyFlags = r.getMesh().flags;
|
||||
option.polyCount = r.getMesh().npolys;
|
||||
option.nvp = r.getMesh().nvp;
|
||||
option.detailMeshes = r.getMeshDetail().meshes;
|
||||
option.detailVerts = r.getMeshDetail().verts;
|
||||
option.detailVertsCount = r.getMeshDetail().nverts;
|
||||
option.detailTris = r.getMeshDetail().tris;
|
||||
option.detailTriCount = r.getMeshDetail().ntris;
|
||||
option.verts = r.GetMesh().verts;
|
||||
option.vertCount = r.GetMesh().nverts;
|
||||
option.polys = r.GetMesh().polys;
|
||||
option.polyAreas = r.GetMesh().areas;
|
||||
option.polyFlags = r.GetMesh().flags;
|
||||
option.polyCount = r.GetMesh().npolys;
|
||||
option.nvp = r.GetMesh().nvp;
|
||||
option.detailMeshes = r.GetMeshDetail().meshes;
|
||||
option.detailVerts = r.GetMeshDetail().verts;
|
||||
option.detailVertsCount = r.GetMeshDetail().nverts;
|
||||
option.detailTris = r.GetMeshDetail().tris;
|
||||
option.detailTriCount = r.GetMeshDetail().ntris;
|
||||
option.walkableRadius = agentRadius;
|
||||
option.walkableHeight = agentHeight;
|
||||
option.walkableClimb = agentClimb;
|
||||
option.bmin = r.getMesh().bmin;
|
||||
option.bmax = r.getMesh().bmax;
|
||||
option.cs = r.getMesh().cs;
|
||||
option.ch = r.getMesh().ch;
|
||||
option.bmin = r.GetMesh().bmin;
|
||||
option.bmax = r.GetMesh().bmax;
|
||||
option.cs = r.GetMesh().cs;
|
||||
option.ch = r.GetMesh().ch;
|
||||
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
|
||||
|
@ -64,32 +64,32 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
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 };
|
||||
float maxHeight = pt.y + heightRange;
|
||||
AtomicBoolean found = new AtomicBoolean();
|
||||
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())
|
||||
{
|
||||
float y = h.result;
|
||||
if (y > minHeight.Get() && y < maxHeight)
|
||||
{
|
||||
minHeight.Exchange(y);
|
||||
found.set(true);
|
||||
found.Set(true);
|
||||
}
|
||||
}
|
||||
}));
|
||||
if (found.get())
|
||||
if (found.Get())
|
||||
{
|
||||
return Tuple.Create(true, minHeight.Get());
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public virtual Vector3f apply(Vector3f start, Vector3f end, float u)
|
||||
public virtual Vector3f Apply(Vector3f start, Vector3f end, float u)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
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;
|
||||
for (int i = 0; i < nsamples; ++i)
|
||||
|
@ -21,7 +21,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!sampleTrajectory(acfg, heightfield, ssmp.p, esmp.p, es.trajectory))
|
||||
if (!SampleTrajectory(acfg, heightfield, ssmp.p, esmp.p, es.trajectory))
|
||||
{
|
||||
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 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));
|
||||
for (int i = 0; i < nsamples; ++i)
|
||||
{
|
||||
float u = (float)i / (float)(nsamples - 1);
|
||||
Vector3f p = tra.apply(pa, pb, u);
|
||||
if (checkHeightfieldCollision(solid, p.x, p.y + acfg.groundTolerance, p.y + acfg.agentHeight, p.z))
|
||||
Vector3f p = tra.Apply(pa, pb, u);
|
||||
if (CheckHeightfieldCollision(solid, p.x, p.y + acfg.groundTolerance, p.y + acfg.agentHeight, p.z))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
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 h = solid.height;
|
||||
|
@ -75,7 +75,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
float symin = orig.y + s.smin * ch;
|
||||
float symax = orig.y + s.smax * ch;
|
||||
if (overlapRange(ymin, ymax, symin, symax))
|
||||
if (OverlapRange(ymin, ymax, symin, symax))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -22,14 +22,14 @@ namespace DotRecast.Detour.Extras
|
|||
{
|
||||
public class ObjExporter
|
||||
{
|
||||
public void export(NavMesh mesh)
|
||||
public void Export(NavMesh mesh)
|
||||
{
|
||||
string filename = Path.Combine(Directory.GetCurrentDirectory(), "Demo", "astar.obj");
|
||||
using var fs = new FileStream(filename, FileMode.CreateNew);
|
||||
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)
|
||||
{
|
||||
for (int v = 0; v < tile.data.header.vertCount; v++)
|
||||
|
@ -41,9 +41,9 @@ namespace DotRecast.Detour.Extras
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
for (int p = 0; p < tile.data.header.polyCount; p++)
|
||||
|
@ -67,8 +67,8 @@ namespace DotRecast.Detour.Extras
|
|||
*
|
||||
MeshSetReader reader = new MeshSetReader();
|
||||
ObjExporter exporter = new ObjExporter();
|
||||
exporter.export(mesh);
|
||||
reader.read(new FileInputStream("/home/piotr/Downloads/graph/all_tiles_navmesh.bin"), 3);
|
||||
exporter.Export(mesh);
|
||||
reader.Read(new FileInputStream("/home/piotr/Downloads/graph/all_tiles_navmesh.bin"), 3);
|
||||
|
||||
|
||||
*/
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace DotRecast.Detour.Extras
|
|||
/**
|
||||
* 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
|
||||
for (int i = 0; i < node.vertCount; i++)
|
||||
|
@ -47,10 +47,10 @@ namespace DotRecast.Detour.Extras
|
|||
for (int k = 0; k < neighbour.vertCount; k++)
|
||||
{
|
||||
int l = (k + 1) % neighbour.vertCount;
|
||||
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[i], neighbourTile.verts, neighbour.verts[k])
|
||||
&& samePosition(tile.verts, node.verts[j], 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[i], neighbourTile.verts, neighbour.verts[k])
|
||||
&& SamePosition(tile.verts, node.verts[j], neighbourTile.verts, neighbour.verts[l])))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ namespace DotRecast.Detour.Extras
|
|||
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++)
|
||||
{
|
||||
|
@ -76,7 +76,7 @@ namespace DotRecast.Detour.Extras
|
|||
/**
|
||||
* 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;
|
||||
int edge = 0;
|
||||
|
|
|
@ -22,11 +22,11 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
{
|
||||
private readonly BVTreeBuilder builder = new BVTreeBuilder();
|
||||
|
||||
public void build(GraphMeshData graphData)
|
||||
public void Build(GraphMeshData graphData)
|
||||
{
|
||||
foreach (MeshData d in graphData.tiles)
|
||||
{
|
||||
builder.build(d);
|
||||
builder.Build(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,24 +24,24 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
{
|
||||
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[]>();
|
||||
ByteBuffer buffer = toByteBuffer(file, filename);
|
||||
while (buffer.remaining() > 0)
|
||||
ByteBuffer buffer = ToByteBuffer(file, filename);
|
||||
while (buffer.Remaining() > 0)
|
||||
{
|
||||
int count = buffer.getInt();
|
||||
int count = buffer.GetInt();
|
||||
int[] nodeConnections = new int[count];
|
||||
connections.Add(nodeConnections);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int nodeIndex = buffer.getInt();
|
||||
int nodeIndex = buffer.GetInt();
|
||||
nodeConnections[i] = indexToNode[nodeIndex];
|
||||
// XXX: Is there anything we can do with the cost?
|
||||
int cost = buffer.getInt();
|
||||
if (meta.isVersionAtLeast(Meta.UPDATED_STRUCT_VERSION))
|
||||
int cost = buffer.GetInt();
|
||||
if (meta.IsVersionAtLeast(Meta.UPDATED_STRUCT_VERSION))
|
||||
{
|
||||
byte shapeEdge = buffer.get();
|
||||
byte shapeEdge = buffer.Get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
this.tiles = tiles;
|
||||
}
|
||||
|
||||
public int countNodes()
|
||||
public int CountNodes()
|
||||
{
|
||||
int polyCount = 0;
|
||||
foreach (MeshData t in tiles)
|
||||
|
@ -42,7 +42,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
return polyCount;
|
||||
}
|
||||
|
||||
public Poly getNode(int node)
|
||||
public Poly GetNode(int node)
|
||||
{
|
||||
int index = 0;
|
||||
foreach (MeshData t in tiles)
|
||||
|
@ -58,7 +58,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
return null;
|
||||
}
|
||||
|
||||
public MeshData getTile(int node)
|
||||
public MeshData GetTile(int node)
|
||||
{
|
||||
int index = 0;
|
||||
foreach (MeshData t in tiles)
|
||||
|
|
|
@ -27,59 +27,59 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
{
|
||||
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);
|
||||
int tileXCount = buffer.getInt();
|
||||
ByteBuffer buffer = ToByteBuffer(file, filename);
|
||||
int tileXCount = buffer.GetInt();
|
||||
if (tileXCount < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int tileZCount = buffer.getInt();
|
||||
int tileZCount = buffer.GetInt();
|
||||
MeshData[] tiles = new MeshData[tileXCount * tileZCount];
|
||||
for (int z = 0; z < tileZCount; z++)
|
||||
{
|
||||
for (int x = 0; x < tileXCount; x++)
|
||||
{
|
||||
int tileIndex = x + z * tileXCount;
|
||||
int tx = buffer.getInt();
|
||||
int tz = buffer.getInt();
|
||||
int tx = buffer.GetInt();
|
||||
int tz = buffer.GetInt();
|
||||
if (tx != x || tz != z)
|
||||
{
|
||||
throw new ArgumentException("Inconsistent tile positions");
|
||||
}
|
||||
|
||||
tiles[tileIndex] = new MeshData();
|
||||
int width = buffer.getInt();
|
||||
int depth = buffer.getInt();
|
||||
int width = buffer.GetInt();
|
||||
int depth = buffer.GetInt();
|
||||
|
||||
int trisCount = buffer.getInt();
|
||||
int trisCount = buffer.GetInt();
|
||||
int[] tris = new int[trisCount];
|
||||
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];
|
||||
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++)
|
||||
{
|
||||
vertsInGraphSpace[i] = buffer.getInt();
|
||||
vertsInGraphSpace[i] = buffer.GetInt();
|
||||
}
|
||||
|
||||
int nodeCount = buffer.getInt();
|
||||
int nodeCount = buffer.GetInt();
|
||||
Poly[] nodes = new Poly[nodeCount];
|
||||
PolyDetail[] detailNodes = new PolyDetail[nodeCount];
|
||||
float[] detailVerts = new float[0];
|
||||
int[] detailTris = new int[4 * nodeCount];
|
||||
int vertMask = getVertMask(vertsCount);
|
||||
int vertMask = GetVertMask(vertsCount);
|
||||
float ymin = float.PositiveInfinity;
|
||||
float ymax = float.NegativeInfinity;
|
||||
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].vertCount = 3;
|
||||
// XXX: What can we do with the penalty?
|
||||
int penalty = buffer.getInt();
|
||||
nodes[i].flags = buffer.getInt();
|
||||
nodes[i].verts[0] = buffer.getInt() & vertMask;
|
||||
nodes[i].verts[1] = buffer.getInt() & vertMask;
|
||||
nodes[i].verts[2] = buffer.getInt() & vertMask;
|
||||
int penalty = buffer.GetInt();
|
||||
nodes[i].flags = buffer.GetInt();
|
||||
nodes[i].verts[0] = buffer.GetInt() & vertMask;
|
||||
nodes[i].verts[1] = 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[1] * 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);
|
||||
}
|
||||
|
||||
public static int highestOneBit(uint i)
|
||||
public static int HighestOneBit(uint i)
|
||||
{
|
||||
i |= (i >> 1);
|
||||
i |= (i >> 2);
|
||||
|
@ -159,9 +159,9 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
vertMask *= 2;
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
{
|
||||
public class GraphMetaReader
|
||||
{
|
||||
public GraphMeta read(ZipArchive file, string filename)
|
||||
public GraphMeta Read(ZipArchive file, string filename)
|
||||
{
|
||||
ZipArchiveEntry entry = file.GetEntry(filename);
|
||||
using StreamReader reader = new StreamReader(entry.Open());
|
||||
|
|
|
@ -24,32 +24,32 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
public class LinkBuilder
|
||||
{
|
||||
// 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++)
|
||||
{
|
||||
int[] nodeConnections = connections[n];
|
||||
MeshData tile = graphData.getTile(n);
|
||||
Poly node = graphData.getNode(n);
|
||||
MeshData tile = graphData.GetTile(n);
|
||||
Poly node = graphData.GetNode(n);
|
||||
foreach (int connection in nodeConnections)
|
||||
{
|
||||
MeshData neighbourTile = graphData.getTile(connection - nodeOffset);
|
||||
MeshData neighbourTile = graphData.GetTile(connection - nodeOffset);
|
||||
if (neighbourTile != tile)
|
||||
{
|
||||
buildExternalLink(tile, node, neighbourTile);
|
||||
BuildExternalLink(tile, node, neighbourTile);
|
||||
}
|
||||
else
|
||||
{
|
||||
Poly neighbour = graphData.getNode(connection - nodeOffset);
|
||||
buildInternalLink(tile, node, neighbourTile, neighbour);
|
||||
Poly neighbour = graphData.GetNode(connection - nodeOffset);
|
||||
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)
|
||||
{
|
||||
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
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,15 +32,15 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
public string[] guids { 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[] minSupported = parseVersion(minVersion);
|
||||
int[] actual = ParseVersion(version);
|
||||
int[] minSupported = ParseVersion(minVersion);
|
||||
for (int i = 0; i < Math.Min(actual.Length, minSupported.Length); i++)
|
||||
{
|
||||
if (actual[i] > minSupported[i])
|
||||
|
@ -56,7 +56,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
return true;
|
||||
}
|
||||
|
||||
private int[] parseVersion(string version)
|
||||
private int[] ParseVersion(string version)
|
||||
{
|
||||
Match m = VERSION_PATTERN.Match(version);
|
||||
if (m.Success)
|
||||
|
@ -73,7 +73,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
throw new ArgumentException("Invalid version format: " + version);
|
||||
}
|
||||
|
||||
public bool isSupportedType()
|
||||
public bool IsSupportedType()
|
||||
{
|
||||
foreach (string t in typeNames)
|
||||
{
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
{
|
||||
public class MetaReader
|
||||
{
|
||||
public Meta read(ZipArchive file, string filename)
|
||||
public Meta Read(ZipArchive file, string filename)
|
||||
{
|
||||
ZipArchiveEntry entry = file.GetEntry(filename);
|
||||
using StreamReader reader = new StreamReader(entry.Open());
|
||||
|
@ -42,12 +42,12 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
json = regex.Replace(json, replacement);
|
||||
|
||||
var meta = JsonSerializer.Deserialize<Meta>(json);
|
||||
if (!meta.isSupportedType())
|
||||
if (!meta.IsSupportedType())
|
||||
{
|
||||
throw new ArgumentException("Unsupported graph type " + string.Join(", ", meta.typeNames));
|
||||
}
|
||||
|
||||
if (!meta.isSupportedVersion())
|
||||
if (!meta.IsSupportedVersion())
|
||||
{
|
||||
throw new ArgumentException("Unsupported version " + meta.version);
|
||||
}
|
||||
|
|
|
@ -23,15 +23,15 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
{
|
||||
class NodeIndexReader : ZipBinaryReader
|
||||
{
|
||||
public int[] read(ZipArchive file, string filename)
|
||||
public int[] Read(ZipArchive file, string filename)
|
||||
{
|
||||
ByteBuffer buffer = toByteBuffer(file, filename);
|
||||
int maxNodeIndex = buffer.getInt();
|
||||
ByteBuffer buffer = ToByteBuffer(file, filename);
|
||||
int maxNodeIndex = buffer.GetInt();
|
||||
int[] int2Node = new int[maxNodeIndex + 1];
|
||||
int node = 0;
|
||||
while (buffer.remaining() > 0)
|
||||
while (buffer.Remaining() > 0)
|
||||
{
|
||||
int index = buffer.getInt();
|
||||
int index = buffer.GetInt();
|
||||
int2Node[index] = node++;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,27 +23,27 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
{
|
||||
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);
|
||||
int linkCount = buffer.getInt();
|
||||
ByteBuffer buffer = ToByteBuffer(file, filename);
|
||||
int linkCount = buffer.GetInt();
|
||||
NodeLink2[] links = new NodeLink2[linkCount];
|
||||
for (int i = 0; i < linkCount; i++)
|
||||
{
|
||||
long linkID = buffer.getLong();
|
||||
int startNode = indexToNode[buffer.getInt()];
|
||||
int endNode = indexToNode[buffer.getInt()];
|
||||
int connectedNode1 = buffer.getInt();
|
||||
int connectedNode2 = buffer.getInt();
|
||||
long linkID = buffer.GetLong();
|
||||
int startNode = indexToNode[buffer.GetInt()];
|
||||
int endNode = indexToNode[buffer.GetInt()];
|
||||
int connectedNode1 = buffer.GetInt();
|
||||
int connectedNode2 = buffer.GetInt();
|
||||
Vector3f clamped1 = new Vector3f();
|
||||
clamped1.x = buffer.getFloat();
|
||||
clamped1.y = buffer.getFloat();
|
||||
clamped1.z = buffer.getFloat();
|
||||
clamped1.x = buffer.GetFloat();
|
||||
clamped1.y = buffer.GetFloat();
|
||||
clamped1.z = buffer.GetFloat();
|
||||
Vector3f clamped2 = new Vector3f();
|
||||
clamped2.x = buffer.getFloat();
|
||||
clamped2.y = buffer.getFloat();
|
||||
clamped2.z = buffer.getFloat();
|
||||
bool postScanCalled = buffer.get() != 0;
|
||||
clamped2.x = buffer.GetFloat();
|
||||
clamped2.y = buffer.GetFloat();
|
||||
clamped2.z = buffer.GetFloat();
|
||||
bool postScanCalled = buffer.Get() != 0;
|
||||
links[i] = new NodeLink2(linkID, startNode, endNode, clamped1, clamped2);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,16 +22,16 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
{
|
||||
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)
|
||||
{
|
||||
foreach (NodeLink2 l in links)
|
||||
{
|
||||
MeshData startTile = graphData.getTile(l.startNode - nodeOffset);
|
||||
Poly startNode = graphData.getNode(l.startNode - nodeOffset);
|
||||
MeshData endTile = graphData.getTile(l.endNode - nodeOffset);
|
||||
Poly endNode = graphData.getNode(l.endNode - nodeOffset);
|
||||
MeshData startTile = graphData.GetTile(l.startNode - nodeOffset);
|
||||
Poly startNode = graphData.GetNode(l.startNode - nodeOffset);
|
||||
MeshData endTile = graphData.GetTile(l.endNode - nodeOffset);
|
||||
Poly endNode = graphData.GetNode(l.endNode - nodeOffset);
|
||||
if (startNode != null && endNode != null)
|
||||
{
|
||||
// FIXME: Optimise
|
||||
|
@ -40,7 +40,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
startTile.polys[poly] = new Poly(poly, 2);
|
||||
startTile.polys[poly].verts[0] = startTile.header.vertCount;
|
||||
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.header.polyCount++;
|
||||
startTile.header.vertCount += 2;
|
||||
|
@ -54,7 +54,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
connection.rad = 0.1f;
|
||||
connection.side = startTile == endTile
|
||||
? 0xFF
|
||||
: NavMeshBuilder.classifyOffMeshPoint(new VectorPtr(connection.pos, 3),
|
||||
: NavMeshBuilder.ClassifyOffMeshPoint(new VectorPtr(connection.pos, 3),
|
||||
startTile.header.bmin, startTile.header.bmax);
|
||||
connection.userId = (int)l.linkID;
|
||||
if (startTile.offMeshCons == null)
|
||||
|
|
|
@ -33,9 +33,9 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
private readonly LinkBuilder linkCreator = new LinkBuilder();
|
||||
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;
|
||||
NodeLink2[] nodeLinks2 = graphData.nodeLinks2;
|
||||
NavMesh[] meshes = new NavMesh[meta.graphs];
|
||||
|
@ -45,7 +45,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
GraphMeta graphMeta = graphData.graphMeta[graphIndex];
|
||||
GraphMeshData graphMeshData = graphData.graphMeshData[graphIndex];
|
||||
List<int[]> connections = graphData.graphConnections[graphIndex];
|
||||
int nodeCount = graphMeshData.countNodes();
|
||||
int nodeCount = graphMeshData.CountNodes();
|
||||
if (connections.Count != 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
|
||||
bvTreeCreator.build(graphMeshData);
|
||||
bvTreeCreator.Build(graphMeshData);
|
||||
// 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
|
||||
offMeshLinkCreator.build(graphMeshData, nodeLinks2, nodeOffset);
|
||||
offMeshLinkCreator.Build(graphMeshData, nodeLinks2, nodeOffset);
|
||||
NavMeshParams option = new NavMeshParams();
|
||||
option.maxTiles = graphMeshData.tiles.Length;
|
||||
option.maxPolys = 32768;
|
||||
|
@ -69,11 +69,11 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
NavMesh mesh = new NavMesh(option, 3);
|
||||
foreach (MeshData t in graphMeshData.tiles)
|
||||
{
|
||||
mesh.addTile(t, 0, 0);
|
||||
mesh.AddTile(t, 0, 0);
|
||||
}
|
||||
|
||||
meshes[graphIndex] = mesh;
|
||||
nodeOffset += graphMeshData.countNodes();
|
||||
nodeOffset += graphMeshData.CountNodes();
|
||||
}
|
||||
|
||||
return meshes;
|
||||
|
|
|
@ -38,27 +38,27 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
private readonly GraphConnectionReader graphConnectionReader = new GraphConnectionReader();
|
||||
private readonly NodeLink2Reader nodeLink2Reader = new NodeLink2Reader();
|
||||
|
||||
public GraphData read(FileStream zipFile)
|
||||
public GraphData Read(FileStream zipFile)
|
||||
{
|
||||
using ZipArchive file = new ZipArchive(zipFile);
|
||||
// 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
|
||||
int[] indexToNode = nodeIndexReader.read(file, NODE_INDEX_FILE_NAME);
|
||||
int[] indexToNode = nodeIndexReader.Read(file, NODE_INDEX_FILE_NAME);
|
||||
// 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
|
||||
List<GraphMeta> metaList = new List<GraphMeta>();
|
||||
List<GraphMeshData> meshDataList = new List<GraphMeshData>();
|
||||
List<List<int[]>> connectionsList = new List<List<int[]>>();
|
||||
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
|
||||
GraphMeshData graphData = graphDataReader.read(file,
|
||||
GraphMeshData graphData = graphDataReader.Read(file,
|
||||
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
|
||||
List<int[]> connections = graphConnectionReader.read(file,
|
||||
List<int[]> connections = graphConnectionReader.Read(file,
|
||||
string.Format(GRAPH_CONNECTION_FILE_NAME_PATTERN, graphIndex), meta, indexToNode);
|
||||
metaList.Add(graphMeta);
|
||||
meshDataList.Add(graphData);
|
||||
|
|
|
@ -25,13 +25,13 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
{
|
||||
public abstract class ZipBinaryReader
|
||||
{
|
||||
protected ByteBuffer toByteBuffer(ZipArchive file, string filename)
|
||||
protected ByteBuffer ToByteBuffer(ZipArchive file, string filename)
|
||||
{
|
||||
ZipArchiveEntry graphReferences = file.GetEntry(filename);
|
||||
using var entryStream = graphReferences.Open();
|
||||
using var bis = new BinaryReader(entryStream);
|
||||
ByteBuffer buffer = IOUtils.toByteBuffer(bis);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
ByteBuffer buffer = IOUtils.ToByteBuffer(bis);
|
||||
buffer.Order(ByteOrder.LITTLE_ENDIAN);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,31 +29,31 @@ namespace DotRecast.Detour.TileCache
|
|||
{
|
||||
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)
|
||||
{
|
||||
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[]>();
|
||||
for (int y = 0; y < th; ++y)
|
||||
{
|
||||
for (int x = 0; x < tw; ++x)
|
||||
{
|
||||
layers.AddRange(build(x, y, order, cCompatibility));
|
||||
layers.AddRange(Build(x, y, order, cCompatibility));
|
||||
}
|
||||
}
|
||||
|
||||
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[]>>>>();
|
||||
for (int y = 0; y < th; ++y)
|
||||
|
@ -64,7 +64,7 @@ namespace DotRecast.Detour.TileCache
|
|||
int ty = y;
|
||||
var task = Task.Run(() =>
|
||||
{
|
||||
var partial = build(tx, ty, order, cCompatibility);
|
||||
var partial = Build(tx, ty, order, cCompatibility);
|
||||
return Tuple.Create(tx, ty, partial);
|
||||
});
|
||||
tasks.Enqueue(task);
|
||||
|
@ -88,6 +88,6 @@ namespace DotRecast.Detour.TileCache
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -54,13 +54,13 @@ namespace DotRecast.Detour.TileCache.Io.Compress
|
|||
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.
|
||||
*/
|
||||
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
|
||||
* {@link #MIN_RECOMENDED_LENGTH_FOR_LEVEL_2} {@link #LEVEL_1} will be choosen,
|
||||
* otherwise {@link #LEVEL_2}.
|
||||
|
@ -82,7 +82,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
|
|||
* @param inputLength length of input buffer
|
||||
* @return Maximum output buffer length
|
||||
*/
|
||||
public static int calculateOutputBufferLength(int inputLength)
|
||||
public static int CalculateOutputBufferLength(int inputLength)
|
||||
{
|
||||
int tempOutputLength = (int)(inputLength * 1.06);
|
||||
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).
|
||||
*/
|
||||
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)
|
||||
{
|
||||
int level;
|
||||
|
@ -178,9 +178,9 @@ namespace DotRecast.Detour.TileCache.Io.Compress
|
|||
/* check for a run */
|
||||
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] &&
|
||||
readU16(input, inOffset + ip - 1) == readU16(input, inOffset + ip + 1))
|
||||
ReadU16(input, inOffset + ip - 1) == ReadU16(input, inOffset + ip + 1))
|
||||
{
|
||||
distance = 1;
|
||||
ip += 3;
|
||||
|
@ -197,7 +197,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
|
|||
{
|
||||
/* find potential match */
|
||||
// HASH_FUNCTION(hval,ip);
|
||||
hval = hashFunction(input, inOffset + ip);
|
||||
hval = HashFunction(input, inOffset + ip);
|
||||
// hslot = htab + hval;
|
||||
hslot = hval;
|
||||
// refs = htab[hval];
|
||||
|
@ -258,7 +258,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
|
|||
len += 2;
|
||||
}
|
||||
}
|
||||
} // end if(!matchLabel)
|
||||
} // end If(!matchLabel)
|
||||
|
||||
/*
|
||||
* match:
|
||||
|
@ -440,11 +440,11 @@ namespace DotRecast.Detour.TileCache.Io.Compress
|
|||
|
||||
/* update the hash at match boundary */
|
||||
//HASH_FUNCTION(hval,ip);
|
||||
hval = hashFunction(input, inOffset + ip);
|
||||
hval = HashFunction(input, inOffset + ip);
|
||||
htab[hval] = ip++;
|
||||
|
||||
//HASH_FUNCTION(hval,ip);
|
||||
hval = hashFunction(input, inOffset + ip);
|
||||
hval = HashFunction(input, inOffset + ip);
|
||||
htab[hval] = ip++;
|
||||
|
||||
/* assuming literal copy */
|
||||
|
@ -459,7 +459,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
|
|||
output[outOffset + op++] = input[inOffset + anchor++];
|
||||
ip = anchor;
|
||||
copy++;
|
||||
if(copy == MAX_COPY){
|
||||
If(copy == MAX_COPY){
|
||||
copy = 0;
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
//int level = ((*(const flzuint8*)input) >> 5) + 1;
|
||||
|
@ -569,8 +569,8 @@ namespace DotRecast.Detour.TileCache.Io.Compress
|
|||
refs -= code;
|
||||
|
||||
/* match from 16-bit distance */
|
||||
// if(FASTLZ_UNEXPECT_CONDITIONAL(code==255))
|
||||
// if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8)))
|
||||
// If(FASTLZ_UNEXPECT_CONDITIONAL(code==255))
|
||||
// If(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8)))
|
||||
if (code == 255 && ofs == 31 << 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)
|
||||
{
|
||||
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);
|
||||
|
||||
// return op - (flzuint8*)output;
|
||||
return op;
|
||||
}
|
||||
|
||||
private static int hashFunction(byte[] p, int offset)
|
||||
private static int HashFunction(byte[] p, int offset)
|
||||
{
|
||||
int v = readU16(p, offset);
|
||||
v ^= readU16(p, offset + 1) ^ v >> 16 - HASH_LOG;
|
||||
int v = ReadU16(p, offset);
|
||||
v ^= ReadU16(p, offset + 1) ^ v >> 16 - HASH_LOG;
|
||||
v &= HASH_MASK;
|
||||
return v;
|
||||
}
|
||||
|
||||
private static int readU16(byte[] data, int offset)
|
||||
private static int ReadU16(byte[] data, int offset)
|
||||
{
|
||||
if (offset + 1 >= data.Length)
|
||||
{
|
||||
|
|
|
@ -24,17 +24,17 @@ namespace DotRecast.Detour.TileCache.Io.Compress
|
|||
{
|
||||
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];
|
||||
FastLz.decompress(buf, offset, len, output, 0, outputlen);
|
||||
FastLz.Decompress(buf, offset, len, output, 0, outputlen);
|
||||
return output;
|
||||
}
|
||||
|
||||
public byte[] compress(byte[] buf)
|
||||
public byte[] Compress(byte[] buf)
|
||||
{
|
||||
byte[] output = new byte[FastLz.calculateOutputBufferLength(buf.Length)];
|
||||
int len = FastLz.compress(buf, 0, buf.Length, output, 0, output.Length);
|
||||
byte[] output = new byte[FastLz.CalculateOutputBufferLength(buf.Length)];
|
||||
int len = FastLz.Compress(buf, 0, buf.Length, output, 0, output.Length);
|
||||
return ArrayUtils.CopyOf(output, len);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,12 @@ namespace DotRecast.Detour.TileCache.Io.Compress
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public byte[] compress(byte[] buf)
|
||||
public byte[] Compress(byte[] buf)
|
||||
{
|
||||
return LZ4Pickler.Pickle(buf);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace DotRecast.Detour.TileCache.Io.Compress
|
|||
{
|
||||
public static class TileCacheCompressorFactory
|
||||
{
|
||||
public static TileCacheCompressor get(bool cCompatibility)
|
||||
public static TileCacheCompressor Get(bool cCompatibility)
|
||||
{
|
||||
if (cCompatibility)
|
||||
return new FastLzTileCacheCompressor();
|
||||
|
|
|
@ -25,39 +25,39 @@ namespace DotRecast.Detour.TileCache.Io
|
|||
{
|
||||
public class TileCacheLayerHeaderReader
|
||||
{
|
||||
public TileCacheLayerHeader read(ByteBuffer data, bool cCompatibility)
|
||||
public TileCacheLayerHeader Read(ByteBuffer data, bool cCompatibility)
|
||||
{
|
||||
TileCacheLayerHeader header = new TileCacheLayerHeader();
|
||||
header.magic = data.getInt();
|
||||
header.version = data.getInt();
|
||||
header.magic = data.GetInt();
|
||||
header.version = data.GetInt();
|
||||
|
||||
if (header.magic != TileCacheLayerHeader.DT_TILECACHE_MAGIC)
|
||||
throw new IOException("Invalid magic");
|
||||
if (header.version != TileCacheLayerHeader.DT_TILECACHE_VERSION)
|
||||
throw new IOException("Invalid version");
|
||||
|
||||
header.tx = data.getInt();
|
||||
header.ty = data.getInt();
|
||||
header.tlayer = data.getInt();
|
||||
header.tx = data.GetInt();
|
||||
header.ty = data.GetInt();
|
||||
header.tlayer = data.GetInt();
|
||||
|
||||
header.bmin.x = data.getFloat();
|
||||
header.bmin.y = data.getFloat();
|
||||
header.bmin.z = data.getFloat();
|
||||
header.bmax.x = data.getFloat();
|
||||
header.bmax.y = data.getFloat();
|
||||
header.bmax.z = data.getFloat();
|
||||
header.bmin.x = data.GetFloat();
|
||||
header.bmin.y = data.GetFloat();
|
||||
header.bmin.z = data.GetFloat();
|
||||
header.bmax.x = data.GetFloat();
|
||||
header.bmax.y = data.GetFloat();
|
||||
header.bmax.z = data.GetFloat();
|
||||
|
||||
header.hmin = data.getShort() & 0xFFFF;
|
||||
header.hmax = data.getShort() & 0xFFFF;
|
||||
header.width = data.get() & 0xFF;
|
||||
header.height = data.get() & 0xFF;
|
||||
header.minx = data.get() & 0xFF;
|
||||
header.maxx = data.get() & 0xFF;
|
||||
header.miny = data.get() & 0xFF;
|
||||
header.maxy = data.get() & 0xFF;
|
||||
header.hmin = data.GetShort() & 0xFFFF;
|
||||
header.hmax = data.GetShort() & 0xFFFF;
|
||||
header.width = data.Get() & 0xFF;
|
||||
header.height = data.Get() & 0xFF;
|
||||
header.minx = data.Get() & 0xFF;
|
||||
header.maxx = data.Get() & 0xFF;
|
||||
header.miny = data.Get() & 0xFF;
|
||||
header.maxy = data.Get() & 0xFF;
|
||||
if (cCompatibility)
|
||||
{
|
||||
data.getShort(); // C struct padding
|
||||
data.GetShort(); // C struct padding
|
||||
}
|
||||
|
||||
return header;
|
||||
|
|
|
@ -26,32 +26,32 @@ namespace DotRecast.Detour.TileCache.Io
|
|||
{
|
||||
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.version, order);
|
||||
write(stream, header.tx, order);
|
||||
write(stream, header.ty, order);
|
||||
write(stream, header.tlayer, order);
|
||||
Write(stream, header.magic, order);
|
||||
Write(stream, header.version, order);
|
||||
Write(stream, header.tx, order);
|
||||
Write(stream, header.ty, order);
|
||||
Write(stream, header.tlayer, order);
|
||||
|
||||
write(stream, header.bmin.x, order);
|
||||
write(stream, header.bmin.y, order);
|
||||
write(stream, header.bmin.z, order);
|
||||
write(stream, header.bmax.x, order);
|
||||
write(stream, header.bmax.y, order);
|
||||
write(stream, header.bmax.z, order);
|
||||
Write(stream, header.bmin.x, order);
|
||||
Write(stream, header.bmin.y, order);
|
||||
Write(stream, header.bmin.z, order);
|
||||
Write(stream, header.bmax.x, order);
|
||||
Write(stream, header.bmax.y, order);
|
||||
Write(stream, header.bmax.z, order);
|
||||
|
||||
write(stream, (short)header.hmin, order);
|
||||
write(stream, (short)header.hmax, order);
|
||||
write(stream, (byte)header.width);
|
||||
write(stream, (byte)header.height);
|
||||
write(stream, (byte)header.minx);
|
||||
write(stream, (byte)header.maxx);
|
||||
write(stream, (byte)header.miny);
|
||||
write(stream, (byte)header.maxy);
|
||||
Write(stream, (short)header.hmin, order);
|
||||
Write(stream, (short)header.hmax, order);
|
||||
Write(stream, (byte)header.width);
|
||||
Write(stream, (byte)header.height);
|
||||
Write(stream, (byte)header.minx);
|
||||
Write(stream, (byte)header.maxx);
|
||||
Write(stream, (byte)header.miny);
|
||||
Write(stream, (byte)header.maxy);
|
||||
if (cCompatibility)
|
||||
{
|
||||
write(stream, (short)0, order); // C struct padding
|
||||
Write(stream, (short)0, order); // C struct padding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,28 +29,28 @@ namespace DotRecast.Detour.TileCache.Io
|
|||
{
|
||||
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);
|
||||
return read(bb, maxVertPerPoly, meshProcessor);
|
||||
ByteBuffer bb = IOUtils.ToByteBuffer(@is);
|
||||
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();
|
||||
header.magic = bb.getInt();
|
||||
header.magic = bb.GetInt();
|
||||
if (header.magic != TileCacheSetHeader.TILECACHESET_MAGIC)
|
||||
{
|
||||
header.magic = IOUtils.swapEndianness(header.magic);
|
||||
header.magic = IOUtils.SwapEndianness(header.magic);
|
||||
if (header.magic != TileCacheSetHeader.TILECACHESET_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_RECAST4J)
|
||||
|
@ -60,52 +60,52 @@ namespace DotRecast.Detour.TileCache.Io
|
|||
}
|
||||
|
||||
bool cCompatibility = header.version == TileCacheSetHeader.TILECACHESET_VERSION;
|
||||
header.numTiles = bb.getInt();
|
||||
header.meshParams = paramReader.read(bb);
|
||||
header.cacheParams = readCacheParams(bb, cCompatibility);
|
||||
header.numTiles = bb.GetInt();
|
||||
header.meshParams = paramReader.Read(bb);
|
||||
header.cacheParams = ReadCacheParams(bb, cCompatibility);
|
||||
NavMesh mesh = new NavMesh(header.meshParams, maxVertPerPoly);
|
||||
TileCacheCompressor compressor = TileCacheCompressorFactory.get(cCompatibility);
|
||||
TileCache tc = new TileCache(header.cacheParams, new TileCacheStorageParams(bb.order(), cCompatibility), mesh,
|
||||
TileCacheCompressor compressor = TileCacheCompressorFactory.Get(cCompatibility);
|
||||
TileCache tc = new TileCache(header.cacheParams, new TileCacheStorageParams(bb.Order(), cCompatibility), mesh,
|
||||
compressor, meshProcessor);
|
||||
// Read tiles.
|
||||
for (int i = 0; i < header.numTiles; ++i)
|
||||
{
|
||||
long tileRef = bb.getInt();
|
||||
int dataSize = bb.getInt();
|
||||
long tileRef = bb.GetInt();
|
||||
int dataSize = bb.GetInt();
|
||||
if (tileRef == 0 || dataSize == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] data = bb.ReadBytes(dataSize).ToArray();
|
||||
long tile = tc.addTile(data, 0);
|
||||
long tile = tc.AddTile(data, 0);
|
||||
if (tile != 0)
|
||||
{
|
||||
tc.buildNavMeshTile(tile);
|
||||
tc.BuildNavMeshTile(tile);
|
||||
}
|
||||
}
|
||||
|
||||
return tc;
|
||||
}
|
||||
|
||||
private TileCacheParams readCacheParams(ByteBuffer bb, bool cCompatibility)
|
||||
private TileCacheParams ReadCacheParams(ByteBuffer bb, bool cCompatibility)
|
||||
{
|
||||
TileCacheParams option = new TileCacheParams();
|
||||
|
||||
option.orig.x = bb.getFloat();
|
||||
option.orig.y = bb.getFloat();
|
||||
option.orig.z = bb.getFloat();
|
||||
option.orig.x = bb.GetFloat();
|
||||
option.orig.y = bb.GetFloat();
|
||||
option.orig.z = bb.GetFloat();
|
||||
|
||||
option.cs = bb.getFloat();
|
||||
option.ch = bb.getFloat();
|
||||
option.width = bb.getInt();
|
||||
option.height = bb.getInt();
|
||||
option.walkableHeight = bb.getFloat();
|
||||
option.walkableRadius = bb.getFloat();
|
||||
option.walkableClimb = bb.getFloat();
|
||||
option.maxSimplificationError = bb.getFloat();
|
||||
option.maxTiles = bb.getInt();
|
||||
option.maxObstacles = bb.getInt();
|
||||
option.cs = bb.GetFloat();
|
||||
option.ch = bb.GetFloat();
|
||||
option.width = bb.GetInt();
|
||||
option.height = bb.GetInt();
|
||||
option.walkableHeight = bb.GetFloat();
|
||||
option.walkableRadius = bb.GetFloat();
|
||||
option.walkableClimb = bb.GetFloat();
|
||||
option.maxSimplificationError = bb.GetFloat();
|
||||
option.maxTiles = bb.GetInt();
|
||||
option.maxObstacles = bb.GetInt();
|
||||
return option;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,54 +29,54 @@ namespace DotRecast.Detour.TileCache.Io
|
|||
private readonly NavMeshParamWriter paramWriter = new NavMeshParamWriter();
|
||||
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, cCompatibility
|
||||
Write(stream, TileCacheSetHeader.TILECACHESET_MAGIC, order);
|
||||
Write(stream, cCompatibility
|
||||
? TileCacheSetHeader.TILECACHESET_VERSION
|
||||
: TileCacheSetHeader.TILECACHESET_VERSION_RECAST4J, order);
|
||||
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)
|
||||
continue;
|
||||
numTiles++;
|
||||
}
|
||||
|
||||
write(stream, numTiles, order);
|
||||
paramWriter.write(stream, cache.getNavMesh().getParams(), order);
|
||||
writeCacheParams(stream, cache.getParams(), order);
|
||||
for (int i = 0; i < cache.getTileCount(); i++)
|
||||
Write(stream, numTiles, order);
|
||||
paramWriter.Write(stream, cache.GetNavMesh().GetParams(), order);
|
||||
WriteCacheParams(stream, cache.GetParams(), order);
|
||||
for (int i = 0; i < cache.GetTileCount(); i++)
|
||||
{
|
||||
CompressedTile tile = cache.getTile(i);
|
||||
CompressedTile tile = cache.GetTile(i);
|
||||
if (tile == null || tile.data == null)
|
||||
continue;
|
||||
write(stream, (int)cache.getTileRef(tile), order);
|
||||
Write(stream, (int)cache.GetTileRef(tile), order);
|
||||
byte[] data = tile.data;
|
||||
TileCacheLayer layer = cache.decompressTile(tile);
|
||||
data = builder.compressTileCacheLayer(layer, order, cCompatibility);
|
||||
write(stream, data.Length, order);
|
||||
TileCacheLayer layer = cache.DecompressTile(tile);
|
||||
data = builder.CompressTileCacheLayer(layer, order, cCompatibility);
|
||||
Write(stream, data.Length, order);
|
||||
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.y, order);
|
||||
write(stream, option.orig.z, order);
|
||||
Write(stream, option.orig.x, order);
|
||||
Write(stream, option.orig.y, order);
|
||||
Write(stream, option.orig.z, order);
|
||||
|
||||
write(stream, option.cs, order);
|
||||
write(stream, option.ch, order);
|
||||
write(stream, option.width, order);
|
||||
write(stream, option.height, order);
|
||||
write(stream, option.walkableHeight, order);
|
||||
write(stream, option.walkableRadius, order);
|
||||
write(stream, option.walkableClimb, order);
|
||||
write(stream, option.maxSimplificationError, order);
|
||||
write(stream, option.maxTiles, order);
|
||||
write(stream, option.maxObstacles, order);
|
||||
Write(stream, option.cs, order);
|
||||
Write(stream, option.ch, order);
|
||||
Write(stream, option.width, order);
|
||||
Write(stream, option.height, order);
|
||||
Write(stream, option.walkableHeight, order);
|
||||
Write(stream, option.walkableRadius, order);
|
||||
Write(stream, option.walkableClimb, order);
|
||||
Write(stream, option.maxSimplificationError, order);
|
||||
Write(stream, option.maxTiles, order);
|
||||
Write(stream, option.maxObstacles, order);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -66,46 +66,46 @@ namespace DotRecast.Detour.TileCache
|
|||
private readonly TileCacheBuilder builder = new TileCacheBuilder();
|
||||
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);
|
||||
}
|
||||
|
||||
/// Encodes a tile id.
|
||||
private long encodeTileId(int salt, int it)
|
||||
private long EncodeTileId(int salt, int it)
|
||||
{
|
||||
return ((long)salt << m_tileBits) | it;
|
||||
}
|
||||
|
||||
/// Decodes a tile salt.
|
||||
private int decodeTileIdSalt(long refs)
|
||||
private int DecodeTileIdSalt(long refs)
|
||||
{
|
||||
long saltMask = (1L << m_saltBits) - 1;
|
||||
return (int)((refs >> m_tileBits) & saltMask);
|
||||
}
|
||||
|
||||
/// Decodes a tile id.
|
||||
private int decodeTileIdTile(long refs)
|
||||
private int DecodeTileIdTile(long refs)
|
||||
{
|
||||
long tileMask = (1L << m_tileBits) - 1;
|
||||
return (int)(refs & tileMask);
|
||||
}
|
||||
|
||||
/// Encodes an obstacle id.
|
||||
private long encodeObstacleId(int salt, int it)
|
||||
private long EncodeObstacleId(int salt, int it)
|
||||
{
|
||||
return ((long)salt << 16) | it;
|
||||
}
|
||||
|
||||
/// Decodes an obstacle salt.
|
||||
private int decodeObstacleIdSalt(long refs)
|
||||
private int DecodeObstacleIdSalt(long refs)
|
||||
{
|
||||
long saltMask = ((long)1 << 16) - 1;
|
||||
return (int)((refs >> 16) & saltMask);
|
||||
}
|
||||
|
||||
/// Decodes an obstacle id.
|
||||
private int decodeObstacleIdObstacle(long refs)
|
||||
private int DecodeObstacleIdObstacle(long refs)
|
||||
{
|
||||
long tileMask = ((long)1 << 16) - 1;
|
||||
return (int)(refs & tileMask);
|
||||
|
@ -120,7 +120,7 @@ namespace DotRecast.Detour.TileCache
|
|||
m_tcomp = tcomp;
|
||||
m_tmproc = tmprocs;
|
||||
|
||||
m_tileLutSize = nextPow2(m_params.maxTiles / 4);
|
||||
m_tileLutSize = NextPow2(m_params.maxTiles / 4);
|
||||
if (m_tileLutSize == 0)
|
||||
{
|
||||
m_tileLutSize = 1;
|
||||
|
@ -136,7 +136,7 @@ namespace DotRecast.Detour.TileCache
|
|||
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);
|
||||
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)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int tileIndex = decodeTileIdTile(refs);
|
||||
int tileSalt = decodeTileIdSalt(refs);
|
||||
int tileIndex = DecodeTileIdTile(refs);
|
||||
int tileSalt = DecodeTileIdSalt(refs);
|
||||
if (tileIndex >= m_params.maxTiles)
|
||||
{
|
||||
return null;
|
||||
|
@ -167,18 +167,18 @@ namespace DotRecast.Detour.TileCache
|
|||
return tile;
|
||||
}
|
||||
|
||||
public List<long> getTilesAt(int tx, int ty)
|
||||
public List<long> GetTilesAt(int tx, int ty)
|
||||
{
|
||||
List<long> tiles = new List<long>();
|
||||
|
||||
// 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];
|
||||
while (tile != null)
|
||||
{
|
||||
if (tile.header != null && tile.header.tx == tx && tile.header.ty == ty)
|
||||
{
|
||||
tiles.Add(getTileRef(tile));
|
||||
tiles.Add(GetTileRef(tile));
|
||||
}
|
||||
|
||||
tile = tile.next;
|
||||
|
@ -187,10 +187,10 @@ namespace DotRecast.Detour.TileCache
|
|||
return tiles;
|
||||
}
|
||||
|
||||
CompressedTile getTileAt(int tx, int ty, int tlayer)
|
||||
CompressedTile GetTileAt(int tx, int ty, int tlayer)
|
||||
{
|
||||
// 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];
|
||||
while (tile != null)
|
||||
{
|
||||
|
@ -205,7 +205,7 @@ namespace DotRecast.Detour.TileCache
|
|||
return null;
|
||||
}
|
||||
|
||||
public long getTileRef(CompressedTile tile)
|
||||
public long GetTileRef(CompressedTile tile)
|
||||
{
|
||||
if (tile == null)
|
||||
{
|
||||
|
@ -213,10 +213,10 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -224,24 +224,24 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int idx = decodeObstacleIdObstacle(refs);
|
||||
int idx = DecodeObstacleIdObstacle(refs);
|
||||
if (idx >= m_obstacles.Count)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
TileCacheObstacle ob = m_obstacles[idx];
|
||||
int salt = decodeObstacleIdSalt(refs);
|
||||
int salt = DecodeObstacleIdSalt(refs);
|
||||
if (ob.salt != salt)
|
||||
{
|
||||
return null;
|
||||
|
@ -250,14 +250,14 @@ namespace DotRecast.Detour.TileCache
|
|||
return ob;
|
||||
}
|
||||
|
||||
public long addTile(byte[] data, int flags)
|
||||
public long AddTile(byte[] data, int flags)
|
||||
{
|
||||
// Make sure the data is in right format.
|
||||
ByteBuffer buf = new ByteBuffer(data);
|
||||
buf.order(m_storageParams.byteOrder);
|
||||
TileCacheLayerHeader header = tileReader.read(buf, m_storageParams.cCompatibility);
|
||||
buf.Order(m_storageParams.byteOrder);
|
||||
TileCacheLayerHeader header = tileReader.Read(buf, m_storageParams.cCompatibility);
|
||||
// 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;
|
||||
}
|
||||
|
@ -278,33 +278,33 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// 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];
|
||||
m_posLookup[h] = tile;
|
||||
|
||||
// Init tile.
|
||||
tile.header = header;
|
||||
tile.data = data;
|
||||
tile.compressed = align4(buf.position());
|
||||
tile.compressed = Align4(buf.Position());
|
||||
tile.flags = flags;
|
||||
|
||||
return getTileRef(tile);
|
||||
return GetTileRef(tile);
|
||||
}
|
||||
|
||||
private int align4(int i)
|
||||
private int Align4(int i)
|
||||
{
|
||||
return (i + 3) & (~3);
|
||||
}
|
||||
|
||||
public void removeTile(long refs)
|
||||
public void RemoveTile(long refs)
|
||||
{
|
||||
if (refs == 0)
|
||||
{
|
||||
throw new Exception("Invalid tile ref");
|
||||
}
|
||||
|
||||
int tileIndex = decodeTileIdTile(refs);
|
||||
int tileSalt = decodeTileIdSalt(refs);
|
||||
int tileIndex = DecodeTileIdTile(refs);
|
||||
int tileSalt = DecodeTileIdSalt(refs);
|
||||
if (tileIndex >= m_params.maxTiles)
|
||||
{
|
||||
throw new Exception("Invalid tile index");
|
||||
|
@ -317,7 +317,7 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// 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 cur = m_posLookup[h];
|
||||
while (cur != null)
|
||||
|
@ -358,34 +358,34 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// 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.pos = pos;
|
||||
ob.radius = radius;
|
||||
ob.height = height;
|
||||
|
||||
return addObstacleRequest(ob).refs;
|
||||
return AddObstacleRequest(ob).refs;
|
||||
}
|
||||
|
||||
// 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.bmin = bmin;
|
||||
ob.bmax = bmax;
|
||||
|
||||
return addObstacleRequest(ob).refs;
|
||||
return AddObstacleRequest(ob).refs;
|
||||
}
|
||||
|
||||
// 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.center = center;
|
||||
ob.extents = extents;
|
||||
|
@ -393,19 +393,19 @@ namespace DotRecast.Detour.TileCache
|
|||
float sinhalf = (float)Math.Sin(-0.5f * yRadians);
|
||||
ob.rotAux[0] = coshalf * sinhalf;
|
||||
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();
|
||||
req.action = ObstacleRequestAction.REQUEST_ADD;
|
||||
req.refs = getObstacleRef(ob);
|
||||
req.refs = GetObstacleRef(ob);
|
||||
m_reqs.Add(req);
|
||||
return req;
|
||||
}
|
||||
|
||||
public void removeObstacle(long refs)
|
||||
public void RemoveObstacle(long refs)
|
||||
{
|
||||
if (refs == 0)
|
||||
{
|
||||
|
@ -418,7 +418,7 @@ namespace DotRecast.Detour.TileCache
|
|||
m_reqs.Add(req);
|
||||
}
|
||||
|
||||
private TileCacheObstacle allocObstacle()
|
||||
private TileCacheObstacle AllocObstacle()
|
||||
{
|
||||
TileCacheObstacle o = m_nextFreeObstacle;
|
||||
if (o == null)
|
||||
|
@ -438,7 +438,7 @@ namespace DotRecast.Detour.TileCache
|
|||
return o;
|
||||
}
|
||||
|
||||
List<long> queryTiles(Vector3f bmin, Vector3f bmax)
|
||||
List<long> QueryTiles(Vector3f bmin, Vector3f bmax)
|
||||
{
|
||||
List<long> results = new List<long>();
|
||||
float tw = m_params.width * m_params.cs;
|
||||
|
@ -451,14 +451,14 @@ namespace DotRecast.Detour.TileCache
|
|||
{
|
||||
for (int tx = tx0; tx <= tx1; ++tx)
|
||||
{
|
||||
List<long> tiles = getTilesAt(tx, ty);
|
||||
List<long> tiles = GetTilesAt(tx, ty);
|
||||
foreach (long i in tiles)
|
||||
{
|
||||
CompressedTile tile = m_tiles[decodeTileIdTile(i)];
|
||||
CompressedTile tile = m_tiles[DecodeTileIdTile(i)];
|
||||
Vector3f tbmin = new Vector3f();
|
||||
Vector3f tbmax = new Vector3f();
|
||||
calcTightTileBounds(tile.header, ref tbmin, ref tbmax);
|
||||
if (overlapBounds(bmin, bmax, tbmin, tbmax))
|
||||
CalcTightTileBounds(tile.header, ref tbmin, ref tbmax);
|
||||
if (OverlapBounds(bmin, bmax, tbmin, tbmax))
|
||||
{
|
||||
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
|
||||
* continue processing obstacle requests and tile rebuilds.
|
||||
*/
|
||||
public bool update()
|
||||
public bool Update()
|
||||
{
|
||||
if (0 == m_update.Count)
|
||||
{
|
||||
// Process requests.
|
||||
foreach (ObstacleRequest req in m_reqs)
|
||||
{
|
||||
int idx = decodeObstacleIdObstacle(req.refs);
|
||||
int idx = DecodeObstacleIdObstacle(req.refs);
|
||||
if (idx >= m_obstacles.Count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TileCacheObstacle ob = m_obstacles[idx];
|
||||
int salt = decodeObstacleIdSalt(req.refs);
|
||||
int salt = DecodeObstacleIdSalt(req.refs);
|
||||
if (ob.salt != salt)
|
||||
{
|
||||
continue;
|
||||
|
@ -501,13 +501,13 @@ namespace DotRecast.Detour.TileCache
|
|||
// Find touched tiles.
|
||||
Vector3f bmin = new Vector3f();
|
||||
Vector3f bmax = new Vector3f();
|
||||
getObstacleBounds(ob, ref bmin, ref bmax);
|
||||
ob.touched = queryTiles(bmin, bmax);
|
||||
GetObstacleBounds(ob, ref bmin, ref bmax);
|
||||
ob.touched = QueryTiles(bmin, bmax);
|
||||
// Add tiles to update list.
|
||||
ob.pending.Clear();
|
||||
foreach (long j in ob.touched)
|
||||
{
|
||||
if (!contains(m_update, j))
|
||||
if (!Contains(m_update, j))
|
||||
{
|
||||
m_update.Add(j);
|
||||
}
|
||||
|
@ -523,7 +523,7 @@ namespace DotRecast.Detour.TileCache
|
|||
ob.pending.Clear();
|
||||
foreach (long j in ob.touched)
|
||||
{
|
||||
if (!contains(m_update, j))
|
||||
if (!Contains(m_update, j))
|
||||
{
|
||||
m_update.Add(j);
|
||||
}
|
||||
|
@ -542,7 +542,7 @@ namespace DotRecast.Detour.TileCache
|
|||
long refs = m_update[0];
|
||||
m_update.RemoveAt(0);
|
||||
// Build mesh
|
||||
buildNavMeshTile(refs);
|
||||
BuildNavMeshTile(refs);
|
||||
|
||||
// Update obstacle states.
|
||||
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;
|
||||
}
|
||||
|
||||
public void buildNavMeshTile(long refs)
|
||||
public void BuildNavMeshTile(long refs)
|
||||
{
|
||||
int idx = decodeTileIdTile(refs);
|
||||
int idx = DecodeTileIdTile(refs);
|
||||
if (idx > m_params.maxTiles)
|
||||
{
|
||||
throw new Exception("Invalid tile index");
|
||||
}
|
||||
|
||||
CompressedTile tile = m_tiles[idx];
|
||||
int salt = decodeTileIdSalt(refs);
|
||||
int salt = DecodeTileIdSalt(refs);
|
||||
if (tile.salt != salt)
|
||||
{
|
||||
throw new Exception("Invalid tile salt");
|
||||
|
@ -601,7 +601,7 @@ namespace DotRecast.Detour.TileCache
|
|||
int walkableClimbVx = (int)(m_params.walkableClimb / m_params.ch);
|
||||
|
||||
// Decompress tile layer data.
|
||||
TileCacheLayer layer = decompressTile(tile);
|
||||
TileCacheLayer layer = DecompressTile(tile);
|
||||
|
||||
// Rasterize obstacles.
|
||||
for (int i = 0; i < m_obstacles.Count; ++i)
|
||||
|
@ -612,32 +612,32 @@ namespace DotRecast.Detour.TileCache
|
|||
continue;
|
||||
}
|
||||
|
||||
if (contains(ob.touched, refs))
|
||||
if (Contains(ob.touched, refs))
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
builder.buildTileCacheRegions(layer, walkableClimbVx);
|
||||
TileCacheContourSet lcset = builder.buildTileCacheContours(layer, walkableClimbVx,
|
||||
builder.BuildTileCacheRegions(layer, walkableClimbVx);
|
||||
TileCacheContourSet lcset = builder.BuildTileCacheContours(layer, walkableClimbVx,
|
||||
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.
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -648,7 +648,7 @@ namespace DotRecast.Detour.TileCache
|
|||
option.polyAreas = polyMesh.areas;
|
||||
option.polyFlags = polyMesh.flags;
|
||||
option.polyCount = polyMesh.npolys;
|
||||
option.nvp = m_navmesh.getMaxVertsPerPoly();
|
||||
option.nvp = m_navmesh.GetMaxVertsPerPoly();
|
||||
option.walkableHeight = m_params.walkableHeight;
|
||||
option.walkableRadius = m_params.walkableRadius;
|
||||
option.walkableClimb = m_params.walkableClimb;
|
||||
|
@ -662,27 +662,27 @@ namespace DotRecast.Detour.TileCache
|
|||
option.bmax = tile.header.bmax;
|
||||
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.
|
||||
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
|
||||
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);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -721,27 +721,27 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
}
|
||||
|
||||
public TileCacheParams getParams()
|
||||
public TileCacheParams GetParams()
|
||||
{
|
||||
return m_params;
|
||||
}
|
||||
|
||||
public TileCacheCompressor getCompressor()
|
||||
public TileCacheCompressor GetCompressor()
|
||||
{
|
||||
return m_tcomp;
|
||||
}
|
||||
|
||||
public int getTileCount()
|
||||
public int GetTileCount()
|
||||
{
|
||||
return m_params.maxTiles;
|
||||
}
|
||||
|
||||
public CompressedTile getTile(int i)
|
||||
public CompressedTile GetTile(int i)
|
||||
{
|
||||
return m_tiles[i];
|
||||
}
|
||||
|
||||
public NavMesh getNavMesh()
|
||||
public NavMesh GetNavMesh()
|
||||
{
|
||||
return m_navmesh;
|
||||
}
|
||||
|
|
|
@ -62,12 +62,12 @@ namespace DotRecast.Detour.TileCache
|
|||
poly = new List<int>();
|
||||
}
|
||||
|
||||
public int npoly()
|
||||
public int Npoly()
|
||||
{
|
||||
return poly.Count;
|
||||
}
|
||||
|
||||
public void clear()
|
||||
public void Clear()
|
||||
{
|
||||
nverts = 0;
|
||||
verts.Clear();
|
||||
|
@ -83,7 +83,7 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
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 h = layer.header.height;
|
||||
|
@ -107,7 +107,7 @@ namespace DotRecast.Detour.TileCache
|
|||
Array.Fill(prevCount, 0, 0, regId);
|
||||
}
|
||||
|
||||
// memset(prevCount,0,sizeof(char)*regId);
|
||||
// Memset(prevCount,0,Sizeof(char)*regId);
|
||||
int sweepId = 0;
|
||||
|
||||
for (int x = 0; x < w; ++x)
|
||||
|
@ -120,7 +120,7 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
// -x
|
||||
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)
|
||||
sid = layer.regs[xidx];
|
||||
|
@ -135,7 +135,7 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
// -y
|
||||
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];
|
||||
if (nr != 0xff)
|
||||
|
@ -221,13 +221,13 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
// Update neighbours
|
||||
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];
|
||||
if (rai != 0xff && rai != ri)
|
||||
{
|
||||
addUniqueLast(regs[ri].neis, rai);
|
||||
addUniqueLast(regs[rai].neis, ri);
|
||||
AddUniqueLast(regs[ri].neis, rai);
|
||||
AddUniqueLast(regs[rai].neis, ri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ namespace DotRecast.Detour.TileCache
|
|||
continue;
|
||||
if (regn.area > mergea)
|
||||
{
|
||||
if (canMerge(reg.regId, regn.regId, regs, nregs))
|
||||
if (CanMerge(reg.regId, regn.regId, regs, nregs))
|
||||
{
|
||||
mergea = regn.area;
|
||||
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;
|
||||
if (n > 0 && a[n - 1] == v)
|
||||
|
@ -299,7 +299,7 @@ namespace DotRecast.Detour.TileCache
|
|||
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])
|
||||
return false;
|
||||
|
@ -308,7 +308,7 @@ namespace DotRecast.Detour.TileCache
|
|||
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;
|
||||
for (int i = 0; i < nregs; ++i)
|
||||
|
@ -326,7 +326,7 @@ namespace DotRecast.Detour.TileCache
|
|||
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.
|
||||
if (cont.nverts > 1)
|
||||
|
@ -360,7 +360,7 @@ namespace DotRecast.Detour.TileCache
|
|||
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 ia = ax + ay * w;
|
||||
|
@ -377,30 +377,30 @@ namespace DotRecast.Detour.TileCache
|
|||
return 0xff;
|
||||
}
|
||||
|
||||
int bx = ax + getDirOffsetX(dir);
|
||||
int by = ay + getDirOffsetY(dir);
|
||||
int bx = ax + GetDirOffsetX(dir);
|
||||
int by = ay + GetDirOffsetY(dir);
|
||||
int ib = bx + by * w;
|
||||
return layer.regs[ib];
|
||||
}
|
||||
|
||||
private int getDirOffsetX(int dir)
|
||||
private int GetDirOffsetX(int dir)
|
||||
{
|
||||
int[] offset = new int[] { -1, 0, 1, 0, };
|
||||
return offset[dir & 0x03];
|
||||
}
|
||||
|
||||
private int getDirOffsetY(int dir)
|
||||
private int GetDirOffsetY(int dir)
|
||||
{
|
||||
int[] offset = new int[] { 0, 1, 0, -1 };
|
||||
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 h = layer.header.height;
|
||||
|
||||
cont.clear();
|
||||
cont.Clear();
|
||||
|
||||
int startX = x;
|
||||
int startY = y;
|
||||
|
@ -409,7 +409,7 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
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])
|
||||
{
|
||||
startDir = ndir;
|
||||
|
@ -425,7 +425,7 @@ namespace DotRecast.Detour.TileCache
|
|||
int iter = 0;
|
||||
while (iter < maxIter)
|
||||
{
|
||||
int rn = getNeighbourReg(layer, x, y, dir);
|
||||
int rn = GetNeighbourReg(layer, x, y, dir);
|
||||
|
||||
int nx = x;
|
||||
int ny = y;
|
||||
|
@ -451,14 +451,14 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move to next.
|
||||
nx = x + getDirOffsetX(dir);
|
||||
ny = y + getDirOffsetY(dir);
|
||||
nx = x + GetDirOffsetX(dir);
|
||||
ny = y + GetDirOffsetY(dir);
|
||||
ndir = (dir + 3) & 0x3; // Rotate CCW
|
||||
}
|
||||
|
||||
|
@ -480,7 +480,7 @@ namespace DotRecast.Detour.TileCache
|
|||
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 pqz = qz - pz;
|
||||
|
@ -501,7 +501,7 @@ namespace DotRecast.Detour.TileCache
|
|||
return dx * dx + dz * dz;
|
||||
}
|
||||
|
||||
private void simplifyContour(TempContour cont, float maxError)
|
||||
private void SimplifyContour(TempContour cont, float maxError)
|
||||
{
|
||||
cont.poly.Clear();
|
||||
|
||||
|
@ -515,7 +515,7 @@ namespace DotRecast.Detour.TileCache
|
|||
cont.poly.Add(i);
|
||||
}
|
||||
|
||||
if (cont.npoly() < 2)
|
||||
if (cont.Npoly() < 2)
|
||||
{
|
||||
// If there is no transitions at all,
|
||||
// create some initial points for the simplification process.
|
||||
|
@ -552,9 +552,9 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
// Add points until all raw points are within
|
||||
// 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 ax = cont.verts[ai * 4];
|
||||
|
@ -588,7 +588,7 @@ namespace DotRecast.Detour.TileCache
|
|||
// Tessellate only outer edges or edges between areas.
|
||||
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)
|
||||
{
|
||||
maxd = d;
|
||||
|
@ -612,14 +612,14 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
// Remap vertices
|
||||
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])
|
||||
start = i;
|
||||
|
||||
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 dst = cont.nverts * 4;
|
||||
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 h = layer.header.height;
|
||||
|
@ -680,7 +680,7 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// 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 h = layer.header.height;
|
||||
|
@ -714,9 +714,9 @@ namespace DotRecast.Detour.TileCache
|
|||
cont.reg = ri;
|
||||
cont.area = layer.areas[idx];
|
||||
|
||||
walkContour(layer, x, y, temp);
|
||||
WalkContour(layer, x, y, temp);
|
||||
|
||||
simplifyContour(temp, maxError);
|
||||
SimplifyContour(temp, maxError);
|
||||
|
||||
// Store contour.
|
||||
cont.nverts = temp.nverts;
|
||||
|
@ -734,7 +734,7 @@ namespace DotRecast.Detour.TileCache
|
|||
// stored at segment
|
||||
// vertex of a
|
||||
// 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);
|
||||
int lh = res.Item1;
|
||||
bool shouldRemove = res.Item2;
|
||||
|
@ -759,7 +759,7 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
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 h2 = 0xd8163841; // here arbitrarily chosen primes
|
||||
|
@ -768,9 +768,9 @@ namespace DotRecast.Detour.TileCache
|
|||
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];
|
||||
while (i != DT_TILECACHE_NULL_IDX)
|
||||
{
|
||||
|
@ -791,7 +791,7 @@ namespace DotRecast.Detour.TileCache
|
|||
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)
|
||||
{
|
||||
// Based on code by Eric Lengyel from:
|
||||
|
@ -932,7 +932,7 @@ namespace DotRecast.Detour.TileCache
|
|||
ezmax = tmp;
|
||||
}
|
||||
|
||||
if (overlapRangeExl(zmin, zmax, ezmin, ezmax))
|
||||
if (OverlapRangeExl(zmin, zmax, ezmin, ezmax))
|
||||
{
|
||||
// Reuse the other polyedge to store dir.
|
||||
e.polyEdge[1] = dir;
|
||||
|
@ -972,7 +972,7 @@ namespace DotRecast.Detour.TileCache
|
|||
exmax = tmp;
|
||||
}
|
||||
|
||||
if (overlapRangeExl(xmin, xmax, exmin, exmax))
|
||||
if (OverlapRangeExl(xmin, xmax, exmin, exmax))
|
||||
{
|
||||
// Reuse the other polyedge to store 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;
|
||||
}
|
||||
|
||||
private int prev(int i, int n)
|
||||
private int Prev(int i, int n)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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])
|
||||
- (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
|
||||
// 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
|
||||
// a point interior to both segments. The properness of the
|
||||
// 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.
|
||||
if (collinear(verts, a, b, c) || collinear(verts, a, b, d) || collinear(verts, c, d, a)
|
||||
|| collinear(verts, c, d, b))
|
||||
if (Collinear(verts, a, b, c) || Collinear(verts, a, b, d) || Collinear(verts, c, d, a)
|
||||
|| Collinear(verts, c, d, b))
|
||||
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
|
||||
// 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;
|
||||
// If ab not vertical, check betweenness on x; else on y.
|
||||
if (verts[a] != verts[b])
|
||||
|
@ -1069,25 +1069,25 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// 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;
|
||||
else if (between(verts, a, b, c) || between(verts, a, b, d) || between(verts, c, d, a)
|
||||
|| between(verts, c, d, b))
|
||||
else if (Between(verts, a, b, c) || Between(verts, a, b, d) || Between(verts, c, d, a)
|
||||
|| Between(verts, c, d, b))
|
||||
return true;
|
||||
else
|
||||
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];
|
||||
}
|
||||
|
||||
// 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*.
|
||||
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 d1 = (indices[j] & 0x7fff) * 4;
|
||||
|
@ -1095,17 +1095,17 @@ namespace DotRecast.Detour.TileCache
|
|||
// For each edge (k,k+1) of P
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
int k1 = next(k, n);
|
||||
int k1 = Next(k, n);
|
||||
// Skip edges incident to i or j
|
||||
if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
|
||||
{
|
||||
int p0 = (indices[k] & 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;
|
||||
|
||||
if (intersect(verts, d0, d1, p0, p1))
|
||||
if (Intersect(verts, d0, d1, p0, p1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1115,29 +1115,29 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
// Returns true iff the diagonal (i,j) is strictly internal to the
|
||||
// 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 pj = (indices[j] & 0x7fff) * 4;
|
||||
int pi1 = (indices[next(i, n)] & 0x7fff) * 4;
|
||||
int pin1 = (indices[prev(i, n)] & 0x7fff) * 4;
|
||||
int pi1 = (indices[Next(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 (leftOn(verts, pin1, pi, pi1))
|
||||
return left(verts, pi, pj, pin1) && left(verts, pj, pi, pi1);
|
||||
if (LeftOn(verts, pin1, pi, pi1))
|
||||
return Left(verts, pi, pj, pin1) && Left(verts, pj, pi, pi1);
|
||||
// Assume (i-1,i,i+1) not collinear.
|
||||
// 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
|
||||
// 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 dst = 0; // tris;
|
||||
|
@ -1145,9 +1145,9 @@ namespace DotRecast.Detour.TileCache
|
|||
// removed.
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
int i1 = next(i, n);
|
||||
int i2 = next(i1, n);
|
||||
if (diagonal(i, i2, n, verts, indices))
|
||||
int i1 = Next(i, n);
|
||||
int i2 = Next(i1, n);
|
||||
if (Diagonal(i, i2, n, verts, indices))
|
||||
indices[i1] |= 0x8000;
|
||||
}
|
||||
|
||||
|
@ -1157,11 +1157,11 @@ namespace DotRecast.Detour.TileCache
|
|||
int mini = -1;
|
||||
for (int mi = 0; mi < n; mi++)
|
||||
{
|
||||
int mi1 = next(mi, n);
|
||||
int mi1 = Next(mi, n);
|
||||
if ((indices[mi1] & 0x8000) != 0)
|
||||
{
|
||||
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 dz = verts[p2 + 2] - verts[p0 + 2];
|
||||
|
@ -1178,15 +1178,15 @@ namespace DotRecast.Detour.TileCache
|
|||
{
|
||||
// Should not happen.
|
||||
/*
|
||||
* printf("mini == -1 ntris=%d n=%d\n", ntris, n); for (int i = 0; i < n; i++) { printf("%d ",
|
||||
* indices[i] & 0x0fffffff); } printf("\n");
|
||||
* Printf("mini == -1 ntris=%d n=%d\n", ntris, n); for (int i = 0; i < n; i++) { Printf("%d ",
|
||||
* indices[i] & 0x0fffffff); } Printf("\n");
|
||||
*/
|
||||
return -ntris;
|
||||
}
|
||||
|
||||
int i = mini;
|
||||
int i1 = next(i, n);
|
||||
int i2 = next(i1, n);
|
||||
int i1 = Next(i, n);
|
||||
int i2 = Next(i1, n);
|
||||
|
||||
tris[dst++] = indices[i] & 0x7fff;
|
||||
tris[dst++] = indices[i1] & 0x7fff;
|
||||
|
@ -1200,14 +1200,14 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
if (i1 >= n)
|
||||
i1 = 0;
|
||||
i = prev(i1, n);
|
||||
i = Prev(i1, n);
|
||||
// Update diagonal flags.
|
||||
if (diagonal(prev(i, n), i1, n, verts, indices))
|
||||
if (Diagonal(Prev(i, n), i1, n, verts, indices))
|
||||
indices[i] |= 0x8000;
|
||||
else
|
||||
indices[i] &= 0x7fff;
|
||||
|
||||
if (diagonal(i, next(i1, n), n, verts, indices))
|
||||
if (Diagonal(i, Next(i1, n), n, verts, indices))
|
||||
indices[i1] |= 0x8000;
|
||||
else
|
||||
indices[i1] &= 0x7fff;
|
||||
|
@ -1222,7 +1222,7 @@ namespace DotRecast.Detour.TileCache
|
|||
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)
|
||||
if (polys[p + i] == DT_TILECACHE_NULL_IDX)
|
||||
|
@ -1230,16 +1230,16 @@ namespace DotRecast.Detour.TileCache
|
|||
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])
|
||||
- (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 nb = countPolyVerts(polys, pb, maxVertsPerPoly);
|
||||
int na = CountPolyVerts(polys, pa, maxVertsPerPoly);
|
||||
int nb = CountPolyVerts(polys, pb, maxVertsPerPoly);
|
||||
|
||||
// If the merged polygon would be too big, do not merge.
|
||||
if (na + nb - 2 > maxVertsPerPoly)
|
||||
|
@ -1290,13 +1290,13 @@ namespace DotRecast.Detour.TileCache
|
|||
va = polys[pa + (ea + na - 1) % na];
|
||||
vb = polys[pa + ea];
|
||||
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 };
|
||||
|
||||
va = polys[pb + (eb + nb - 1) % nb];
|
||||
vb = polys[pb + eb];
|
||||
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 };
|
||||
|
||||
va = polys[pa + ea];
|
||||
|
@ -1308,12 +1308,12 @@ namespace DotRecast.Detour.TileCache
|
|||
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 na = countPolyVerts(polys, pa, maxVertsPerPoly);
|
||||
int nb = countPolyVerts(polys, pb, maxVertsPerPoly);
|
||||
int na = CountPolyVerts(polys, pa, maxVertsPerPoly);
|
||||
int nb = CountPolyVerts(polys, pb, maxVertsPerPoly);
|
||||
|
||||
// Merge polygons.
|
||||
Array.Fill(tmp, DT_TILECACHE_NULL_IDX);
|
||||
|
@ -1327,19 +1327,19 @@ namespace DotRecast.Detour.TileCache
|
|||
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);
|
||||
return arr.Count;
|
||||
}
|
||||
|
||||
private int pushBack(int v, List<int> arr)
|
||||
private int PushBack(int v, List<int> arr)
|
||||
{
|
||||
arr.Add(v);
|
||||
return arr.Count;
|
||||
}
|
||||
|
||||
private bool canRemoveVertex(TileCachePolyMesh mesh, int rem)
|
||||
private bool CanRemoveVertex(TileCachePolyMesh mesh, int rem)
|
||||
{
|
||||
// Count number of polygons to remove.
|
||||
int maxVertsPerPoly = mesh.nvp;
|
||||
|
@ -1347,7 +1347,7 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
int p = i * mesh.nvp * 2;
|
||||
int nv = countPolyVerts(mesh.polys, p, maxVertsPerPoly);
|
||||
int nv = CountPolyVerts(mesh.polys, p, maxVertsPerPoly);
|
||||
int numRemoved = 0;
|
||||
int numVerts = 0;
|
||||
for (int j = 0; j < nv; ++j)
|
||||
|
@ -1380,7 +1380,7 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
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.
|
||||
for (int j = 0, k = nv - 1; j < nv; k = j++)
|
||||
|
@ -1437,7 +1437,7 @@ namespace DotRecast.Detour.TileCache
|
|||
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.
|
||||
int maxVertsPerPoly = mesh.nvp;
|
||||
|
@ -1445,7 +1445,7 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (mesh.polys[p + j] == rem)
|
||||
|
@ -1462,7 +1462,7 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
int p = i * maxVertsPerPoly * 2;
|
||||
int nv = countPolyVerts(mesh.polys, p, maxVertsPerPoly);
|
||||
int nv = CountPolyVerts(mesh.polys, p, maxVertsPerPoly);
|
||||
bool hasRem = false;
|
||||
for (int j = 0; j < nv; ++j)
|
||||
if (mesh.polys[p + j] == rem)
|
||||
|
@ -1505,7 +1505,7 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
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)
|
||||
if (mesh.polys[p + j] > rem)
|
||||
mesh.polys[p + j]--;
|
||||
|
@ -1524,8 +1524,8 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
// Start with one vertex, keep appending connected
|
||||
// segments to the start and end of the hole.
|
||||
nhole = pushBack(edges[0], hole);
|
||||
pushBack(edges[2], harea);
|
||||
nhole = PushBack(edges[0], hole);
|
||||
PushBack(edges[2], harea);
|
||||
|
||||
while (nedges != 0)
|
||||
{
|
||||
|
@ -1540,15 +1540,15 @@ namespace DotRecast.Detour.TileCache
|
|||
if (hole[0] == eb)
|
||||
{
|
||||
// The segment matches the beginning of the hole boundary.
|
||||
nhole = pushFront(ea, hole);
|
||||
pushFront(a, harea);
|
||||
nhole = PushFront(ea, hole);
|
||||
PushFront(a, harea);
|
||||
add = true;
|
||||
}
|
||||
else if (hole[nhole - 1] == ea)
|
||||
{
|
||||
// The segment matches the end of the hole boundary.
|
||||
nhole = pushBack(eb, hole);
|
||||
pushBack(a, harea);
|
||||
nhole = PushBack(eb, hole);
|
||||
PushBack(a, harea);
|
||||
add = true;
|
||||
}
|
||||
|
||||
|
@ -1584,7 +1584,7 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// Triangulate the hole.
|
||||
int ntris = triangulate(nhole, tverts, tpoly, tris);
|
||||
int ntris = Triangulate(nhole, tverts, tpoly, tris);
|
||||
if (ntris < 0)
|
||||
{
|
||||
// TODO: issue warning!
|
||||
|
@ -1628,7 +1628,7 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int k = j + 1; k < npolys; ++k)
|
||||
{
|
||||
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 ea = pm[1];
|
||||
int eb = pm[2];
|
||||
|
@ -1648,7 +1648,7 @@ namespace DotRecast.Detour.TileCache
|
|||
// Found best, merge.
|
||||
int pa = bestPa * 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);
|
||||
pareas[bestPb] = pareas[npolys - 1];
|
||||
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 maxTris = 0;
|
||||
|
@ -1733,7 +1733,7 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int j = 0; j < cont.nverts; ++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)
|
||||
{
|
||||
// TODO: issue warning!
|
||||
|
@ -1744,7 +1744,7 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int j = 0; j < cont.nverts; ++j)
|
||||
{
|
||||
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);
|
||||
mesh.nverts = Math.Max(mesh.nverts, indices[j] + 1);
|
||||
if ((cont.verts[v + 3] & 0x80) != 0)
|
||||
|
@ -1787,7 +1787,7 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int k = j + 1; k < npolys; ++k)
|
||||
{
|
||||
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 ea = pm[1];
|
||||
int eb = pm[2];
|
||||
|
@ -1807,7 +1807,7 @@ namespace DotRecast.Detour.TileCache
|
|||
// Found best, merge.
|
||||
int pa = bestPa * 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);
|
||||
npolys--;
|
||||
}
|
||||
|
@ -1838,12 +1838,12 @@ namespace DotRecast.Detour.TileCache
|
|||
{
|
||||
if (vflags[i] != 0)
|
||||
{
|
||||
if (!canRemoveVertex(mesh, i))
|
||||
if (!CanRemoveVertex(mesh, i))
|
||||
continue;
|
||||
removeVertex(mesh, i, maxTris);
|
||||
RemoveVertex(mesh, i, maxTris);
|
||||
// Remove vertex
|
||||
// Note: mesh.nverts is already decremented inside
|
||||
// removeVertex()!
|
||||
// RemoveVertex()!
|
||||
for (int j = i; j < mesh.nverts; ++j)
|
||||
vflags[j] = vflags[j + 1];
|
||||
--i;
|
||||
|
@ -1851,12 +1851,12 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 bmax = new Vector3f();
|
||||
|
@ -1866,7 +1866,7 @@ namespace DotRecast.Detour.TileCache
|
|||
bmax.x = pos.x + radius;
|
||||
bmax.y = pos.y + height;
|
||||
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 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 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 baos = new BinaryWriter(ms);
|
||||
TileCacheLayerHeaderWriter hw = new TileCacheLayerHeaderWriter();
|
||||
try
|
||||
{
|
||||
hw.write(baos, layer.header, order, cCompatibility);
|
||||
hw.Write(baos, layer.header, order, cCompatibility);
|
||||
int gridSize = layer.header.width * layer.header.height;
|
||||
byte[] buffer = new byte[gridSize * 3];
|
||||
for (int i = 0; i < gridSize; i++)
|
||||
|
@ -1978,7 +1978,7 @@ namespace DotRecast.Detour.TileCache
|
|||
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();
|
||||
}
|
||||
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)
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
|
@ -1995,7 +1995,7 @@ namespace DotRecast.Detour.TileCache
|
|||
TileCacheLayerHeaderWriter hw = new TileCacheLayerHeaderWriter();
|
||||
try
|
||||
{
|
||||
hw.write(baos, header, order, cCompatibility);
|
||||
hw.Write(baos, header, order, cCompatibility);
|
||||
int gridSize = header.width * header.height;
|
||||
byte[] buffer = new byte[gridSize * 3];
|
||||
for (int i = 0; i < gridSize; i++)
|
||||
|
@ -2005,7 +2005,7 @@ namespace DotRecast.Detour.TileCache
|
|||
buffer[gridSize * 2 + i] = (byte)cons[i];
|
||||
}
|
||||
|
||||
baos.Write(TileCacheCompressorFactory.get(cCompatibility).compress(buffer));
|
||||
baos.Write(TileCacheCompressorFactory.Get(cCompatibility).Compress(buffer));
|
||||
return ms.ToArray();
|
||||
}
|
||||
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)
|
||||
{
|
||||
ByteBuffer buf = new ByteBuffer(compressed);
|
||||
buf.order(order);
|
||||
buf.Order(order);
|
||||
TileCacheLayer layer = new TileCacheLayer();
|
||||
try
|
||||
{
|
||||
layer.header = reader.read(buf, cCompatibility);
|
||||
layer.header = reader.Read(buf, cCompatibility);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
@ -2030,7 +2030,7 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
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.areas = new short[gridSize];
|
||||
layer.cons = new short[gridSize];
|
||||
|
@ -2045,7 +2045,7 @@ namespace DotRecast.Detour.TileCache
|
|||
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)
|
||||
{
|
||||
int w = layer.header.width;
|
||||
|
|
|
@ -22,8 +22,8 @@ namespace DotRecast.Detour.TileCache
|
|||
{
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -22,6 +22,6 @@ namespace DotRecast.Detour.TileCache
|
|||
{
|
||||
public interface TileCacheMeshProcess
|
||||
{
|
||||
void process(NavMeshDataCreateParams option);
|
||||
void Process(NavMeshDataCreateParams option);
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ namespace DotRecast.Detour.TileCache
|
|||
public float radius, height;
|
||||
public Vector3f center = 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 readonly List<long> pending = new List<long>();
|
||||
public int salt;
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace DotRecast.Detour
|
|||
Overlap,
|
||||
}
|
||||
|
||||
public static float[] intersect(float[] p, float[] q)
|
||||
public static float[] Intersect(float[] p, float[] q)
|
||||
{
|
||||
int n = p.Length / 3;
|
||||
int m = q.Length / 3;
|
||||
|
@ -68,24 +68,24 @@ namespace DotRecast.Detour
|
|||
|
||||
do
|
||||
{
|
||||
vCopy(ref a, p, 3 * (ai % n));
|
||||
vCopy(ref b, q, 3 * (bi % m));
|
||||
vCopy(ref a1, p, 3 * ((ai + n - 1) % n)); // prev a
|
||||
vCopy(ref b1, q, 3 * ((bi + m - 1) % m)); // prev b
|
||||
VCopy(ref a, p, 3 * (ai % n));
|
||||
VCopy(ref b, q, 3 * (bi % m));
|
||||
VCopy(ref a1, p, 3 * ((ai + n - 1) % n)); // prev a
|
||||
VCopy(ref b1, q, 3 * ((bi + m - 1) % m)); // prev b
|
||||
|
||||
Vector3f A = vSub(a, a1);
|
||||
Vector3f B = vSub(b, b1);
|
||||
Vector3f A = VSub(a, a1);
|
||||
Vector3f B = VSub(b, b1);
|
||||
|
||||
float cross = B.x * A.z - A.x * B.z; // triArea2D({0, 0}, A, B);
|
||||
float aHB = triArea2D(b1, b, a);
|
||||
float bHA = triArea2D(a1, a, b);
|
||||
float cross = B.x * A.z - A.x * B.z; // TriArea2D({0, 0}, A, B);
|
||||
float aHB = TriArea2D(b1, b, a);
|
||||
float bHA = TriArea2D(a1, a, b);
|
||||
if (Math.Abs(cross) < EPSILON)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -95,17 +95,17 @@ namespace DotRecast.Detour
|
|||
aa = ba = 0;
|
||||
}
|
||||
|
||||
ii = addVertex(inters, ii, ip);
|
||||
f = inOut(f, aHB, bHA);
|
||||
ii = AddVertex(inters, ii, ip);
|
||||
f = InOut(f, aHB, bHA);
|
||||
}
|
||||
|
||||
/*-----Advance rules-----*/
|
||||
|
||||
/* 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, iq);
|
||||
ii = AddVertex(inters, ii, ip);
|
||||
ii = AddVertex(inters, ii, iq);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,7 @@ namespace DotRecast.Detour
|
|||
{
|
||||
if (f == InFlag.Pin)
|
||||
{
|
||||
ii = addVertex(inters, ii, a);
|
||||
ii = AddVertex(inters, ii, a);
|
||||
}
|
||||
|
||||
aa++;
|
||||
|
@ -146,7 +146,7 @@ namespace DotRecast.Detour
|
|||
{
|
||||
if (f == InFlag.Qin)
|
||||
{
|
||||
ii = addVertex(inters, ii, b);
|
||||
ii = AddVertex(inters, ii, b);
|
||||
}
|
||||
|
||||
ba++;
|
||||
|
@ -159,7 +159,7 @@ namespace DotRecast.Detour
|
|||
{
|
||||
if (f == InFlag.Qin)
|
||||
{
|
||||
ii = addVertex(inters, ii, b);
|
||||
ii = AddVertex(inters, ii, b);
|
||||
}
|
||||
|
||||
ba++;
|
||||
|
@ -169,7 +169,7 @@ namespace DotRecast.Detour
|
|||
{
|
||||
if (f == InFlag.Pin)
|
||||
{
|
||||
ii = addVertex(inters, ii, a);
|
||||
ii = AddVertex(inters, ii, a);
|
||||
}
|
||||
|
||||
aa++;
|
||||
|
@ -190,7 +190,7 @@ namespace DotRecast.Detour
|
|||
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)
|
||||
{
|
||||
|
@ -211,7 +211,7 @@ namespace DotRecast.Detour
|
|||
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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -247,9 +247,9 @@ namespace DotRecast.Detour
|
|||
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)
|
||||
{
|
||||
float s = isec.Item1;
|
||||
|
@ -266,44 +266,44 @@ namespace DotRecast.Detour
|
|||
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;
|
||||
q = d;
|
||||
return Intersection.Overlap;
|
||||
}
|
||||
|
||||
if (between(c, d, a) && between(c, d, b))
|
||||
if (Between(c, d, a) && Between(c, d, b))
|
||||
{
|
||||
p = a;
|
||||
q = b;
|
||||
return Intersection.Overlap;
|
||||
}
|
||||
|
||||
if (between(a, b, c) && between(c, d, b))
|
||||
if (Between(a, b, c) && Between(c, d, b))
|
||||
{
|
||||
p = c;
|
||||
q = b;
|
||||
return Intersection.Overlap;
|
||||
}
|
||||
|
||||
if (between(a, b, c) && between(c, d, a))
|
||||
if (Between(a, b, c) && Between(c, d, a))
|
||||
{
|
||||
p = c;
|
||||
q = a;
|
||||
return Intersection.Overlap;
|
||||
}
|
||||
|
||||
if (between(a, b, d) && between(c, d, b))
|
||||
if (Between(a, b, d) && Between(c, d, b))
|
||||
{
|
||||
p = d;
|
||||
q = b;
|
||||
return Intersection.Overlap;
|
||||
}
|
||||
|
||||
if (between(a, b, d) && between(c, d, a))
|
||||
if (Between(a, b, d) && Between(c, d, a))
|
||||
{
|
||||
p = d;
|
||||
q = a;
|
||||
|
@ -313,7 +313,7 @@ namespace DotRecast.Detour
|
|||
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))
|
||||
{
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace DotRecast.Detour
|
|||
*
|
||||
* <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
|
||||
* 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public void setIncludeFlags(int flags)
|
||||
public void SetIncludeFlags(int flags)
|
||||
{
|
||||
m_includeFlags = flags;
|
||||
}
|
||||
|
||||
public int getExcludeFlags()
|
||||
public int GetExcludeFlags()
|
||||
{
|
||||
return m_excludeFlags;
|
||||
}
|
||||
|
||||
public void setExcludeFlags(int flags)
|
||||
public void SetExcludeFlags(int flags)
|
||||
{
|
||||
m_excludeFlags = flags;
|
||||
}
|
||||
|
|
|
@ -35,9 +35,9 @@ namespace DotRecast.Detour
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,9 +22,9 @@ namespace DotRecast.Detour
|
|||
{
|
||||
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)
|
||||
{
|
||||
data.header.x = tileX;
|
||||
|
|
|
@ -23,17 +23,17 @@ namespace DotRecast.Detour
|
|||
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.
|
||||
Result<ClosestPointOnPolyResult> closest = query.closestPointOnPoly(refs, center);
|
||||
bool posOverPoly = closest.result.isPosOverPoly();
|
||||
var closestPtPoly = closest.result.getClosest();
|
||||
Result<ClosestPointOnPolyResult> closest = query.ClosestPointOnPoly(refs, center);
|
||||
bool posOverPoly = closest.result.IsPosOverPoly();
|
||||
var closestPtPoly = closest.result.GetClosest();
|
||||
|
||||
// If a point is directly over a polygon and closer than
|
||||
// climb height, favor that instead of straight line nearest point.
|
||||
float d = 0;
|
||||
Vector3f diff = vSub(center, closestPtPoly);
|
||||
Vector3f diff = VSub(center, closestPtPoly);
|
||||
if (posOverPoly)
|
||||
{
|
||||
d = Math.Abs(diff.y) - tile.data.header.walkableClimb;
|
||||
|
@ -41,7 +41,7 @@ namespace DotRecast.Detour
|
|||
}
|
||||
else
|
||||
{
|
||||
d = vLenSqr(diff);
|
||||
d = VLenSqr(diff);
|
||||
}
|
||||
|
||||
if (d < nearestDistanceSqr)
|
||||
|
@ -53,7 +53,7 @@ namespace DotRecast.Detour
|
|||
}
|
||||
}
|
||||
|
||||
public FindNearestPolyResult result()
|
||||
public FindNearestPolyResult Result()
|
||||
{
|
||||
return new FindNearestPolyResult(nearestRef, nearestPt, overPoly);
|
||||
}
|
||||
|
|
|
@ -24,14 +24,14 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
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);
|
||||
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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
write(stream, (int)((ulong)value >> 32), order);
|
||||
write(stream, (int)(value & 0xFFFFFFFF), order);
|
||||
Write(stream, (int)((ulong)value >> 32), order);
|
||||
Write(stream, (int)(value & 0xFFFFFFFF), order);
|
||||
}
|
||||
else
|
||||
{
|
||||
write(stream, (int)(value & 0xFFFFFFFF), order);
|
||||
write(stream, (int)((ulong)value >> 32), order);
|
||||
Write(stream, (int)(value & 0xFFFFFFFF), 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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
protected void write(BinaryWriter stream, MemoryStream data)
|
||||
protected void Write(BinaryWriter stream, MemoryStream data)
|
||||
{
|
||||
data.Position = 0;
|
||||
byte[] buffer = new byte[data.Length];
|
||||
|
|
|
@ -24,9 +24,9 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
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)
|
||||
{
|
||||
Array.Reverse(data);
|
||||
|
@ -35,7 +35,7 @@ namespace DotRecast.Detour.Io
|
|||
return new ByteBuffer(data);
|
||||
}
|
||||
|
||||
public static byte[] toByteArray(BinaryReader inputStream)
|
||||
public static byte[] ToByteArray(BinaryReader inputStream)
|
||||
{
|
||||
using var baos = new MemoryStream();
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
return (int)s;
|
||||
|
|
|
@ -25,46 +25,46 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
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);
|
||||
return read(buf, maxVertPerPoly, false);
|
||||
ByteBuffer buf = IOUtils.ToByteBuffer(stream);
|
||||
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);
|
||||
return read(buf, maxVertPerPoly, true);
|
||||
ByteBuffer buf = IOUtils.ToByteBuffer(stream);
|
||||
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();
|
||||
MeshHeader header = new MeshHeader();
|
||||
data.header = header;
|
||||
header.magic = buf.getInt();
|
||||
header.magic = buf.GetInt();
|
||||
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)
|
||||
{
|
||||
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_RECAST4J_FIRST
|
||||
|
@ -75,67 +75,67 @@ namespace DotRecast.Detour.Io
|
|||
}
|
||||
|
||||
bool cCompatibility = header.version == MeshHeader.DT_NAVMESH_VERSION;
|
||||
header.x = buf.getInt();
|
||||
header.y = buf.getInt();
|
||||
header.layer = buf.getInt();
|
||||
header.userId = buf.getInt();
|
||||
header.polyCount = buf.getInt();
|
||||
header.vertCount = buf.getInt();
|
||||
header.maxLinkCount = buf.getInt();
|
||||
header.detailMeshCount = buf.getInt();
|
||||
header.detailVertCount = buf.getInt();
|
||||
header.detailTriCount = buf.getInt();
|
||||
header.bvNodeCount = buf.getInt();
|
||||
header.offMeshConCount = buf.getInt();
|
||||
header.offMeshBase = buf.getInt();
|
||||
header.walkableHeight = buf.getFloat();
|
||||
header.walkableRadius = buf.getFloat();
|
||||
header.walkableClimb = buf.getFloat();
|
||||
header.x = buf.GetInt();
|
||||
header.y = buf.GetInt();
|
||||
header.layer = buf.GetInt();
|
||||
header.userId = buf.GetInt();
|
||||
header.polyCount = buf.GetInt();
|
||||
header.vertCount = buf.GetInt();
|
||||
header.maxLinkCount = buf.GetInt();
|
||||
header.detailMeshCount = buf.GetInt();
|
||||
header.detailVertCount = buf.GetInt();
|
||||
header.detailTriCount = buf.GetInt();
|
||||
header.bvNodeCount = buf.GetInt();
|
||||
header.offMeshConCount = buf.GetInt();
|
||||
header.offMeshBase = buf.GetInt();
|
||||
header.walkableHeight = buf.GetFloat();
|
||||
header.walkableRadius = buf.GetFloat();
|
||||
header.walkableClimb = buf.GetFloat();
|
||||
|
||||
header.bmin.x = buf.getFloat();
|
||||
header.bmin.y = buf.getFloat();
|
||||
header.bmin.z = buf.getFloat();
|
||||
header.bmin.x = buf.GetFloat();
|
||||
header.bmin.y = buf.GetFloat();
|
||||
header.bmin.z = buf.GetFloat();
|
||||
|
||||
header.bmax.x = buf.getFloat();
|
||||
header.bmax.y = buf.getFloat();
|
||||
header.bmax.z = buf.getFloat();
|
||||
header.bmax.x = buf.GetFloat();
|
||||
header.bmax.y = buf.GetFloat();
|
||||
header.bmax.z = buf.GetFloat();
|
||||
|
||||
header.bvQuantFactor = buf.getFloat();
|
||||
data.verts = readVerts(buf, header.vertCount);
|
||||
data.polys = readPolys(buf, header, maxVertPerPoly);
|
||||
header.bvQuantFactor = buf.GetFloat();
|
||||
data.verts = ReadVerts(buf, header.vertCount);
|
||||
data.polys = ReadPolys(buf, header, maxVertPerPoly);
|
||||
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.detailVerts = readVerts(buf, header.detailVertCount);
|
||||
data.detailTris = readDTris(buf, header);
|
||||
data.bvTree = readBVTree(buf, header);
|
||||
data.offMeshCons = readOffMeshCons(buf, header);
|
||||
data.detailMeshes = ReadPolyDetails(buf, header, cCompatibility);
|
||||
data.detailVerts = ReadVerts(buf, header.detailVertCount);
|
||||
data.detailTris = ReadDTris(buf, header);
|
||||
data.bvTree = ReadBVTree(buf, header);
|
||||
data.offMeshCons = ReadOffMeshCons(buf, header);
|
||||
return data;
|
||||
}
|
||||
|
||||
public const int LINK_SIZEOF = 16;
|
||||
public const int LINK_SIZEOF32BIT = 12;
|
||||
|
||||
public static int getSizeofLink(bool is32Bit)
|
||||
public static int GetSizeofLink(bool is32Bit)
|
||||
{
|
||||
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];
|
||||
for (int i = 0; i < verts.Length; i++)
|
||||
{
|
||||
verts[i] = buf.getFloat();
|
||||
verts[i] = buf.GetFloat();
|
||||
}
|
||||
|
||||
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];
|
||||
for (int i = 0; i < polys.Length; i++)
|
||||
|
@ -143,58 +143,58 @@ namespace DotRecast.Detour.Io
|
|||
polys[i] = new Poly(i, maxVertPerPoly);
|
||||
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++)
|
||||
{
|
||||
polys[i].verts[j] = buf.getShort() & 0xFFFF;
|
||||
polys[i].verts[j] = buf.GetShort() & 0xFFFF;
|
||||
}
|
||||
|
||||
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].vertCount = buf.get() & 0xFF;
|
||||
polys[i].areaAndtype = buf.get() & 0xFF;
|
||||
polys[i].flags = buf.GetShort() & 0xFFFF;
|
||||
polys[i].vertCount = buf.Get() & 0xFF;
|
||||
polys[i].areaAndtype = buf.Get() & 0xFF;
|
||||
}
|
||||
|
||||
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];
|
||||
for (int i = 0; i < polys.Length; i++)
|
||||
{
|
||||
polys[i] = new PolyDetail();
|
||||
polys[i].vertBase = buf.getInt();
|
||||
polys[i].triBase = buf.getInt();
|
||||
polys[i].vertCount = buf.get() & 0xFF;
|
||||
polys[i].triCount = buf.get() & 0xFF;
|
||||
polys[i].vertBase = buf.GetInt();
|
||||
polys[i].triBase = buf.GetInt();
|
||||
polys[i].vertCount = buf.Get() & 0xFF;
|
||||
polys[i].triCount = buf.Get() & 0xFF;
|
||||
if (cCompatibility)
|
||||
{
|
||||
buf.getShort(); // C struct padding
|
||||
buf.GetShort(); // C struct padding
|
||||
}
|
||||
}
|
||||
|
||||
return polys;
|
||||
}
|
||||
|
||||
private int[] readDTris(ByteBuffer buf, MeshHeader header)
|
||||
private int[] ReadDTris(ByteBuffer buf, MeshHeader header)
|
||||
{
|
||||
int[] tris = new int[4 * header.detailTriCount];
|
||||
for (int i = 0; i < tris.Length; i++)
|
||||
{
|
||||
tris[i] = buf.get() & 0xFF;
|
||||
tris[i] = buf.Get() & 0xFF;
|
||||
}
|
||||
|
||||
return tris;
|
||||
}
|
||||
|
||||
private BVNode[] readBVTree(ByteBuffer buf, MeshHeader header)
|
||||
private BVNode[] ReadBVTree(ByteBuffer buf, MeshHeader header)
|
||||
{
|
||||
BVNode[] nodes = new BVNode[header.bvNodeCount];
|
||||
for (int i = 0; i < nodes.Length; i++)
|
||||
|
@ -204,34 +204,34 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
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++)
|
||||
{
|
||||
nodes[i].bmax[j] = buf.getShort() & 0xFFFF;
|
||||
nodes[i].bmax[j] = buf.GetShort() & 0xFFFF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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++)
|
||||
{
|
||||
nodes[i].bmax[j] = buf.getInt();
|
||||
nodes[i].bmax[j] = buf.GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
nodes[i].i = buf.getInt();
|
||||
nodes[i].i = buf.GetInt();
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
private OffMeshConnection[] readOffMeshCons(ByteBuffer buf, MeshHeader header)
|
||||
private OffMeshConnection[] ReadOffMeshCons(ByteBuffer buf, MeshHeader header)
|
||||
{
|
||||
OffMeshConnection[] cons = new OffMeshConnection[header.offMeshConCount];
|
||||
for (int i = 0; i < cons.Length; i++)
|
||||
|
@ -239,14 +239,14 @@ namespace DotRecast.Detour.Io
|
|||
cons[i] = new OffMeshConnection();
|
||||
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].poly = buf.getShort() & 0xFFFF;
|
||||
cons[i].flags = buf.get() & 0xFF;
|
||||
cons[i].side = buf.get() & 0xFF;
|
||||
cons[i].userId = buf.getInt();
|
||||
cons[i].rad = buf.GetFloat();
|
||||
cons[i].poly = buf.GetShort() & 0xFFFF;
|
||||
cons[i].flags = buf.Get() & 0xFF;
|
||||
cons[i].side = buf.Get() & 0xFF;
|
||||
cons[i].userId = buf.GetInt();
|
||||
}
|
||||
|
||||
return cons;
|
||||
|
|
|
@ -23,106 +23,106 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
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;
|
||||
write(stream, header.magic, order);
|
||||
write(stream, cCompatibility ? MeshHeader.DT_NAVMESH_VERSION : MeshHeader.DT_NAVMESH_VERSION_RECAST4J_LAST, order);
|
||||
write(stream, header.x, order);
|
||||
write(stream, header.y, order);
|
||||
write(stream, header.layer, order);
|
||||
write(stream, header.userId, order);
|
||||
write(stream, header.polyCount, order);
|
||||
write(stream, header.vertCount, order);
|
||||
write(stream, header.maxLinkCount, order);
|
||||
write(stream, header.detailMeshCount, order);
|
||||
write(stream, header.detailVertCount, order);
|
||||
write(stream, header.detailTriCount, order);
|
||||
write(stream, header.bvNodeCount, order);
|
||||
write(stream, header.offMeshConCount, order);
|
||||
write(stream, header.offMeshBase, order);
|
||||
write(stream, header.walkableHeight, order);
|
||||
write(stream, header.walkableRadius, order);
|
||||
write(stream, header.walkableClimb, order);
|
||||
write(stream, header.bmin.x, order);
|
||||
write(stream, header.bmin.y, order);
|
||||
write(stream, header.bmin.z, order);
|
||||
write(stream, header.bmax.x, order);
|
||||
write(stream, header.bmax.y, order);
|
||||
write(stream, header.bmax.z, order);
|
||||
write(stream, header.bvQuantFactor, order);
|
||||
writeVerts(stream, data.verts, header.vertCount, order);
|
||||
writePolys(stream, data, order, cCompatibility);
|
||||
Write(stream, header.magic, order);
|
||||
Write(stream, cCompatibility ? MeshHeader.DT_NAVMESH_VERSION : MeshHeader.DT_NAVMESH_VERSION_RECAST4J_LAST, order);
|
||||
Write(stream, header.x, order);
|
||||
Write(stream, header.y, order);
|
||||
Write(stream, header.layer, order);
|
||||
Write(stream, header.userId, order);
|
||||
Write(stream, header.polyCount, order);
|
||||
Write(stream, header.vertCount, order);
|
||||
Write(stream, header.maxLinkCount, order);
|
||||
Write(stream, header.detailMeshCount, order);
|
||||
Write(stream, header.detailVertCount, order);
|
||||
Write(stream, header.detailTriCount, order);
|
||||
Write(stream, header.bvNodeCount, order);
|
||||
Write(stream, header.offMeshConCount, order);
|
||||
Write(stream, header.offMeshBase, order);
|
||||
Write(stream, header.walkableHeight, order);
|
||||
Write(stream, header.walkableRadius, order);
|
||||
Write(stream, header.walkableClimb, order);
|
||||
Write(stream, header.bmin.x, order);
|
||||
Write(stream, header.bmin.y, order);
|
||||
Write(stream, header.bmin.z, order);
|
||||
Write(stream, header.bmax.x, order);
|
||||
Write(stream, header.bmax.y, order);
|
||||
Write(stream, header.bmax.z, order);
|
||||
Write(stream, header.bvQuantFactor, order);
|
||||
WriteVerts(stream, data.verts, header.vertCount, order);
|
||||
WritePolys(stream, data, order, cCompatibility);
|
||||
if (cCompatibility)
|
||||
{
|
||||
byte[] linkPlaceholder = new byte[header.maxLinkCount * MeshDataReader.getSizeofLink(false)];
|
||||
byte[] linkPlaceholder = new byte[header.maxLinkCount * MeshDataReader.GetSizeofLink(false)];
|
||||
stream.Write(linkPlaceholder);
|
||||
}
|
||||
|
||||
writePolyDetails(stream, data, order, cCompatibility);
|
||||
writeVerts(stream, data.detailVerts, header.detailVertCount, order);
|
||||
writeDTris(stream, data);
|
||||
writeBVTree(stream, data, order, cCompatibility);
|
||||
writeOffMeshCons(stream, data, order);
|
||||
WritePolyDetails(stream, data, order, cCompatibility);
|
||||
WriteVerts(stream, data.detailVerts, header.detailVertCount, order);
|
||||
WriteDTris(stream, data);
|
||||
WriteBVTree(stream, data, order, cCompatibility);
|
||||
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++)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
if (cCompatibility)
|
||||
{
|
||||
write(stream, 0xFFFF, order);
|
||||
Write(stream, 0xFFFF, order);
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
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, (byte)data.polys[i].vertCount);
|
||||
write(stream, (byte)data.polys[i].areaAndtype);
|
||||
Write(stream, (short)data.polys[i].flags, order);
|
||||
Write(stream, (byte)data.polys[i].vertCount);
|
||||
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++)
|
||||
{
|
||||
write(stream, data.detailMeshes[i].vertBase, order);
|
||||
write(stream, data.detailMeshes[i].triBase, order);
|
||||
write(stream, (byte)data.detailMeshes[i].vertCount);
|
||||
write(stream, (byte)data.detailMeshes[i].triCount);
|
||||
Write(stream, data.detailMeshes[i].vertBase, order);
|
||||
Write(stream, data.detailMeshes[i].triBase, order);
|
||||
Write(stream, (byte)data.detailMeshes[i].vertCount);
|
||||
Write(stream, (byte)data.detailMeshes[i].triCount);
|
||||
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++)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
|
@ -130,45 +130,45 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
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++)
|
||||
{
|
||||
write(stream, (short)data.bvTree[i].bmax[j], order);
|
||||
Write(stream, (short)data.bvTree[i].bmax[j], order);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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++)
|
||||
{
|
||||
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 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, (short)data.offMeshCons[i].poly, order);
|
||||
write(stream, (byte)data.offMeshCons[i].flags);
|
||||
write(stream, (byte)data.offMeshCons[i].side);
|
||||
write(stream, data.offMeshCons[i].userId, order);
|
||||
Write(stream, data.offMeshCons[i].rad, order);
|
||||
Write(stream, (short)data.offMeshCons[i].poly, order);
|
||||
Write(stream, (byte)data.offMeshCons[i].flags);
|
||||
Write(stream, (byte)data.offMeshCons[i].side);
|
||||
Write(stream, data.offMeshCons[i].userId, order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,39 +30,39 @@ namespace DotRecast.Detour.Io
|
|||
private readonly MeshDataReader meshReader = new MeshDataReader();
|
||||
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)
|
||||
{
|
||||
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;
|
||||
NavMesh mesh = new NavMesh(header.option, header.maxVertsPerPoly);
|
||||
readTiles(bb, is32Bit, header, cCompatibility, mesh);
|
||||
ReadTiles(bb, is32Bit, header, cCompatibility, mesh);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
private NavMeshSetHeader readHeader(ByteBuffer bb, int maxVertsPerPoly)
|
||||
private NavMeshSetHeader ReadHeader(ByteBuffer bb, int maxVertsPerPoly)
|
||||
{
|
||||
NavMeshSetHeader header = new NavMeshSetHeader();
|
||||
header.magic = bb.getInt();
|
||||
header.magic = bb.GetInt();
|
||||
if (header.magic != NavMeshSetHeader.NAVMESHSET_MAGIC)
|
||||
{
|
||||
header.magic = IOUtils.swapEndianness(header.magic);
|
||||
header.magic = IOUtils.SwapEndianness(header.magic);
|
||||
if (header.magic != NavMeshSetHeader.NAVMESHSET_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
|
||||
&& header.version != NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J)
|
||||
{
|
||||
throw new IOException("Invalid version " + header.version);
|
||||
}
|
||||
|
||||
header.numTiles = bb.getInt();
|
||||
header.option = paramReader.read(bb);
|
||||
header.numTiles = bb.GetInt();
|
||||
header.option = paramReader.Read(bb);
|
||||
header.maxVertsPerPoly = maxVertsPerPoly;
|
||||
if (header.version == NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J)
|
||||
{
|
||||
header.maxVertsPerPoly = bb.getInt();
|
||||
header.maxVertsPerPoly = bb.GetInt();
|
||||
}
|
||||
|
||||
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.
|
||||
for (int i = 0; i < header.numTiles; ++i)
|
||||
|
@ -115,14 +115,14 @@ namespace DotRecast.Detour.Io
|
|||
NavMeshTileHeader tileHeader = new NavMeshTileHeader();
|
||||
if (is32Bit)
|
||||
{
|
||||
tileHeader.tileRef = convert32BitRef(bb.getInt(), header.option);
|
||||
tileHeader.tileRef = Convert32BitRef(bb.GetInt(), header.option);
|
||||
}
|
||||
else
|
||||
{
|
||||
tileHeader.tileRef = bb.getLong();
|
||||
tileHeader.tileRef = bb.GetLong();
|
||||
}
|
||||
|
||||
tileHeader.dataSize = bb.getInt();
|
||||
tileHeader.dataSize = bb.GetInt();
|
||||
if (tileHeader.tileRef == 0 || tileHeader.dataSize == 0)
|
||||
{
|
||||
break;
|
||||
|
@ -130,18 +130,18 @@ namespace DotRecast.Detour.Io
|
|||
|
||||
if (cCompatibility && !is32Bit)
|
||||
{
|
||||
bb.getInt(); // C struct padding
|
||||
bb.GetInt(); // C struct padding
|
||||
}
|
||||
|
||||
MeshData data = meshReader.read(bb, mesh.getMaxVertsPerPoly(), is32Bit);
|
||||
mesh.addTile(data, i, tileHeader.tileRef);
|
||||
MeshData data = meshReader.Read(bb, mesh.GetMaxVertsPerPoly(), is32Bit);
|
||||
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_polyBits = ilog2(nextPow2(option.maxPolys));
|
||||
int m_tileBits = Ilog2(NextPow2(option.maxTiles));
|
||||
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.
|
||||
int m_saltBits = Math.Min(31, 32 - m_tileBits - m_polyBits);
|
||||
int saltMask = (1 << m_saltBits) - 1;
|
||||
|
@ -150,7 +150,7 @@ namespace DotRecast.Detour.Io
|
|||
int salt = ((refs >> (m_polyBits + m_tileBits)) & saltMask);
|
||||
int it = ((refs >> m_polyBits) & tileMask);
|
||||
int ip = refs & polyMask;
|
||||
return NavMesh.encodePolyId(salt, it, ip);
|
||||
return NavMesh.EncodePolyId(salt, it, ip);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,20 +26,20 @@ namespace DotRecast.Detour.Io
|
|||
private readonly MeshDataWriter writer = new MeshDataWriter();
|
||||
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);
|
||||
writeTiles(stream, mesh, order, cCompatibility);
|
||||
WriteHeader(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, cCompatibility ? NavMeshSetHeader.NAVMESHSET_VERSION : NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J, order);
|
||||
Write(stream, NavMeshSetHeader.NAVMESHSET_MAGIC, order);
|
||||
Write(stream, cCompatibility ? NavMeshSetHeader.NAVMESHSET_VERSION : NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J, order);
|
||||
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)
|
||||
{
|
||||
continue;
|
||||
|
@ -48,39 +48,39 @@ namespace DotRecast.Detour.Io
|
|||
numTiles++;
|
||||
}
|
||||
|
||||
write(stream, numTiles, order);
|
||||
paramWriter.write(stream, mesh.getParams(), order);
|
||||
Write(stream, numTiles, order);
|
||||
paramWriter.Write(stream, mesh.GetParams(), order);
|
||||
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)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
NavMeshTileHeader tileHeader = new NavMeshTileHeader();
|
||||
tileHeader.tileRef = mesh.getTileRef(tile);
|
||||
tileHeader.tileRef = mesh.GetTileRef(tile);
|
||||
using MemoryStream bb = new MemoryStream();
|
||||
using BinaryWriter baos = new BinaryWriter(bb);
|
||||
writer.write(baos, tile.data, order, cCompatibility);
|
||||
writer.Write(baos, tile.data, order, cCompatibility);
|
||||
baos.Flush();
|
||||
baos.Close();
|
||||
|
||||
byte[] ba = bb.ToArray();
|
||||
tileHeader.dataSize = ba.Length;
|
||||
write(stream, tileHeader.tileRef, order);
|
||||
write(stream, tileHeader.dataSize, order);
|
||||
Write(stream, tileHeader.tileRef, order);
|
||||
Write(stream, tileHeader.dataSize, order);
|
||||
if (cCompatibility)
|
||||
{
|
||||
write(stream, 0, order); // C struct padding
|
||||
Write(stream, 0, order); // C struct padding
|
||||
}
|
||||
|
||||
stream.Write(ba);
|
||||
|
|
|
@ -4,16 +4,16 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
public class NavMeshParamReader
|
||||
{
|
||||
public NavMeshParams read(ByteBuffer bb)
|
||||
public NavMeshParams Read(ByteBuffer bb)
|
||||
{
|
||||
NavMeshParams option = new NavMeshParams();
|
||||
option.orig.x = bb.getFloat();
|
||||
option.orig.y = bb.getFloat();
|
||||
option.orig.z = bb.getFloat();
|
||||
option.tileWidth = bb.getFloat();
|
||||
option.tileHeight = bb.getFloat();
|
||||
option.maxTiles = bb.getInt();
|
||||
option.maxPolys = bb.getInt();
|
||||
option.orig.x = bb.GetFloat();
|
||||
option.orig.y = bb.GetFloat();
|
||||
option.orig.z = bb.GetFloat();
|
||||
option.tileWidth = bb.GetFloat();
|
||||
option.tileHeight = bb.GetFloat();
|
||||
option.maxTiles = bb.GetInt();
|
||||
option.maxPolys = bb.GetInt();
|
||||
return option;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,15 +5,15 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
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.y, order);
|
||||
write(stream, option.orig.z, order);
|
||||
write(stream, option.tileWidth, order);
|
||||
write(stream, option.tileHeight, order);
|
||||
write(stream, option.maxTiles, order);
|
||||
write(stream, option.maxPolys, order);
|
||||
Write(stream, option.orig.x, order);
|
||||
Write(stream, option.orig.y, order);
|
||||
Write(stream, option.orig.z, order);
|
||||
Write(stream, option.tileWidth, order);
|
||||
Write(stream, option.tileHeight, order);
|
||||
Write(stream, option.maxTiles, order);
|
||||
Write(stream, option.maxPolys, order);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
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
|
||||
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>>();
|
||||
}
|
||||
|
@ -55,27 +55,27 @@ namespace DotRecast.Detour
|
|||
return Results.Success(singlePath);
|
||||
}
|
||||
|
||||
m_nodePool.clear();
|
||||
m_openList.clear();
|
||||
m_nodePool.Clear();
|
||||
m_openList.Clear();
|
||||
|
||||
Node startNode = m_nodePool.getNode(startRef);
|
||||
Node startNode = m_nodePool.GetNode(startRef);
|
||||
startNode.pos = startPos;
|
||||
startNode.pidx = 0;
|
||||
startNode.cost = 0;
|
||||
startNode.total = vDist(startPos, endPos) * H_SCALE;
|
||||
startNode.total = VDist(startPos, endPos) * H_SCALE;
|
||||
startNode.id = startRef;
|
||||
startNode.flags = Node.DT_NODE_OPEN;
|
||||
m_openList.push(startNode);
|
||||
m_openList.Push(startNode);
|
||||
|
||||
Node lastBestNode = startNode;
|
||||
float lastBestNodeCost = startNode.total;
|
||||
|
||||
Status status = Status.SUCCSESS;
|
||||
|
||||
while (!m_openList.isEmpty())
|
||||
while (!m_openList.IsEmpty())
|
||||
{
|
||||
// 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_CLOSED;
|
||||
|
||||
|
@ -89,7 +89,7 @@ namespace DotRecast.Detour
|
|||
// Get current poly and tile.
|
||||
// The API input has been cheked already, skip checking internal data.
|
||||
long bestRef = bestNode.id;
|
||||
Tuple<MeshTile, Poly> tileAndPoly = m_nav.getTileAndPolyByRefUnsafe(bestRef);
|
||||
Tuple<MeshTile, Poly> tileAndPoly = m_nav.GetTileAndPolyByRefUnsafe(bestRef);
|
||||
MeshTile bestTile = tileAndPoly.Item1;
|
||||
Poly bestPoly = tileAndPoly.Item2;
|
||||
|
||||
|
@ -99,12 +99,12 @@ namespace DotRecast.Detour
|
|||
Poly parentPoly = null;
|
||||
if (bestNode.pidx != 0)
|
||||
{
|
||||
parentRef = m_nodePool.getNodeAtIdx(bestNode.pidx).id;
|
||||
parentRef = m_nodePool.GetNodeAtIdx(bestNode.pidx).id;
|
||||
}
|
||||
|
||||
if (parentRef != 0)
|
||||
{
|
||||
tileAndPoly = m_nav.getTileAndPolyByRefUnsafe(parentRef);
|
||||
tileAndPoly = m_nav.GetTileAndPolyByRefUnsafe(parentRef);
|
||||
parentTile = tileAndPoly.Item1;
|
||||
parentPoly = tileAndPoly.Item2;
|
||||
}
|
||||
|
@ -121,11 +121,11 @@ namespace DotRecast.Detour
|
|||
|
||||
// Get neighbour poly and tile.
|
||||
// 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;
|
||||
Poly neighbourPoly = tileAndPoly.Item2;
|
||||
|
||||
if (!filter.passFilter(neighbourRef, neighbourTile, neighbourPoly))
|
||||
if (!filter.PassFilter(neighbourRef, neighbourTile, neighbourPoly))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -138,12 +138,12 @@ namespace DotRecast.Detour
|
|||
}
|
||||
|
||||
// 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 (neighbourNode.flags == 0)
|
||||
{
|
||||
var midpod = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
|
||||
var midpod = GetEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
|
||||
neighbourTile);
|
||||
if (!midpod.Failed())
|
||||
{
|
||||
|
@ -159,9 +159,9 @@ namespace DotRecast.Detour
|
|||
if (neighbourRef == endRef)
|
||||
{
|
||||
// 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);
|
||||
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);
|
||||
|
||||
cost = bestNode.cost + curCost + endCost;
|
||||
|
@ -170,10 +170,10 @@ namespace DotRecast.Detour
|
|||
else
|
||||
{
|
||||
// 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);
|
||||
cost = bestNode.cost + curCost;
|
||||
heuristic = vDist(neighbourNode.pos, endPos) * H_SCALE;
|
||||
heuristic = VDist(neighbourNode.pos, endPos) * H_SCALE;
|
||||
}
|
||||
|
||||
float total = cost + heuristic;
|
||||
|
@ -191,7 +191,7 @@ namespace DotRecast.Detour
|
|||
}
|
||||
|
||||
// Add or update the node.
|
||||
neighbourNode.pidx = m_nodePool.getNodeIdx(bestNode);
|
||||
neighbourNode.pidx = m_nodePool.GetNodeIdx(bestNode);
|
||||
neighbourNode.id = neighbourRef;
|
||||
neighbourNode.flags = (neighbourNode.flags & ~Node.DT_NODE_CLOSED);
|
||||
neighbourNode.cost = cost;
|
||||
|
@ -200,13 +200,13 @@ namespace DotRecast.Detour
|
|||
if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0)
|
||||
{
|
||||
// Already in open, update node location.
|
||||
m_openList.modify(neighbourNode);
|
||||
m_openList.Modify(neighbourNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Put the node in open list.
|
||||
neighbourNode.flags |= Node.DT_NODE_OPEN;
|
||||
m_openList.push(neighbourNode);
|
||||
m_openList.Push(neighbourNode);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -235,27 +235,27 @@ namespace DotRecast.Detour
|
|||
* The maximum number of iterations to perform.
|
||||
* @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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
return Results.Of(m_query.status, 0);
|
||||
}
|
||||
|
||||
int iter = 0;
|
||||
while (iter < maxIter && !m_openList.isEmpty())
|
||||
while (iter < maxIter && !m_openList.IsEmpty())
|
||||
{
|
||||
iter++;
|
||||
|
||||
// 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_CLOSED;
|
||||
|
||||
|
@ -271,7 +271,7 @@ namespace DotRecast.Detour
|
|||
// The API input has been cheked already, skip checking internal
|
||||
// data.
|
||||
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())
|
||||
{
|
||||
m_query.status = Status.FAILURE;
|
||||
|
@ -288,20 +288,20 @@ namespace DotRecast.Detour
|
|||
Node parentNode = null;
|
||||
if (bestNode.pidx != 0)
|
||||
{
|
||||
parentNode = m_nodePool.getNodeAtIdx(bestNode.pidx);
|
||||
parentNode = m_nodePool.GetNodeAtIdx(bestNode.pidx);
|
||||
parentRef = parentNode.id;
|
||||
if (parentNode.pidx != 0)
|
||||
{
|
||||
grandpaRef = m_nodePool.getNodeAtIdx(parentNode.pidx).id;
|
||||
grandpaRef = m_nodePool.GetNodeAtIdx(parentNode.pidx).id;
|
||||
}
|
||||
}
|
||||
|
||||
if (parentRef != 0)
|
||||
{
|
||||
bool invalidParent = false;
|
||||
tileAndPoly = m_nav.getTileAndPolyByRef(parentRef);
|
||||
tileAndPoly = m_nav.GetTileAndPolyByRef(parentRef);
|
||||
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,
|
||||
// fail.
|
||||
|
@ -317,7 +317,7 @@ namespace DotRecast.Detour
|
|||
bool tryLOS = false;
|
||||
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;
|
||||
}
|
||||
|
@ -337,17 +337,17 @@ namespace DotRecast.Detour
|
|||
// Get neighbour poly and tile.
|
||||
// The API input has been cheked already, skip checking internal
|
||||
// data.
|
||||
Tuple<MeshTile, Poly> tileAndPolyUns = m_nav.getTileAndPolyByRefUnsafe(neighbourRef);
|
||||
Tuple<MeshTile, Poly> tileAndPolyUns = m_nav.GetTileAndPolyByRefUnsafe(neighbourRef);
|
||||
MeshTile neighbourTile = tileAndPolyUns.Item1;
|
||||
Poly neighbourPoly = tileAndPolyUns.Item2;
|
||||
|
||||
if (!m_query.filter.passFilter(neighbourRef, neighbourTile, neighbourPoly))
|
||||
if (!m_query.filter.PassFilter(neighbourRef, neighbourTile, neighbourPoly))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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
|
||||
// same parent
|
||||
|
@ -360,7 +360,7 @@ namespace DotRecast.Detour
|
|||
// position.
|
||||
if (neighbourNode.flags == 0)
|
||||
{
|
||||
var midpod = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
|
||||
var midpod = GetEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
|
||||
neighbourTile);
|
||||
if (!midpod.Failed())
|
||||
{
|
||||
|
@ -376,7 +376,7 @@ namespace DotRecast.Detour
|
|||
bool foundShortCut = false;
|
||||
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);
|
||||
if (rayHit.Succeeded())
|
||||
{
|
||||
|
@ -394,7 +394,7 @@ namespace DotRecast.Detour
|
|||
if (!foundShortCut)
|
||||
{
|
||||
// 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);
|
||||
cost = bestNode.cost + curCost;
|
||||
}
|
||||
|
@ -402,7 +402,7 @@ namespace DotRecast.Detour
|
|||
// Special case for last node.
|
||||
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);
|
||||
|
||||
cost = cost + endCost;
|
||||
|
@ -410,7 +410,7 @@ namespace DotRecast.Detour
|
|||
}
|
||||
else
|
||||
{
|
||||
heuristic = vDist(neighbourNode.pos, m_query.endPos) * H_SCALE;
|
||||
heuristic = VDist(neighbourNode.pos, m_query.endPos) * H_SCALE;
|
||||
}
|
||||
|
||||
float total = cost + heuristic;
|
||||
|
@ -430,7 +430,7 @@ namespace DotRecast.Detour
|
|||
}
|
||||
|
||||
// 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.flags = (neighbourNode.flags & ~(Node.DT_NODE_CLOSED | Node.DT_NODE_PARENT_DETACHED));
|
||||
neighbourNode.cost = cost;
|
||||
|
@ -443,13 +443,13 @@ namespace DotRecast.Detour
|
|||
if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0)
|
||||
{
|
||||
// Already in open, update node location.
|
||||
m_openList.modify(neighbourNode);
|
||||
m_openList.Modify(neighbourNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Put the node in open list.
|
||||
neighbourNode.flags |= Node.DT_NODE_OPEN;
|
||||
m_openList.push(neighbourNode);
|
||||
m_openList.Push(neighbourNode);
|
||||
}
|
||||
|
||||
// Update nearest node to target so far.
|
||||
|
@ -462,7 +462,7 @@ namespace DotRecast.Detour
|
|||
}
|
||||
|
||||
// Exhausted all nodes, but could not find path.
|
||||
if (m_openList.isEmpty())
|
||||
if (m_openList.IsEmpty())
|
||||
{
|
||||
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.)
|
||||
/// [(polyRef) * @p pathCount]
|
||||
/// @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);
|
||||
if (m_query.status.isFailed())
|
||||
if (m_query.status.IsFailed())
|
||||
{
|
||||
// Reset query.
|
||||
m_query = new QueryData();
|
||||
|
@ -502,8 +502,8 @@ namespace DotRecast.Detour
|
|||
int prevRay = 0;
|
||||
do
|
||||
{
|
||||
Node next = m_nodePool.getNodeAtIdx(node.pidx);
|
||||
node.pidx = m_nodePool.getNodeIdx(prev);
|
||||
Node next = m_nodePool.GetNodeAtIdx(node.pidx);
|
||||
node.pidx = m_nodePool.GetNodeIdx(prev);
|
||||
prev = node;
|
||||
int nextRay = node.flags & Node.DT_NODE_PARENT_DETACHED; // keep track of whether parent is not adjacent
|
||||
// (i.e. due to raycast shortcut)
|
||||
|
@ -517,10 +517,10 @@ namespace DotRecast.Detour
|
|||
node = prev;
|
||||
do
|
||||
{
|
||||
Node next = m_nodePool.getNodeAtIdx(node.pidx);
|
||||
Node next = m_nodePool.GetNodeAtIdx(node.pidx);
|
||||
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())
|
||||
{
|
||||
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.)
|
||||
/// [(polyRef) * @p pathCount]
|
||||
/// @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);
|
||||
if (null == existing || existing.Count <= 0)
|
||||
|
@ -563,7 +563,7 @@ namespace DotRecast.Detour
|
|||
return Results.Failure(path);
|
||||
}
|
||||
|
||||
if (m_query.status.isFailed())
|
||||
if (m_query.status.IsFailed())
|
||||
{
|
||||
// Reset query.
|
||||
m_query = new QueryData();
|
||||
|
@ -582,7 +582,7 @@ namespace DotRecast.Detour
|
|||
Node node = null;
|
||||
for (int i = existing.Count - 1; i >= 0; --i)
|
||||
{
|
||||
node = m_nodePool.findNode(existing[i]);
|
||||
node = m_nodePool.FindNode(existing[i]);
|
||||
if (node != null)
|
||||
{
|
||||
break;
|
||||
|
@ -599,8 +599,8 @@ namespace DotRecast.Detour
|
|||
int prevRay = 0;
|
||||
do
|
||||
{
|
||||
Node next = m_nodePool.getNodeAtIdx(node.pidx);
|
||||
node.pidx = m_nodePool.getNodeIdx(prev);
|
||||
Node next = m_nodePool.GetNodeAtIdx(node.pidx);
|
||||
node.pidx = m_nodePool.GetNodeIdx(prev);
|
||||
prev = node;
|
||||
int nextRay = node.flags & Node.DT_NODE_PARENT_DETACHED; // keep track of whether parent is not adjacent
|
||||
// (i.e. due to raycast shortcut)
|
||||
|
@ -614,10 +614,10 @@ namespace DotRecast.Detour
|
|||
node = prev;
|
||||
do
|
||||
{
|
||||
Node next = m_nodePool.getNodeAtIdx(node.pidx);
|
||||
Node next = m_nodePool.GetNodeAtIdx(node.pidx);
|
||||
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())
|
||||
{
|
||||
path.AddRange(iresult.result.path);
|
||||
|
@ -645,41 +645,41 @@ namespace DotRecast.Detour
|
|||
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
|
||||
if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(centerPos) || maxRadius < 0
|
||||
if (!m_nav.IsValidPolyRef(startRef) || !VIsFinite(centerPos) || maxRadius < 0
|
||||
|| !float.IsFinite(maxRadius) || null == filter)
|
||||
{
|
||||
return Results.InvalidParam<FindDistanceToWallResult>();
|
||||
}
|
||||
|
||||
m_nodePool.clear();
|
||||
m_openList.clear();
|
||||
m_nodePool.Clear();
|
||||
m_openList.Clear();
|
||||
|
||||
Node startNode = m_nodePool.getNode(startRef);
|
||||
Node startNode = m_nodePool.GetNode(startRef);
|
||||
startNode.pos = centerPos;
|
||||
startNode.pidx = 0;
|
||||
startNode.cost = 0;
|
||||
startNode.total = 0;
|
||||
startNode.id = startRef;
|
||||
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();
|
||||
VectorPtr bestvj = 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_CLOSED;
|
||||
|
||||
// Get poly and tile.
|
||||
// The API input has been cheked already, skip checking internal data.
|
||||
long bestRef = bestNode.id;
|
||||
Tuple<MeshTile, Poly> tileAndPoly = m_nav.getTileAndPolyByRefUnsafe(bestRef);
|
||||
Tuple<MeshTile, Poly> tileAndPoly = m_nav.GetTileAndPolyByRefUnsafe(bestRef);
|
||||
MeshTile bestTile = tileAndPoly.Item1;
|
||||
Poly bestPoly = tileAndPoly.Item2;
|
||||
|
||||
|
@ -687,7 +687,7 @@ namespace DotRecast.Detour
|
|||
long parentRef = 0;
|
||||
if (bestNode.pidx != 0)
|
||||
{
|
||||
parentRef = m_nodePool.getNodeAtIdx(bestNode.pidx).id;
|
||||
parentRef = m_nodePool.GetNodeAtIdx(bestNode.pidx).id;
|
||||
}
|
||||
|
||||
// Hit test walls.
|
||||
|
@ -705,10 +705,10 @@ namespace DotRecast.Detour
|
|||
{
|
||||
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;
|
||||
Poly neiPoly = linkTileAndPoly.Item2;
|
||||
if (filter.passFilter(link.refs, neiTile, neiPoly))
|
||||
if (filter.PassFilter(link.refs, neiTile, neiPoly))
|
||||
{
|
||||
solid = false;
|
||||
}
|
||||
|
@ -727,8 +727,8 @@ namespace DotRecast.Detour
|
|||
{
|
||||
// Internal edge
|
||||
int idx = (bestPoly.neis[j] - 1);
|
||||
long refs = m_nav.getPolyRefBase(bestTile) | idx;
|
||||
if (filter.passFilter(refs, bestTile, bestTile.data.polys[idx]))
|
||||
long refs = m_nav.GetPolyRefBase(bestTile) | idx;
|
||||
if (filter.PassFilter(refs, bestTile, bestTile.data.polys[idx]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -737,7 +737,7 @@ namespace DotRecast.Detour
|
|||
// Calc distance to the edge.
|
||||
int vj = bestPoly.verts[j] * 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 tseg = distseg.Item2;
|
||||
|
||||
|
@ -770,12 +770,12 @@ namespace DotRecast.Detour
|
|||
}
|
||||
|
||||
// Expand to neighbour.
|
||||
Tuple<MeshTile, Poly> neighbourTileAndPoly = m_nav.getTileAndPolyByRefUnsafe(neighbourRef);
|
||||
Tuple<MeshTile, Poly> neighbourTileAndPoly = m_nav.GetTileAndPolyByRefUnsafe(neighbourRef);
|
||||
MeshTile neighbourTile = neighbourTileAndPoly.Item1;
|
||||
Poly neighbourPoly = neighbourTileAndPoly.Item2;
|
||||
|
||||
// Skip off-mesh connections.
|
||||
if (neighbourPoly.getType() == Poly.DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||
if (neighbourPoly.GetType() == Poly.DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -783,7 +783,7 @@ namespace DotRecast.Detour
|
|||
// Calc distance to the edge.
|
||||
int va = bestPoly.verts[link.edge] * 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;
|
||||
// If the circle is not touching the next polygon, skip it.
|
||||
if (distSqr > radiusSqr)
|
||||
|
@ -791,12 +791,12 @@ namespace DotRecast.Detour
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!filter.passFilter(neighbourRef, neighbourTile, neighbourPoly))
|
||||
if (!filter.PassFilter(neighbourRef, neighbourTile, neighbourPoly))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Node neighbourNode = m_nodePool.getNode(neighbourRef);
|
||||
Node neighbourNode = m_nodePool.GetNode(neighbourRef);
|
||||
|
||||
if ((neighbourNode.flags & Node.DT_NODE_CLOSED) != 0)
|
||||
{
|
||||
|
@ -806,7 +806,7 @@ namespace DotRecast.Detour
|
|||
// Cost
|
||||
if (neighbourNode.flags == 0)
|
||||
{
|
||||
var midPoint = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
|
||||
var midPoint = GetEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
|
||||
neighbourTile);
|
||||
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.
|
||||
if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0 && total >= neighbourNode.total)
|
||||
|
@ -824,17 +824,17 @@ namespace DotRecast.Detour
|
|||
|
||||
neighbourNode.id = neighbourRef;
|
||||
neighbourNode.flags = (neighbourNode.flags & ~Node.DT_NODE_CLOSED);
|
||||
neighbourNode.pidx = m_nodePool.getNodeIdx(bestNode);
|
||||
neighbourNode.pidx = m_nodePool.GetNodeIdx(bestNode);
|
||||
neighbourNode.total = total;
|
||||
|
||||
if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0)
|
||||
{
|
||||
m_openList.modify(neighbourNode);
|
||||
m_openList.Modify(neighbourNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
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();
|
||||
if (bestvi != null && bestvj != null)
|
||||
{
|
||||
var tangent = vSub(bestvi, bestvj);
|
||||
var tangent = VSub(bestvi, bestvj);
|
||||
hitNormal.x = tangent.z;
|
||||
hitNormal.y = 0;
|
||||
hitNormal.z = -tangent.x;
|
||||
vNormalize(ref hitNormal);
|
||||
VNormalize(ref hitNormal);
|
||||
}
|
||||
|
||||
return Results.Success(new FindDistanceToWallResult((float)Math.Sqrt(radiusSqr), hitPos, hitNormal));
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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[] bmax = new int[3];
|
||||
|
@ -94,7 +94,7 @@ namespace DotRecast.Detour
|
|||
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 maxVal = x;
|
||||
|
@ -113,7 +113,7 @@ namespace DotRecast.Detour
|
|||
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 icur = curNode;
|
||||
|
@ -137,11 +137,11 @@ namespace DotRecast.Detour
|
|||
else
|
||||
{
|
||||
// Split
|
||||
int[][] minmax = calcExtends(items, nitems, imin, imax);
|
||||
int[][] minmax = CalcExtends(items, nitems, imin, imax);
|
||||
node.bmin = minmax[0];
|
||||
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]);
|
||||
|
||||
if (axis == 0)
|
||||
|
@ -163,9 +163,9 @@ namespace DotRecast.Detour
|
|||
int isplit = imin + inum / 2;
|
||||
|
||||
// Left
|
||||
curNode = subdivide(items, nitems, imin, isplit, curNode, nodes);
|
||||
curNode = Subdivide(items, nitems, imin, isplit, curNode, nodes);
|
||||
// Right
|
||||
curNode = subdivide(items, nitems, isplit, imax, curNode, nodes);
|
||||
curNode = Subdivide(items, nitems, isplit, imax, curNode, nodes);
|
||||
|
||||
int iescape = curNode - icur;
|
||||
// Negative index means escape.
|
||||
|
@ -175,7 +175,7 @@ namespace DotRecast.Detour
|
|||
return curNode;
|
||||
}
|
||||
|
||||
private static int createBVTree(NavMeshDataCreateParams option, BVNode[] nodes)
|
||||
private static int CreateBVTree(NavMeshDataCreateParams option, BVNode[] nodes)
|
||||
{
|
||||
// Build tree
|
||||
float quantFactor = 1 / option.cs;
|
||||
|
@ -193,22 +193,22 @@ namespace DotRecast.Detour
|
|||
Vector3f bmin = new Vector3f();
|
||||
Vector3f bmax = new Vector3f();
|
||||
int dv = vb * 3;
|
||||
vCopy(ref bmin, option.detailVerts, dv);
|
||||
vCopy(ref bmax, option.detailVerts, dv);
|
||||
VCopy(ref bmin, option.detailVerts, dv);
|
||||
VCopy(ref bmax, option.detailVerts, dv);
|
||||
for (int j = 1; j < ndv; j++)
|
||||
{
|
||||
vMin(ref bmin, option.detailVerts, dv + j * 3);
|
||||
vMax(ref bmax, option.detailVerts, dv + j * 3);
|
||||
VMin(ref bmin, option.detailVerts, dv + j * 3);
|
||||
VMax(ref bmax, option.detailVerts, dv + j * 3);
|
||||
}
|
||||
|
||||
// BV-tree uses cs for all dimensions
|
||||
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[2] = clamp((int)((bmin.z - option.bmin.z) * 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[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[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[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[2] = Clamp((int)((bmax.z - option.bmin.z) * quantFactor), 0, int.MaxValue);
|
||||
}
|
||||
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;
|
||||
|
@ -254,13 +254,13 @@ namespace DotRecast.Detour
|
|||
const int XM = 1 << 2;
|
||||
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;
|
||||
outcode |= (pt.get(0) >= bmax.x) ? XP : 0;
|
||||
outcode |= (pt.get(2) >= bmax.z) ? ZP : 0;
|
||||
outcode |= (pt.get(0) < bmin.x) ? XM : 0;
|
||||
outcode |= (pt.get(2) < bmin.z) ? ZM : 0;
|
||||
outcode |= (pt.Get(0) >= bmax.x) ? XP : 0;
|
||||
outcode |= (pt.Get(2) >= bmax.z) ? ZP : 0;
|
||||
outcode |= (pt.Get(0) < bmin.x) ? XM : 0;
|
||||
outcode |= (pt.Get(2) < bmin.z) ? ZM : 0;
|
||||
|
||||
switch (outcode)
|
||||
{
|
||||
|
@ -293,7 +293,7 @@ namespace DotRecast.Detour
|
|||
*
|
||||
* @return created tile data
|
||||
*/
|
||||
public static MeshData createNavMeshData(NavMeshDataCreateParams option)
|
||||
public static MeshData CreateNavMeshData(NavMeshDataCreateParams option)
|
||||
{
|
||||
if (option.vertCount >= 0xffff)
|
||||
return null;
|
||||
|
@ -353,14 +353,14 @@ namespace DotRecast.Detour
|
|||
VectorPtr p0 = new VectorPtr(option.offMeshConVerts, (i * 2 + 0) * 3);
|
||||
VectorPtr p1 = new VectorPtr(option.offMeshConVerts, (i * 2 + 1) * 3);
|
||||
|
||||
offMeshConClass[i * 2 + 0] = classifyOffMeshPoint(p0, bmin, bmax);
|
||||
offMeshConClass[i * 2 + 1] = classifyOffMeshPoint(p1, bmin, bmax);
|
||||
offMeshConClass[i * 2 + 0] = ClassifyOffMeshPoint(p0, bmin, bmax);
|
||||
offMeshConClass[i * 2 + 1] = ClassifyOffMeshPoint(p1, bmin, bmax);
|
||||
|
||||
// Zero out off-mesh start positions which are not even
|
||||
// potentially touching the mesh.
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -517,8 +517,8 @@ namespace DotRecast.Detour
|
|||
navPolys[i] = p;
|
||||
p.vertCount = 0;
|
||||
p.flags = option.polyFlags[i];
|
||||
p.setArea(option.polyAreas[i]);
|
||||
p.setType(Poly.DT_POLYTYPE_GROUND);
|
||||
p.SetArea(option.polyAreas[i]);
|
||||
p.SetType(Poly.DT_POLYTYPE_GROUND);
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (option.polys[src + j] == MESH_NULL_IDX)
|
||||
|
@ -564,8 +564,8 @@ namespace DotRecast.Detour
|
|||
p.verts[0] = offMeshVertsBase + n * 2;
|
||||
p.verts[1] = offMeshVertsBase + n * 2 + 1;
|
||||
p.flags = option.offMeshConFlags[i];
|
||||
p.setArea(option.offMeshConAreas[i]);
|
||||
p.setType(Poly.DT_POLYTYPE_OFFMESH_CONNECTION);
|
||||
p.SetArea(option.offMeshConAreas[i]);
|
||||
p.SetType(Poly.DT_POLYTYPE_OFFMESH_CONNECTION);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
@ -637,7 +637,7 @@ namespace DotRecast.Detour
|
|||
if (option.buildBvTree)
|
||||
{
|
||||
// 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.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,14 +26,14 @@ namespace DotRecast.Detour
|
|||
*/
|
||||
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)
|
||||
{
|
||||
float? intersection = raycast(tile, src, dst);
|
||||
float? intersection = Raycast(tile, src, dst);
|
||||
if (null != intersection)
|
||||
{
|
||||
return intersection;
|
||||
|
@ -44,12 +44,12 @@ namespace DotRecast.Detour
|
|||
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)
|
||||
{
|
||||
Poly p = tile.data.polys[i];
|
||||
if (p.getType() == Poly.DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||
if (p.GetType() == Poly.DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return intersection;
|
||||
|
|
|
@ -24,13 +24,13 @@ namespace DotRecast.Detour
|
|||
{
|
||||
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 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)
|
||||
{
|
||||
for (int i = 0; i < tile.data.verts.Length; i += 3)
|
||||
|
|
|
@ -31,13 +31,13 @@ namespace DotRecast.Detour
|
|||
{
|
||||
}
|
||||
|
||||
public void clear()
|
||||
public void Clear()
|
||||
{
|
||||
m_nodes.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);
|
||||
;
|
||||
|
@ -49,7 +49,7 @@ namespace DotRecast.Detour
|
|||
return nodes;
|
||||
}
|
||||
|
||||
public Node findNode(long id)
|
||||
public Node FindNode(long id)
|
||||
{
|
||||
var hasNode = m_map.TryGetValue(id, out var nodes);
|
||||
;
|
||||
|
@ -61,7 +61,7 @@ namespace DotRecast.Detour
|
|||
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);
|
||||
;
|
||||
|
@ -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.id = id;
|
||||
|
@ -97,22 +97,22 @@ namespace DotRecast.Detour
|
|||
return node;
|
||||
}
|
||||
|
||||
public int getNodeIdx(Node node)
|
||||
public int GetNodeIdx(Node node)
|
||||
{
|
||||
return node != null ? node.index : 0;
|
||||
}
|
||||
|
||||
public Node getNodeAtIdx(int idx)
|
||||
public Node GetNodeAtIdx(int idx)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -28,40 +28,40 @@ namespace DotRecast.Detour
|
|||
{
|
||||
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();
|
||||
}
|
||||
|
||||
public void clear()
|
||||
public void Clear()
|
||||
{
|
||||
m_heap.Clear();
|
||||
}
|
||||
|
||||
public Node top()
|
||||
public Node Top()
|
||||
{
|
||||
return m_heap.Top();
|
||||
}
|
||||
|
||||
public Node pop()
|
||||
public Node Pop()
|
||||
{
|
||||
var node = top();
|
||||
var node = Top();
|
||||
m_heap.Remove(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
public void push(Node node)
|
||||
public void Push(Node node)
|
||||
{
|
||||
m_heap.Enqueue(node);
|
||||
}
|
||||
|
||||
public void modify(Node node)
|
||||
public void Modify(Node node)
|
||||
{
|
||||
m_heap.Remove(node);
|
||||
push(node);
|
||||
Push(node);
|
||||
}
|
||||
|
||||
public bool isEmpty()
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return 0 == m_heap.Count();
|
||||
}
|
||||
|
|
|
@ -30,11 +30,11 @@ namespace DotRecast.Detour
|
|||
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)
|
||||
{
|
||||
// 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())
|
||||
{
|
||||
return null;
|
||||
|
@ -44,9 +44,9 @@ namespace DotRecast.Detour
|
|||
float[] steerPoints = new float[straightPath.Count * 3];
|
||||
for (int i = 0; i < straightPath.Count; i++)
|
||||
{
|
||||
steerPoints[i * 3] = straightPath[i].getPos().x;
|
||||
steerPoints[i * 3 + 1] = straightPath[i].getPos().y;
|
||||
steerPoints[i * 3 + 2] = straightPath[i].getPos().z;
|
||||
steerPoints[i * 3] = straightPath[i].GetPos().x;
|
||||
steerPoints[i * 3 + 1] = straightPath[i].GetPos().y;
|
||||
steerPoints[i * 3 + 2] = straightPath[i].GetPos().z;
|
||||
}
|
||||
|
||||
// Find vertex far enough to steer to.
|
||||
|
@ -54,8 +54,8 @@ namespace DotRecast.Detour
|
|||
while (ns < straightPath.Count)
|
||||
{
|
||||
// Stop at Off-Mesh link or when point is further than slop away.
|
||||
if (((straightPath[ns].getFlags() & NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|
||||
|| !inRange(straightPath[ns].getPos(), startPos, minTargetDist, 1000.0f))
|
||||
if (((straightPath[ns].GetFlags() & NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|
||||
|| !InRange(straightPath[ns].GetPos(), startPos, minTargetDist, 1000.0f))
|
||||
break;
|
||||
ns++;
|
||||
}
|
||||
|
@ -65,18 +65,18 @@ namespace DotRecast.Detour
|
|||
return null;
|
||||
|
||||
Vector3f steerPos = Vector3f.Of(
|
||||
straightPath[ns].getPos().x,
|
||||
straightPath[ns].GetPos().x,
|
||||
startPos.y,
|
||||
straightPath[ns].getPos().z
|
||||
straightPath[ns].GetPos().z
|
||||
);
|
||||
int steerPosFlag = straightPath[ns].getFlags();
|
||||
long steerPosRef = straightPath[ns].getRef();
|
||||
int steerPosFlag = straightPath[ns].GetFlags();
|
||||
long steerPosRef = straightPath[ns].GetRef();
|
||||
|
||||
SteerTarget target = new SteerTarget(steerPos, steerPosFlag, steerPosRef, steerPoints);
|
||||
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 dy = v2.y - v1.y;
|
||||
|
@ -84,7 +84,7 @@ namespace DotRecast.Detour
|
|||
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 furthestVisited = -1;
|
||||
|
@ -143,7 +143,7 @@ namespace DotRecast.Detour
|
|||
// +-S-+-T-+
|
||||
// |:::| | <-- 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)
|
||||
{
|
||||
|
@ -153,7 +153,7 @@ namespace DotRecast.Detour
|
|||
// Get connected polygons
|
||||
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())
|
||||
{
|
||||
return path;
|
||||
|
|
|
@ -58,25 +58,25 @@ namespace DotRecast.Detour
|
|||
}
|
||||
|
||||
/** Sets the user defined area id. [Limit: < {@link org.recast4j.detour.NavMesh#DT_MAX_AREAS}] */
|
||||
public void setArea(int a)
|
||||
public void SetArea(int a)
|
||||
{
|
||||
areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f);
|
||||
}
|
||||
|
||||
/** Sets the polygon type. (See: #dtPolyTypes.) */
|
||||
public void setType(int t)
|
||||
public void SetType(int t)
|
||||
{
|
||||
areaAndtype = (areaAndtype & 0x3f) | (t << 6);
|
||||
}
|
||||
|
||||
/** Gets the user defined area id. */
|
||||
public int getArea()
|
||||
public int GetArea()
|
||||
{
|
||||
return areaAndtype & 0x3f;
|
||||
}
|
||||
|
||||
/** Gets the polygon type. (See: #dtPolyTypes) */
|
||||
public int getType()
|
||||
public int GetType()
|
||||
{
|
||||
return areaAndtype >> 6;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,6 @@ namespace DotRecast.Detour
|
|||
{
|
||||
public interface PolyQuery
|
||||
{
|
||||
void process(MeshTile tile, Poly poly, long refs);
|
||||
void Process(MeshTile tile, Poly poly, long refs);
|
||||
}
|
||||
}
|
|
@ -25,21 +25,21 @@ namespace DotRecast.Detour
|
|||
|
||||
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();
|
||||
}
|
||||
|
||||
public static PolygonByCircleConstraint strict()
|
||||
public static PolygonByCircleConstraint Strict()
|
||||
{
|
||||
return new StrictPolygonByCircleConstraint();
|
||||
}
|
||||
|
||||
public class NoOpPolygonByCircleConstraint : PolygonByCircleConstraint
|
||||
{
|
||||
public float[] aply(float[] polyVerts, Vector3f circleCenter, float radius)
|
||||
public float[] Aply(float[] polyVerts, Vector3f circleCenter, float radius)
|
||||
{
|
||||
return polyVerts;
|
||||
}
|
||||
|
@ -53,13 +53,13 @@ namespace DotRecast.Detour
|
|||
private const int CIRCLE_SEGMENTS = 12;
|
||||
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;
|
||||
int outsideVertex = -1;
|
||||
for (int pv = 0; pv < verts.Length; pv += 3)
|
||||
{
|
||||
if (vDist2DSqr(center, verts, pv) > radiusSqr)
|
||||
if (VDist2DSqr(center, verts, pv) > radiusSqr)
|
||||
{
|
||||
outsideVertex = pv;
|
||||
break;
|
||||
|
@ -72,9 +72,9 @@ namespace DotRecast.Detour
|
|||
return verts;
|
||||
}
|
||||
|
||||
float[] qCircle = circle(center, radius);
|
||||
float[] intersection = ConvexConvexIntersection.intersect(verts, qCircle);
|
||||
if (intersection == null && pointInPolygon(center, verts, verts.Length / 3))
|
||||
float[] qCircle = Circle(center, radius);
|
||||
float[] intersection = ConvexConvexIntersection.Intersect(verts, qCircle);
|
||||
if (intersection == null && PointInPolygon(center, verts, verts.Length / 3))
|
||||
{
|
||||
// circle inside polygon
|
||||
return qCircle;
|
||||
|
@ -83,7 +83,7 @@ namespace DotRecast.Detour
|
|||
return intersection;
|
||||
}
|
||||
|
||||
private float[] circle(Vector3f center, float radius)
|
||||
private float[] Circle(Vector3f center, float radius)
|
||||
{
|
||||
if (unitCircle == null)
|
||||
{
|
||||
|
|
|
@ -24,9 +24,9 @@ namespace DotRecast.Detour
|
|||
{
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -22,6 +22,6 @@ namespace DotRecast.Detour
|
|||
{
|
||||
public interface QueryHeuristic
|
||||
{
|
||||
float getCost(Vector3f neighbourPos, Vector3f endPos);
|
||||
float GetCost(Vector3f neighbourPos, Vector3f endPos);
|
||||
}
|
||||
}
|
|
@ -34,13 +34,13 @@ namespace DotRecast.Detour.QueryResults
|
|||
}
|
||||
|
||||
/** Returns true if the position is over the polygon. */
|
||||
public bool isPosOverPoly()
|
||||
public bool IsPosOverPoly()
|
||||
{
|
||||
return posOverPoly;
|
||||
}
|
||||
|
||||
/** Returns the closest point on the polygon. [(x, y, z)] */
|
||||
public Vector3f getClosest()
|
||||
public Vector3f GetClosest()
|
||||
{
|
||||
return closest;
|
||||
}
|
||||
|
|
|
@ -36,17 +36,17 @@ namespace DotRecast.Detour.QueryResults
|
|||
this.normal = normal;
|
||||
}
|
||||
|
||||
public float getDistance()
|
||||
public float GetDistance()
|
||||
{
|
||||
return distance;
|
||||
}
|
||||
|
||||
public Vector3f getPosition()
|
||||
public Vector3f GetPosition()
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
public Vector3f getNormal()
|
||||
public Vector3f GetNormal()
|
||||
{
|
||||
return normal;
|
||||
}
|
||||
|
|
|
@ -34,12 +34,12 @@ namespace DotRecast.Detour.QueryResults
|
|||
this.parentRefs = parentRefs;
|
||||
}
|
||||
|
||||
public List<long> getRefs()
|
||||
public List<long> GetRefs()
|
||||
{
|
||||
return refs;
|
||||
}
|
||||
|
||||
public List<long> getParentRefs()
|
||||
public List<long> GetParentRefs()
|
||||
{
|
||||
return parentRefs;
|
||||
}
|
||||
|
|
|
@ -36,18 +36,18 @@ namespace DotRecast.Detour.QueryResults
|
|||
}
|
||||
|
||||
/** Returns the reference id of the nearest polygon. 0 if no polygon is found. */
|
||||
public long getNearestRef()
|
||||
public long GetNearestRef()
|
||||
{
|
||||
return nearestRef;
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
public bool isOverPoly()
|
||||
public bool IsOverPoly()
|
||||
{
|
||||
return overPoly;
|
||||
}
|
||||
|
|
|
@ -36,17 +36,17 @@ namespace DotRecast.Detour.QueryResults
|
|||
this.costs = costs;
|
||||
}
|
||||
|
||||
public List<long> getRefs()
|
||||
public List<long> GetRefs()
|
||||
{
|
||||
return refs;
|
||||
}
|
||||
|
||||
public List<long> getParentRefs()
|
||||
public List<long> GetParentRefs()
|
||||
{
|
||||
return parentRefs;
|
||||
}
|
||||
|
||||
public List<float> getCosts()
|
||||
public List<float> GetCosts()
|
||||
{
|
||||
return costs;
|
||||
}
|
||||
|
|
|
@ -35,13 +35,13 @@ namespace DotRecast.Detour.QueryResults
|
|||
}
|
||||
|
||||
/// @param[out] randomRef The reference id of the random location.
|
||||
public long getRandomRef()
|
||||
public long GetRandomRef()
|
||||
{
|
||||
return randomRef;
|
||||
}
|
||||
|
||||
/// @param[out] randomPt The random location.
|
||||
public Vector3f getRandomPt()
|
||||
public Vector3f GetRandomPt()
|
||||
{
|
||||
return randomPt;
|
||||
}
|
||||
|
|
|
@ -34,23 +34,23 @@ namespace DotRecast.Detour.QueryResults
|
|||
_segmentRefs = segmentRefs;
|
||||
}
|
||||
|
||||
public int countSegmentVerts()
|
||||
public int CountSegmentVerts()
|
||||
{
|
||||
return _segmentVerts.Count;
|
||||
}
|
||||
|
||||
public int countSegmentRefs()
|
||||
public int CountSegmentRefs()
|
||||
{
|
||||
return _segmentRefs.Count;
|
||||
}
|
||||
|
||||
|
||||
public SegmentVert getSegmentVert(int idx)
|
||||
public SegmentVert GetSegmentVert(int idx)
|
||||
{
|
||||
return _segmentVerts[idx];
|
||||
}
|
||||
|
||||
public long getSegmentRef(int idx)
|
||||
public long GetSegmentRef(int idx)
|
||||
{
|
||||
return _segmentRefs[idx];
|
||||
}
|
||||
|
|
|
@ -37,12 +37,12 @@ namespace DotRecast.Detour.QueryResults
|
|||
this.visited = visited;
|
||||
}
|
||||
|
||||
public Vector3f getResultPos()
|
||||
public Vector3f GetResultPos()
|
||||
{
|
||||
return resultPos;
|
||||
}
|
||||
|
||||
public List<long> getVisited()
|
||||
public List<long> GetVisited()
|
||||
{
|
||||
return visited;
|
||||
}
|
||||
|
|
|
@ -84,12 +84,12 @@ namespace DotRecast.Detour.QueryResults
|
|||
|
||||
public bool Failed()
|
||||
{
|
||||
return status.isFailed();
|
||||
return status.IsFailed();
|
||||
}
|
||||
|
||||
public bool Succeeded()
|
||||
{
|
||||
return status.isSuccess();
|
||||
return status.IsSuccess();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,22 +38,22 @@ namespace DotRecast.Detour
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
public static bool isInProgress(this Status @this)
|
||||
public static bool IsInProgress(this Status @this)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public static bool isPartial(this Status @this)
|
||||
public static bool IsPartial(this Status @this)
|
||||
{
|
||||
return @this == Status.PARTIAL_RESULT;
|
||||
}
|
||||
|
|
|
@ -38,17 +38,17 @@ namespace DotRecast.Detour
|
|||
this.refs = refs;
|
||||
}
|
||||
|
||||
public Vector3f getPos()
|
||||
public Vector3f GetPos()
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
public int getFlags()
|
||||
public int GetFlags()
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
|
||||
public long getRef()
|
||||
public long GetRef()
|
||||
{
|
||||
return refs;
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ namespace DotRecast.Recast.Demo.Builder;
|
|||
|
||||
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,
|
||||
RecastBuilderResult rcResult)
|
||||
{
|
||||
PolyMesh m_pmesh = rcResult.getMesh();
|
||||
PolyMeshDetail m_dmesh = rcResult.getMeshDetail();
|
||||
PolyMesh m_pmesh = rcResult.GetMesh();
|
||||
PolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
|
||||
NavMeshDataCreateParams option = new NavMeshDataCreateParams();
|
||||
for (int i = 0; i < m_pmesh.npolys; ++i)
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ public abstract class AbstractNavMeshBuilder
|
|||
option.ch = m_cellHeight;
|
||||
option.buildBvTree = true;
|
||||
|
||||
option.offMeshConCount = m_geom.getOffMeshConnections().Count;
|
||||
option.offMeshConCount = m_geom.GetOffMeshConnections().Count;
|
||||
option.offMeshConVerts = new float[option.offMeshConCount * 6];
|
||||
option.offMeshConRad = new float[option.offMeshConCount];
|
||||
option.offMeshConDir = new int[option.offMeshConCount];
|
||||
|
@ -51,7 +51,7 @@ public abstract class AbstractNavMeshBuilder
|
|||
option.offMeshConUserID = new int[option.offMeshConCount];
|
||||
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++)
|
||||
{
|
||||
option.offMeshConVerts[6 * i + j] = offMeshCon.verts[j];
|
||||
|
@ -66,27 +66,27 @@ public abstract class AbstractNavMeshBuilder
|
|||
return option;
|
||||
}
|
||||
|
||||
protected MeshData updateAreaAndFlags(MeshData meshData)
|
||||
protected MeshData UpdateAreaAndFlags(MeshData meshData)
|
||||
{
|
||||
// Update poly flags from areas.
|
||||
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
|
||||
|| meshData.polys[i].getArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GRASS
|
||||
|| meshData.polys[i].getArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD)
|
||||
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_ROAD)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -26,28 +26,28 @@ namespace DotRecast.Recast.Demo.Builder;
|
|||
|
||||
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_agentMaxSlope, 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, 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_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError, filterLowHangingObstacles, filterLedgeSpans,
|
||||
filterWalkableLowHeightSpans);
|
||||
return Tuple.Create(ImmutableArray.Create(rcResult) as IList<RecastBuilderResult>,
|
||||
buildNavMesh(
|
||||
buildMeshData(m_geom, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, rcResult),
|
||||
BuildNavMesh(
|
||||
BuildMeshData(m_geom, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, rcResult),
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
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,
|
||||
|
@ -57,16 +57,16 @@ public class SoloNavMeshBuilder : AbstractNavMeshBuilder
|
|||
filterLedgeSpans, filterWalkableLowHeightSpans, m_agentHeight, m_agentRadius, m_agentMaxClimb, m_regionMinSize,
|
||||
m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError,
|
||||
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();
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return updateAreaAndFlags(NavMeshBuilder.createNavMeshData(option));
|
||||
return UpdateAreaAndFlags(NavMeshBuilder.CreateNavMeshData(option));
|
||||
}
|
||||
}
|
|
@ -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_agentMaxSlope, 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, 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_vertsPerPoly, m_detailSampleDist, m_detailSampleMaxError, filterLowHangingObstacles, filterLedgeSpans,
|
||||
filterWalkableLowHeightSpans, tileSize);
|
||||
return Tuple.Create((IList<RecastBuilderResult>)rcResult,
|
||||
buildNavMesh(m_geom,
|
||||
buildMeshData(m_geom, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, rcResult),
|
||||
BuildNavMesh(m_geom,
|
||||
BuildMeshData(m_geom, m_cellSize, m_cellHeight, m_agentHeight, m_agentRadius, m_agentMaxClimb, rcResult),
|
||||
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_agentMaxSlope, 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, 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,
|
||||
filterWalkableLowHeightSpans, m_agentHeight, m_agentRadius, m_agentMaxClimb,
|
||||
m_regionMinSize * m_regionMinSize * m_cellSize * m_cellSize,
|
||||
m_regionMergeSize * m_regionMergeSize * m_cellSize * m_cellSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly,
|
||||
true, m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE);
|
||||
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)
|
||||
{
|
||||
NavMeshParams navMeshParams = new NavMeshParams();
|
||||
navMeshParams.orig.x = geom.getMeshBoundsMin().x;
|
||||
navMeshParams.orig.y = geom.getMeshBoundsMin().y;
|
||||
navMeshParams.orig.z = geom.getMeshBoundsMin().z;
|
||||
navMeshParams.orig.x = geom.GetMeshBoundsMin().x;
|
||||
navMeshParams.orig.y = geom.GetMeshBoundsMin().y;
|
||||
navMeshParams.orig.z = geom.GetMeshBoundsMin().z;
|
||||
navMeshParams.tileWidth = 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.maxPolys = getMaxPolysPerTile(geom, cellSize, tileSize);
|
||||
navMeshParams.maxTiles = GetMaxTiles(geom, cellSize, tileSize);
|
||||
navMeshParams.maxPolys = GetMaxPolysPerTile(geom, cellSize, tileSize);
|
||||
NavMesh navMesh = new NavMesh(navMeshParams, vertsPerPoly);
|
||||
meshData.forEach(md => navMesh.addTile(md, 0, 0));
|
||||
meshData.ForEach(md => navMesh.AddTile(md, 0, 0));
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
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 th = (wh[1] + tileSize - 1) / tileSize;
|
||||
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)
|
||||
{
|
||||
// Add tiles to nav mesh
|
||||
|
@ -121,14 +121,14 @@ public class TileNavMeshBuilder : AbstractNavMeshBuilder
|
|||
{
|
||||
int x = result.tileX;
|
||||
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);
|
||||
option.tileX = x;
|
||||
option.tileZ = z;
|
||||
MeshData md = NavMeshBuilder.createNavMeshData(option);
|
||||
MeshData md = NavMeshBuilder.CreateNavMeshData(option);
|
||||
if (md != null)
|
||||
{
|
||||
meshData.Add(updateAreaAndFlags(md));
|
||||
meshData.Add(UpdateAreaAndFlags(md));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
begin(DebugDrawPrimitives.LINES, lineWidth);
|
||||
appendCylinderWire(minx, miny, minz, maxx, maxy, maxz, col);
|
||||
end();
|
||||
Begin(DebugDrawPrimitives.LINES, lineWidth);
|
||||
AppendCylinderWire(minx, miny, minz, maxx, maxy, maxz, col);
|
||||
End();
|
||||
}
|
||||
|
||||
private const int CYLINDER_NUM_SEG = 16;
|
||||
private readonly float[] cylinderDir = new float[CYLINDER_NUM_SEG * 2];
|
||||
private bool cylinderInit = false;
|
||||
|
||||
private void initCylinder()
|
||||
private void InitCylinder()
|
||||
{
|
||||
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 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++)
|
||||
{
|
||||
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[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[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[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);
|
||||
}
|
||||
|
||||
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, maxy, 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);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
begin(DebugDrawPrimitives.LINES, lineWidth);
|
||||
appendBoxWire(minx, miny, minz, maxx, maxy, maxz, col);
|
||||
end();
|
||||
Begin(DebugDrawPrimitives.LINES, lineWidth);
|
||||
AppendBoxWire(minx, miny, minz, maxx, maxy, maxz, col);
|
||||
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
|
||||
vertex(minx, miny, minz, col);
|
||||
vertex(maxx, miny, minz, col);
|
||||
vertex(maxx, miny, minz, col);
|
||||
vertex(maxx, miny, maxz, col);
|
||||
vertex(maxx, miny, maxz, col);
|
||||
vertex(minx, miny, maxz, col);
|
||||
vertex(minx, miny, maxz, col);
|
||||
vertex(minx, miny, minz, col);
|
||||
Vertex(minx, miny, minz, col);
|
||||
Vertex(maxx, miny, minz, col);
|
||||
Vertex(maxx, miny, minz, col);
|
||||
Vertex(maxx, miny, maxz, col);
|
||||
Vertex(maxx, miny, maxz, col);
|
||||
Vertex(minx, miny, maxz, col);
|
||||
Vertex(minx, miny, maxz, col);
|
||||
Vertex(minx, miny, minz, col);
|
||||
|
||||
// bottom
|
||||
vertex(minx, maxy, minz, col);
|
||||
vertex(maxx, maxy, minz, col);
|
||||
vertex(maxx, maxy, minz, col);
|
||||
vertex(maxx, maxy, maxz, col);
|
||||
vertex(maxx, maxy, maxz, col);
|
||||
vertex(minx, maxy, maxz, col);
|
||||
vertex(minx, maxy, maxz, col);
|
||||
vertex(minx, maxy, minz, col);
|
||||
Vertex(minx, maxy, minz, col);
|
||||
Vertex(maxx, maxy, minz, col);
|
||||
Vertex(maxx, maxy, minz, col);
|
||||
Vertex(maxx, maxy, maxz, col);
|
||||
Vertex(maxx, maxy, maxz, col);
|
||||
Vertex(minx, maxy, maxz, col);
|
||||
Vertex(minx, maxy, maxz, col);
|
||||
Vertex(minx, maxy, minz, col);
|
||||
|
||||
// Sides
|
||||
vertex(minx, miny, minz, col);
|
||||
vertex(minx, maxy, minz, col);
|
||||
vertex(maxx, miny, minz, col);
|
||||
vertex(maxx, maxy, minz, col);
|
||||
vertex(maxx, miny, maxz, col);
|
||||
vertex(maxx, maxy, maxz, col);
|
||||
vertex(minx, miny, maxz, col);
|
||||
vertex(minx, maxy, maxz, col);
|
||||
Vertex(minx, miny, minz, col);
|
||||
Vertex(minx, maxy, minz, col);
|
||||
Vertex(maxx, miny, minz, col);
|
||||
Vertex(maxx, maxy, minz, col);
|
||||
Vertex(maxx, miny, maxz, col);
|
||||
Vertex(maxx, maxy, maxz, col);
|
||||
Vertex(minx, miny, 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 =
|
||||
{
|
||||
|
@ -161,66 +161,66 @@ public class DebugDraw
|
|||
int idx = 0;
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
vertex(verts[boxIndices[idx]], fcol[i]);
|
||||
Vertex(verts[boxIndices[idx]], fcol[i]);
|
||||
idx++;
|
||||
vertex(verts[boxIndices[idx]], fcol[i]);
|
||||
Vertex(verts[boxIndices[idx]], fcol[i]);
|
||||
idx++;
|
||||
vertex(verts[boxIndices[idx]], fcol[i]);
|
||||
Vertex(verts[boxIndices[idx]], fcol[i]);
|
||||
idx++;
|
||||
vertex(verts[boxIndices[idx]], fcol[i]);
|
||||
Vertex(verts[boxIndices[idx]], fcol[i]);
|
||||
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)
|
||||
{
|
||||
begin(DebugDrawPrimitives.LINES, lineWidth);
|
||||
appendArc(x0, y0, z0, x1, y1, z1, h, as0, as1, col);
|
||||
end();
|
||||
Begin(DebugDrawPrimitives.LINES, lineWidth);
|
||||
AppendArc(x0, y0, z0, x1, y1, z1, h, as0, as1, col);
|
||||
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);
|
||||
appendCircle(x, y, z, r, col);
|
||||
end();
|
||||
Begin(DebugDrawPrimitives.LINES, lineWidth);
|
||||
AppendCircle(x, y, z, r, col);
|
||||
End();
|
||||
}
|
||||
|
||||
private bool circleInit = false;
|
||||
|
@ -229,7 +229,7 @@ public class DebugDraw
|
|||
private float[] _viewMatrix = 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)
|
||||
{
|
||||
|
@ -244,8 +244,8 @@ public class DebugDraw
|
|||
|
||||
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[i * 2 + 0] * r, y, z + circeDir[i * 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,21 +253,21 @@ public class DebugDraw
|
|||
private static readonly float PAD = 0.05f;
|
||||
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 dy = y1 - y0;
|
||||
float dz = z1 - z0;
|
||||
float len = (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
|
||||
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)
|
||||
{
|
||||
float u = PAD + i * ARC_PTS_SCALE;
|
||||
Vector3f pt = new Vector3f();
|
||||
evalArc(x0, y0, z0, dx, dy, dz, len * h, u, ref pt);
|
||||
vertex(prev.x, prev.y, prev.z, col);
|
||||
vertex(pt.x, pt.y, pt.z, col);
|
||||
EvalArc(x0, y0, z0, dx, dy, dz, len * h, u, ref pt);
|
||||
Vertex(prev.x, prev.y, prev.z, col);
|
||||
Vertex(pt.x, pt.y, pt.z, col);
|
||||
prev.x = pt.x;
|
||||
prev.y = pt.y;
|
||||
prev.z = pt.z;
|
||||
|
@ -278,64 +278,64 @@ public class DebugDraw
|
|||
{
|
||||
Vector3f p = 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 + 0.05f, ref q);
|
||||
appendArrowHead(p, q, as0, col);
|
||||
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);
|
||||
AppendArrowHead(p, q, as0, col);
|
||||
}
|
||||
|
||||
if (as1 > 0.001f)
|
||||
{
|
||||
Vector3f p = 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 + 0.05f), ref q);
|
||||
appendArrowHead(p, q, as1, col);
|
||||
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);
|
||||
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.y = y0 + dy * u + h * (1 - (u * 2 - 1) * (u * 2 - 1));
|
||||
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);
|
||||
appendCross(x, y, z, size, col);
|
||||
end();
|
||||
Begin(DebugDrawPrimitives.LINES, lineWidth);
|
||||
AppendCross(x, y, z, size, col);
|
||||
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, y - s, z, col);
|
||||
vertex(x, y + s, z, col);
|
||||
vertex(x, y, z - s, col);
|
||||
vertex(x, y, z + s, 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, 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);
|
||||
appendBox(minx, miny, minz, maxx, maxy, maxz, fcol);
|
||||
end();
|
||||
Begin(DebugDrawPrimitives.QUADS);
|
||||
AppendBox(minx, miny, minz, maxx, maxy, maxz, fcol);
|
||||
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);
|
||||
appendCylinder(minx, miny, minz, maxx, maxy, maxz, col);
|
||||
end();
|
||||
Begin(DebugDrawPrimitives.TRIS);
|
||||
AppendCylinder(minx, miny, minz, maxx, maxy, maxz, col);
|
||||
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 cz = (maxz + minz) / 2;
|
||||
|
@ -345,57 +345,57 @@ public class DebugDraw
|
|||
for (int i = 2; i < CYLINDER_NUM_SEG; ++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[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[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[c * 2 + 0] * rx, miny, cz + cylinderDir[c * 2 + 1] * rz, col2);
|
||||
}
|
||||
|
||||
for (int i = 2; i < CYLINDER_NUM_SEG; ++i)
|
||||
{
|
||||
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[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[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[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++)
|
||||
{
|
||||
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, 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[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[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[i * 2 + 0] * rx, maxy, cz + cylinderDir[i * 2 + 1] * rz, col);
|
||||
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[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)
|
||||
{
|
||||
begin(DebugDrawPrimitives.LINES, lineWidth);
|
||||
appendArrow(x0, y0, z0, x1, y1, z1, as0, as1, col);
|
||||
end();
|
||||
Begin(DebugDrawPrimitives.LINES, lineWidth);
|
||||
AppendArrow(x0, y0, z0, x1, y1, z1, as0, as1, col);
|
||||
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(x1, y1, z1, col);
|
||||
Vertex(x0, y0, z0, col);
|
||||
Vertex(x1, y1, z1, col);
|
||||
|
||||
// End arrows
|
||||
Vector3f p = Vector3f.Of(x0, y0, z0);
|
||||
Vector3f q = Vector3f.Of(x1, y1, z1);
|
||||
if (as0 > 0.001f)
|
||||
appendArrowHead(p, q, as0, col);
|
||||
AppendArrowHead(p, q, as0, col);
|
||||
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;
|
||||
if (vdistSqr(p, q) < eps * eps)
|
||||
if (VdistSqr(p, q) < eps * eps)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -403,29 +403,29 @@ public class DebugDraw
|
|||
Vector3f ax = new Vector3f();
|
||||
Vector3f ay = Vector3f.Of(0, 1, 0);
|
||||
Vector3f az = new Vector3f();
|
||||
vsub(ref az, q, p);
|
||||
vnormalize(ref az);
|
||||
vcross(ref ax, ay, az);
|
||||
vcross(ref ay, az, ax);
|
||||
vnormalize(ref ay);
|
||||
Vsub(ref az, q, p);
|
||||
Vnormalize(ref az);
|
||||
Vcross(ref ax, ay, az);
|
||||
Vcross(ref ay, az, ax);
|
||||
Vnormalize(ref ay);
|
||||
|
||||
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 + 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.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, 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, 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);
|
||||
}
|
||||
|
||||
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.y = v1.z * v2.x - v1.x * v2.z;
|
||||
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));
|
||||
v.x *= d;
|
||||
|
@ -433,14 +433,14 @@ public class DebugDraw
|
|||
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.y = v1.y - v2.y;
|
||||
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 y = v1.y - v2.y;
|
||||
|
@ -448,49 +448,49 @@ public class DebugDraw
|
|||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
// public static int areaToCol(int area) {
|
||||
// public static int AreaToCol(int area) {
|
||||
// if (area == 0) {
|
||||
// return duRGBA(0, 192, 255, 255);
|
||||
// return DuRGBA(0, 192, 255, 255);
|
||||
// } else {
|
||||
// return duIntToCol(area, 255);
|
||||
// return DuIntToCol(area, 255);
|
||||
// }
|
||||
// }
|
||||
|
||||
public static int areaToCol(int area)
|
||||
public static int AreaToCol(int area)
|
||||
{
|
||||
switch (area)
|
||||
{
|
||||
// Ground (0) : light blue
|
||||
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WALKABLE:
|
||||
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND:
|
||||
return duRGBA(0, 192, 255, 255);
|
||||
return DuRGBA(0, 192, 255, 255);
|
||||
// Water : blue
|
||||
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER:
|
||||
return duRGBA(0, 0, 255, 255);
|
||||
return DuRGBA(0, 0, 255, 255);
|
||||
// Road : brown
|
||||
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD:
|
||||
return duRGBA(50, 20, 12, 255);
|
||||
return DuRGBA(50, 20, 12, 255);
|
||||
// Door : cyan
|
||||
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_DOOR:
|
||||
return duRGBA(0, 255, 255, 255);
|
||||
return DuRGBA(0, 255, 255, 255);
|
||||
// Grass : green
|
||||
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GRASS:
|
||||
return duRGBA(0, 255, 0, 255);
|
||||
return DuRGBA(0, 255, 0, 255);
|
||||
// Jump : yellow
|
||||
case SampleAreaModifications.SAMPLE_POLYAREA_TYPE_JUMP:
|
||||
return duRGBA(255, 255, 0, 255);
|
||||
return DuRGBA(255, 255, 0, 255);
|
||||
// Unexpected : red
|
||||
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);
|
||||
}
|
||||
|
||||
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 ga = (ca >> 8) & 0xff;
|
||||
|
@ -505,134 +505,134 @@ public class DebugDraw
|
|||
int g = (ga * (255 - u) + gb * u) / 255;
|
||||
int b = (ba * (255 - u) + bb * 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;
|
||||
}
|
||||
|
||||
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 g = bit(i, 2) + bit(i, 4) * 2 + 1;
|
||||
int b = bit(i, 0) + bit(i, 5) * 2 + 1;
|
||||
return duRGBA(r * 63, g * 63, b * 63, a);
|
||||
int r = Bit(i, 1) + Bit(i, 3) * 2 + 1;
|
||||
int g = Bit(i, 2) + Bit(i, 4) * 2 + 1;
|
||||
int b = Bit(i, 0) + Bit(i, 5) * 2 + 1;
|
||||
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[1] = duMultCol(colSide, 140);
|
||||
colors[2] = duMultCol(colSide, 165);
|
||||
colors[3] = duMultCol(colSide, 165);
|
||||
colors[4] = duMultCol(colSide, 217);
|
||||
colors[5] = duMultCol(colSide, 217);
|
||||
colors[0] = DuMultCol(colTop, 250);
|
||||
colors[1] = DuMultCol(colSide, 140);
|
||||
colors[2] = DuMultCol(colSide, 165);
|
||||
colors[3] = DuMultCol(colSide, 165);
|
||||
colors[4] = 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 g = (col >> 8) & 0xff;
|
||||
int b = (col >> 16) & 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);
|
||||
}
|
||||
|
||||
public static int duDarkenCol(int col)
|
||||
public static int DuDarkenCol(int col)
|
||||
{
|
||||
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);
|
||||
getOpenGlDraw().projectionMatrix(_projectionMatrix);
|
||||
updateFrustum();
|
||||
GLU.GlhPerspectivef2(_projectionMatrix, fovy, aspect, near, far);
|
||||
GetOpenGlDraw().ProjectionMatrix(_projectionMatrix);
|
||||
UpdateFrustum();
|
||||
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[] ry = GLU.build_4x4_rotation_matrix(cameraEulers[1], 0, 1, 0);
|
||||
float[] r = GLU.mul(rx, ry);
|
||||
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[] r = GLU.Mul(rx, ry);
|
||||
float[] t = new float[16];
|
||||
t[0] = t[5] = t[10] = t[15] = 1;
|
||||
t[12] = -cameraPos.x;
|
||||
t[13] = -cameraPos.y;
|
||||
t[14] = -cameraPos.z;
|
||||
_viewMatrix = GLU.mul(r, t);
|
||||
getOpenGlDraw().viewMatrix(_viewMatrix);
|
||||
updateFrustum();
|
||||
_viewMatrix = GLU.Mul(r, t);
|
||||
GetOpenGlDraw().ViewMatrix(_viewMatrix);
|
||||
UpdateFrustum();
|
||||
return _viewMatrix;
|
||||
}
|
||||
|
||||
private OpenGLDraw getOpenGlDraw()
|
||||
private OpenGLDraw GetOpenGlDraw()
|
||||
{
|
||||
return openGlDraw;
|
||||
}
|
||||
|
||||
private void updateFrustum()
|
||||
private void UpdateFrustum()
|
||||
{
|
||||
float[] vpm = GLU.mul(_projectionMatrix, _viewMatrix);
|
||||
float[] vpm = GLU.Mul(_projectionMatrix, _viewMatrix);
|
||||
// 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]);
|
||||
// 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]);
|
||||
// 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]);
|
||||
// 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]);
|
||||
// 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]);
|
||||
// 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]);
|
||||
}
|
||||
|
||||
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);
|
||||
if (length != 0)
|
||||
|
@ -647,7 +647,7 @@ public class DebugDraw
|
|||
return new float[] { px, py, pz, pw };
|
||||
}
|
||||
|
||||
public bool frustumTest(float[] bounds)
|
||||
public bool FrustumTest(float[] bounds)
|
||||
{
|
||||
foreach (float[] plane in frustumPlanes)
|
||||
{
|
||||
|
@ -699,8 +699,8 @@ public class DebugDraw
|
|||
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 });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ public class GLCheckerTexture
|
|||
_gl = gl;
|
||||
}
|
||||
|
||||
public void release()
|
||||
public void Release()
|
||||
{
|
||||
if (m_texId != 0)
|
||||
{
|
||||
|
@ -40,13 +40,13 @@ public class GLCheckerTexture
|
|||
}
|
||||
}
|
||||
|
||||
public void bind()
|
||||
public void Bind()
|
||||
{
|
||||
if (m_texId == 0)
|
||||
{
|
||||
// Create checker pattern.
|
||||
int col0 = DebugDraw.duRGBA(215, 215, 215, 255);
|
||||
int col1 = DebugDraw.duRGBA(255, 255, 255, 255);
|
||||
int col0 = DebugDraw.DuRGBA(215, 215, 215, 255);
|
||||
int col1 = DebugDraw.DuRGBA(255, 255, 255, 255);
|
||||
uint TSIZE = 64;
|
||||
int[] data = new int[TSIZE * TSIZE];
|
||||
|
||||
|
|
|
@ -24,24 +24,24 @@ namespace DotRecast.Recast.Demo.Draw;
|
|||
|
||||
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];
|
||||
glhPerspectivef2(projectionMatrix, fovy, aspect, near, far);
|
||||
//glLoadMatrixf(projectionMatrix);
|
||||
GlhPerspectivef2(projectionMatrix, fovy, aspect, near, far);
|
||||
//GlLoadMatrixf(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 ymax, xmax;
|
||||
ymax = (float)(znear * Math.Tan(fovyInDegrees * Math.PI / 360.0));
|
||||
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 temp, temp2, temp3, temp4;
|
||||
|
@ -67,7 +67,7 @@ public class GLU
|
|||
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
|
||||
float[] m = new float[16], A = new float[16];
|
||||
|
@ -76,7 +76,7 @@ public class GLU
|
|||
// and store in A[16]
|
||||
MultiplyMatrices4by4OpenGL_FLOAT(A, projection, modelview);
|
||||
// Now compute the inverse of matrix A
|
||||
if (glhInvertMatrixf2(A, m) == 0)
|
||||
if (GlhInvertMatrixf2(A, m) == 0)
|
||||
return 0;
|
||||
// Transformation of normalized coordinates between -1 and 1
|
||||
@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
|
||||
static int glhInvertMatrixf2(float[] m, float[] @out)
|
||||
static int GlhInvertMatrixf2(float[] m, float[] @out)
|
||||
{
|
||||
float[][] wtmp = ArrayUtils.Of<float>(4, 8);
|
||||
float m0, m1, m2, m3, s;
|
||||
|
@ -370,7 +370,7 @@ public class GLU
|
|||
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];
|
||||
a = (float)(a * Math.PI / 180.0); // convert to radians
|
||||
|
@ -408,7 +408,7 @@ public class GLU
|
|||
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 m01 = left[1] * right[0] + left[5] * right[1] + left[9] * right[2] + left[13] * right[3];
|
||||
|
|
|
@ -35,7 +35,7 @@ public class ModernOpenGLDraw : OpenGLDraw
|
|||
_gl = gl;
|
||||
}
|
||||
|
||||
public unsafe void init()
|
||||
public unsafe void Init()
|
||||
{
|
||||
string SHADER_VERSION = "#version 400\n";
|
||||
string vertex_shader = SHADER_VERSION + "uniform mat4 ProjMtx;\n" //
|
||||
|
@ -153,7 +153,7 @@ public class ModernOpenGLDraw : OpenGLDraw
|
|||
_gl.BindBuffer(GLEnum.ElementArrayBuffer, 0);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
public void Clear()
|
||||
{
|
||||
_gl.ClearColor(0.3f, 0.3f, 0.32f, 1.0f);
|
||||
_gl.Clear((uint)GLEnum.ColorBufferBit | (uint)GLEnum.DepthBufferBit);
|
||||
|
@ -164,7 +164,7 @@ public class ModernOpenGLDraw : OpenGLDraw
|
|||
_gl.Enable(GLEnum.CullFace);
|
||||
}
|
||||
|
||||
public void begin(DebugDrawPrimitives prim, float size)
|
||||
public void Begin(DebugDrawPrimitives prim, float size)
|
||||
{
|
||||
currentPrim = prim;
|
||||
vertices.Clear();
|
||||
|
@ -172,7 +172,7 @@ public class ModernOpenGLDraw : OpenGLDraw
|
|||
_gl.PointSize(size);
|
||||
}
|
||||
|
||||
public unsafe void end()
|
||||
public unsafe void End()
|
||||
{
|
||||
if (0 >= vertices.Count)
|
||||
{
|
||||
|
@ -189,8 +189,8 @@ public class ModernOpenGLDraw : OpenGLDraw
|
|||
_gl.BindVertexArray(vao);
|
||||
_gl.BindBuffer(GLEnum.ArrayBuffer, vbo);
|
||||
_gl.BindBuffer(GLEnum.ElementArrayBuffer, ebo);
|
||||
// glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_BUFFER, GL_STREAM_DRAW);
|
||||
// glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_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);
|
||||
|
||||
uint vboSize = (uint)vertices.Count * 24;
|
||||
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* 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())
|
||||
{
|
||||
System.Buffer.MemoryCopy(v, pVerts, vboSize, vboSize);
|
||||
|
@ -241,7 +241,7 @@ public class ModernOpenGLDraw : OpenGLDraw
|
|||
}
|
||||
if (_texture != null)
|
||||
{
|
||||
_texture.bind();
|
||||
_texture.Bind();
|
||||
_gl.Uniform1(uniformUseTexture, 1.0f);
|
||||
}
|
||||
else
|
||||
|
@ -276,63 +276,63 @@ public class ModernOpenGLDraw : OpenGLDraw
|
|||
_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));
|
||||
}
|
||||
|
||||
public void vertex(float[] pos, int color)
|
||||
public void Vertex(float[] pos, int 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));
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public void depthMask(bool state)
|
||||
public void DepthMask(bool 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;
|
||||
if (_texture != null)
|
||||
{
|
||||
_texture.bind();
|
||||
_texture.Bind();
|
||||
}
|
||||
}
|
||||
|
||||
public void projectionMatrix(float[] projectionMatrix)
|
||||
public void ProjectionMatrix(float[] projectionMatrix)
|
||||
{
|
||||
this._projectionMatrix = projectionMatrix;
|
||||
}
|
||||
|
||||
public void viewMatrix(float[] viewMatrix)
|
||||
public void ViewMatrix(float[] viewMatrix)
|
||||
{
|
||||
this._viewMatrix = viewMatrix;
|
||||
}
|
||||
|
||||
public void fog(float start, float end)
|
||||
public void Fog(float start, float end)
|
||||
{
|
||||
fogStart = start;
|
||||
fogEnd = end;
|
||||
}
|
||||
|
||||
public void fog(bool state)
|
||||
public void Fog(bool state)
|
||||
{
|
||||
fogEnabled = state;
|
||||
}
|
||||
|
|
|
@ -39,45 +39,45 @@ public class NavMeshRenderer
|
|||
this.debugDraw = debugDraw;
|
||||
}
|
||||
|
||||
public RecastDebugDraw getDebugDraw()
|
||||
public RecastDebugDraw GetDebugDraw()
|
||||
{
|
||||
return debugDraw;
|
||||
}
|
||||
|
||||
public void render(Sample sample)
|
||||
public void Render(Sample sample)
|
||||
{
|
||||
if (sample == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NavMeshQuery navQuery = sample.getNavMeshQuery();
|
||||
DemoInputGeomProvider geom = sample.getInputGeom();
|
||||
IList<RecastBuilderResult> rcBuilderResults = sample.getRecastResults();
|
||||
NavMesh navMesh = sample.getNavMesh();
|
||||
RcSettingsView rcSettingsView = sample.getSettingsUI();
|
||||
debugDraw.fog(true);
|
||||
debugDraw.depthMask(true);
|
||||
var drawMode = rcSettingsView.getDrawMode();
|
||||
NavMeshQuery navQuery = sample.GetNavMeshQuery();
|
||||
DemoInputGeomProvider geom = sample.GetInputGeom();
|
||||
IList<RecastBuilderResult> rcBuilderResults = sample.GetRecastResults();
|
||||
NavMesh navMesh = sample.GetNavMesh();
|
||||
RcSettingsView rcSettingsView = sample.GetSettingsUI();
|
||||
debugDraw.Fog(true);
|
||||
debugDraw.DepthMask(true);
|
||||
var drawMode = rcSettingsView.GetDrawMode();
|
||||
|
||||
float texScale = 1.0f / (rcSettingsView.getCellSize() * 10.0f);
|
||||
float m_agentMaxSlope = rcSettingsView.getAgentMaxSlope();
|
||||
float texScale = 1.0f / (rcSettingsView.GetCellSize() * 10.0f);
|
||||
float m_agentMaxSlope = rcSettingsView.GetAgentMaxSlope();
|
||||
|
||||
if (drawMode != DrawMode.DRAWMODE_NAVMESH_TRANS)
|
||||
{
|
||||
// Draw mesh
|
||||
if (geom != null)
|
||||
{
|
||||
debugDraw.debugDrawTriMeshSlope(geom.vertices, geom.faces, geom.normals, m_agentMaxSlope, texScale);
|
||||
drawOffMeshConnections(geom, false);
|
||||
debugDraw.DebugDrawTriMeshSlope(geom.vertices, geom.faces, geom.normals, m_agentMaxSlope, texScale);
|
||||
DrawOffMeshConnections(geom, false);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.fog(false);
|
||||
debugDraw.depthMask(false);
|
||||
debugDraw.Fog(false);
|
||||
debugDraw.DepthMask(false);
|
||||
if (geom != null)
|
||||
{
|
||||
drawGeomBounds(geom);
|
||||
DrawGeomBounds(geom);
|
||||
}
|
||||
|
||||
if (navMesh != null && navQuery != null
|
||||
|
@ -88,221 +88,221 @@ public class NavMeshRenderer
|
|||
{
|
||||
if (drawMode != DrawMode.DRAWMODE_NAVMESH_INVIS)
|
||||
{
|
||||
debugDraw.debugDrawNavMeshWithClosedList(navMesh, navQuery, navMeshDrawFlags);
|
||||
debugDraw.DebugDrawNavMeshWithClosedList(navMesh, navQuery, navMeshDrawFlags);
|
||||
}
|
||||
|
||||
if (drawMode == DrawMode.DRAWMODE_NAVMESH_BVTREE)
|
||||
{
|
||||
debugDraw.debugDrawNavMeshBVTree(navMesh);
|
||||
debugDraw.DebugDrawNavMeshBVTree(navMesh);
|
||||
}
|
||||
|
||||
if (drawMode == DrawMode.DRAWMODE_NAVMESH_PORTALS)
|
||||
{
|
||||
debugDraw.debugDrawNavMeshPortals(navMesh);
|
||||
debugDraw.DebugDrawNavMeshPortals(navMesh);
|
||||
}
|
||||
|
||||
if (drawMode == DrawMode.DRAWMODE_NAVMESH_NODES)
|
||||
{
|
||||
debugDraw.debugDrawNavMeshNodes(navQuery);
|
||||
debugDraw.debugDrawNavMeshPolysWithFlags(navMesh, SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED,
|
||||
DebugDraw.duRGBA(0, 0, 0, 128));
|
||||
debugDraw.DebugDrawNavMeshNodes(navQuery);
|
||||
debugDraw.DebugDrawNavMeshPolysWithFlags(navMesh, SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED,
|
||||
DebugDraw.DuRGBA(0, 0, 0, 128));
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.depthMask(true);
|
||||
debugDraw.DepthMask(true);
|
||||
|
||||
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.debugDrawHeightfieldSolid(rcBuilderResult.getSolidHeightfield());
|
||||
debugDraw.fog(false);
|
||||
debugDraw.Fog(true);
|
||||
debugDraw.DebugDrawHeightfieldSolid(rcBuilderResult.GetSolidHeightfield());
|
||||
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.debugDrawHeightfieldWalkable(rcBuilderResult.getSolidHeightfield());
|
||||
debugDraw.fog(false);
|
||||
debugDraw.Fog(true);
|
||||
debugDraw.DebugDrawHeightfieldWalkable(rcBuilderResult.GetSolidHeightfield());
|
||||
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.debugDrawRawContours(rcBuilderResult.getContourSet(), 1f);
|
||||
debugDraw.depthMask(true);
|
||||
debugDraw.DepthMask(false);
|
||||
debugDraw.DebugDrawRawContours(rcBuilderResult.GetContourSet(), 1f);
|
||||
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.debugDrawRawContours(rcBuilderResult.getContourSet(), 0.5f);
|
||||
debugDraw.debugDrawContours(rcBuilderResult.getContourSet());
|
||||
debugDraw.depthMask(true);
|
||||
debugDraw.DepthMask(false);
|
||||
debugDraw.DebugDrawRawContours(rcBuilderResult.GetContourSet(), 0.5f);
|
||||
debugDraw.DebugDrawContours(rcBuilderResult.GetContourSet());
|
||||
debugDraw.DepthMask(true);
|
||||
}
|
||||
|
||||
if (rcBuilderResult.getContourSet() != null && drawMode == DrawMode.DRAWMODE_CONTOURS)
|
||||
if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_CONTOURS)
|
||||
{
|
||||
debugDraw.depthMask(false);
|
||||
debugDraw.debugDrawContours(rcBuilderResult.getContourSet());
|
||||
debugDraw.depthMask(true);
|
||||
debugDraw.DepthMask(false);
|
||||
debugDraw.DebugDrawContours(rcBuilderResult.GetContourSet());
|
||||
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.depthMask(false);
|
||||
if (rcBuilderResult.getContourSet() != null)
|
||||
debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.GetCompactHeightfield());
|
||||
debugDraw.DepthMask(false);
|
||||
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.debugDrawPolyMesh(rcBuilderResult.getMesh());
|
||||
debugDraw.depthMask(true);
|
||||
debugDraw.DepthMask(false);
|
||||
debugDraw.DebugDrawPolyMesh(rcBuilderResult.GetMesh());
|
||||
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.debugDrawPolyMeshDetail(rcBuilderResult.getMeshDetail());
|
||||
debugDraw.depthMask(true);
|
||||
debugDraw.DepthMask(false);
|
||||
debugDraw.DebugDrawPolyMeshDetail(rcBuilderResult.GetMeshDetail());
|
||||
debugDraw.DepthMask(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (geom != null)
|
||||
{
|
||||
drawConvexVolumes(geom);
|
||||
DrawConvexVolumes(geom);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawGeomBounds(DemoInputGeomProvider geom)
|
||||
private void DrawGeomBounds(DemoInputGeomProvider geom)
|
||||
{
|
||||
// Draw bounds
|
||||
Vector3f bmin = geom.getMeshBoundsMin();
|
||||
Vector3f bmax = geom.getMeshBoundsMax();
|
||||
debugDraw.debugDrawBoxWire(bmin.x, bmin.y, bmin.z, bmax.x, bmax.y, bmax.z,
|
||||
DebugDraw.duRGBA(255, 255, 255, 128), 1.0f);
|
||||
debugDraw.begin(DebugDrawPrimitives.POINTS, 5.0f);
|
||||
debugDraw.vertex(bmin.x, bmin.y, bmin.z, DebugDraw.duRGBA(255, 255, 255, 128));
|
||||
debugDraw.end();
|
||||
Vector3f bmin = geom.GetMeshBoundsMin();
|
||||
Vector3f bmax = geom.GetMeshBoundsMax();
|
||||
debugDraw.DebugDrawBoxWire(bmin.x, bmin.y, bmin.z, bmax.x, bmax.y, bmax.z,
|
||||
DebugDraw.DuRGBA(255, 255, 255, 128), 1.0f);
|
||||
debugDraw.Begin(DebugDrawPrimitives.POINTS, 5.0f);
|
||||
debugDraw.Vertex(bmin.x, bmin.y, bmin.z, DebugDraw.DuRGBA(255, 255, 255, 128));
|
||||
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 baseColor = DebugDraw.duRGBA(0, 0, 0, 64);
|
||||
debugDraw.depthMask(false);
|
||||
int conColor = DebugDraw.DuRGBA(192, 0, 128, 192);
|
||||
int baseColor = DebugDraw.DuRGBA(0, 0, 0, 64);
|
||||
debugDraw.DepthMask(false);
|
||||
|
||||
debugDraw.begin(DebugDrawPrimitives.LINES, 2.0f);
|
||||
foreach (DemoOffMeshConnection con in geom.getOffMeshConnections())
|
||||
debugDraw.Begin(DebugDrawPrimitives.LINES, 2.0f);
|
||||
foreach (DemoOffMeshConnection con in geom.GetOffMeshConnections())
|
||||
{
|
||||
float[] v = con.verts;
|
||||
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], 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] + 0.2f, v[5], baseColor);
|
||||
debugDraw.Vertex(v[3], v[4], 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[3], v[4] + 0.1f, v[5], 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);
|
||||
|
||||
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)
|
||||
{
|
||||
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]);
|
||||
|
||||
debugDraw.vertex(vol.verts[0], vol.hmax, vol.verts[2], col);
|
||||
debugDraw.vertex(vb.x, vol.hmax, vb.z, col);
|
||||
debugDraw.vertex(va.x, vol.hmax, va.z, col);
|
||||
debugDraw.Vertex(vol.verts[0], vol.hmax, vol.verts[2], col);
|
||||
debugDraw.Vertex(vb.x, vol.hmax, vb.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.hmax, va.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.hmax, va.z, col);
|
||||
debugDraw.Vertex(vb.x, vol.hmax, vb.z, 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.hmin, vb.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.hmin, vb.z, DebugDraw.DuDarkenCol(col));
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.end();
|
||||
debugDraw.End();
|
||||
|
||||
debugDraw.begin(DebugDrawPrimitives.LINES, 2.0f);
|
||||
foreach (ConvexVolume vol in geom.convexVolumes())
|
||||
debugDraw.Begin(DebugDrawPrimitives.LINES, 2.0f);
|
||||
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)
|
||||
{
|
||||
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]);
|
||||
debugDraw.vertex(va.x, vol.hmin, va.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(vb.x, vol.hmax, vb.z, 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.hmin, va.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(vb.x, vol.hmax, vb.z, col);
|
||||
debugDraw.Vertex(va.x, vol.hmin, va.z, DebugDraw.DuDarkenCol(col));
|
||||
debugDraw.Vertex(va.x, vol.hmax, va.z, col);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.end();
|
||||
debugDraw.End();
|
||||
|
||||
debugDraw.begin(DebugDrawPrimitives.POINTS, 3.0f);
|
||||
foreach (ConvexVolume vol in geom.convexVolumes())
|
||||
debugDraw.Begin(DebugDrawPrimitives.POINTS, 3.0f);
|
||||
foreach (ConvexVolume vol in geom.ConvexVolumes())
|
||||
{
|
||||
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)
|
||||
{
|
||||
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.hmax, 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.hmax, vol.verts[j + 2], col);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.end();
|
||||
debugDraw.End();
|
||||
|
||||
debugDraw.depthMask(true);
|
||||
debugDraw.DepthMask(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,32 +5,32 @@ namespace DotRecast.Recast.Demo.Draw;
|
|||
|
||||
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(Vector3f pos, int color);
|
||||
void Vertex(float[] 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);
|
||||
}
|
|
@ -46,7 +46,7 @@ public struct OpenGLVertex
|
|||
this.color = color;
|
||||
}
|
||||
|
||||
public void store(BinaryWriter writer)
|
||||
public void Store(BinaryWriter writer)
|
||||
{
|
||||
// writer.Write(BitConverter.GetBytes(x));
|
||||
// writer.Write(BitConverter.GetBytes(y));
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -39,11 +39,11 @@ public class DemoInputGeomProvider : InputGeomProvider
|
|||
private readonly TriMesh _mesh;
|
||||
|
||||
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];
|
||||
for (int i = 0; i < faces.Length; i++)
|
||||
|
@ -54,7 +54,7 @@ public class DemoInputGeomProvider : InputGeomProvider
|
|||
return faces;
|
||||
}
|
||||
|
||||
private static float[] mapVertices(List<float> vertexPositions)
|
||||
private static float[] MapVertices(List<float> vertexPositions)
|
||||
{
|
||||
float[] vertices = new float[vertexPositions.Count];
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
|
@ -70,31 +70,31 @@ public class DemoInputGeomProvider : InputGeomProvider
|
|||
this.vertices = vertices;
|
||||
this.faces = faces;
|
||||
normals = new float[faces.Length];
|
||||
calculateNormals();
|
||||
CalculateNormals();
|
||||
bmin = Vector3f.Zero;
|
||||
bmax = Vector3f.Zero;
|
||||
RecastVectors.copy(ref bmin, vertices, 0);
|
||||
RecastVectors.copy(ref bmax, vertices, 0);
|
||||
RecastVectors.Copy(ref bmin, vertices, 0);
|
||||
RecastVectors.Copy(ref bmax, vertices, 0);
|
||||
for (int i = 1; i < vertices.Length / 3; i++)
|
||||
{
|
||||
RecastVectors.min(ref bmin, vertices, i * 3);
|
||||
RecastVectors.max(ref bmax, vertices, i * 3);
|
||||
RecastVectors.Min(ref bmin, vertices, i * 3);
|
||||
RecastVectors.Max(ref bmax, vertices, i * 3);
|
||||
}
|
||||
|
||||
_mesh = new TriMesh(vertices, faces);
|
||||
}
|
||||
|
||||
public Vector3f getMeshBoundsMin()
|
||||
public Vector3f GetMeshBoundsMin()
|
||||
{
|
||||
return bmin;
|
||||
}
|
||||
|
||||
public Vector3f getMeshBoundsMax()
|
||||
public Vector3f GetMeshBoundsMax()
|
||||
{
|
||||
return bmax;
|
||||
}
|
||||
|
||||
public void calculateNormals()
|
||||
public void CalculateNormals()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public IEnumerable<TriMesh> meshes()
|
||||
public IEnumerable<TriMesh> Meshes()
|
||||
{
|
||||
return ImmutableArray.Create(_mesh);
|
||||
}
|
||||
|
||||
public List<DemoOffMeshConnection> getOffMeshConnections()
|
||||
public List<DemoOffMeshConnection> GetOffMeshConnections()
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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 : 확인 필요
|
||||
}
|
||||
|
||||
public float? raycastMesh(Vector3f src, Vector3f dst)
|
||||
public float? RaycastMesh(Vector3f src, Vector3f dst)
|
||||
{
|
||||
// Prune hit ray.
|
||||
float[] btminmax = Intersections.intersectSegmentAABB(src, dst, bmin, bmax);
|
||||
float[] btminmax = Intersections.IntersectSegmentAABB(src, dst, bmin, bmax);
|
||||
if (null == btminmax)
|
||||
{
|
||||
return null;
|
||||
|
@ -166,7 +166,7 @@ public class DemoInputGeomProvider : InputGeomProvider
|
|||
q[0] = src.x + (dst.x - src.x) * 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)
|
||||
{
|
||||
return null;
|
||||
|
@ -194,7 +194,7 @@ public class DemoInputGeomProvider : InputGeomProvider
|
|||
vertices[tris[j + 2] * 3 + 1],
|
||||
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 (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();
|
||||
volume.verts = verts;
|
||||
|
@ -221,7 +221,7 @@ public class DemoInputGeomProvider : InputGeomProvider
|
|||
_convexVolumes.Add(volume);
|
||||
}
|
||||
|
||||
public void clearConvexVolumes()
|
||||
public void ClearConvexVolumes()
|
||||
{
|
||||
_convexVolumes.Clear();
|
||||
}
|
||||
|
|
|
@ -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.y += scrollZoom * 2.0f * modelviewMatrix[6];
|
||||
cameraPos.z += scrollZoom * 2.0f * modelviewMatrix[10];
|
||||
|
@ -168,7 +168,7 @@ public class RecastDemo
|
|||
|
||||
if (pan)
|
||||
{
|
||||
float[] modelviewMatrix = dd.viewMatrix(cameraPos, cameraEulers);
|
||||
float[] modelviewMatrix = dd.ViewMatrix(cameraPos, cameraEulers);
|
||||
cameraPos.x = origCameraPos.x;
|
||||
cameraPos.y = origCameraPos.y;
|
||||
cameraPos.z = origCameraPos.z;
|
||||
|
@ -286,7 +286,7 @@ public class RecastDemo
|
|||
|
||||
// // -- move somewhere else:
|
||||
// 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.MakeContextCurrent(window);
|
||||
//}
|
||||
|
@ -296,35 +296,35 @@ public class RecastDemo
|
|||
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);
|
||||
toolsUI.setEnabled(true);
|
||||
toolsUI.SetEnabled(true);
|
||||
return geom;
|
||||
}
|
||||
|
||||
private void loadNavMesh(FileStream file, string filename)
|
||||
private void LoadNavMesh(FileStream file, string filename)
|
||||
{
|
||||
NavMesh mesh = null;
|
||||
if (filename.EndsWith(".zip") || filename.EndsWith(".bytes"))
|
||||
{
|
||||
UnityAStarPathfindingImporter importer = new UnityAStarPathfindingImporter();
|
||||
mesh = importer.load(file)[0];
|
||||
mesh = importer.Load(file)[0];
|
||||
}
|
||||
else if (filename.EndsWith(".bin") || filename.EndsWith(".navmesh"))
|
||||
{
|
||||
MeshSetReader reader = new MeshSetReader();
|
||||
using (var fis = new BinaryReader(file))
|
||||
{
|
||||
mesh = reader.read(fis, 6);
|
||||
mesh = reader.Read(fis, 6);
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh != null)
|
||||
{
|
||||
//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);
|
||||
renderer = new NavMeshRenderer(dd);
|
||||
|
||||
dd.init(camr);
|
||||
dd.Init(camr);
|
||||
|
||||
_imgui = new ImGuiController(_gl, window, _input);
|
||||
|
||||
|
@ -391,7 +391,7 @@ public class RecastDemo
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -409,31 +409,31 @@ public class RecastDemo
|
|||
var tempMoveAccel = keyboard.IsKeyPressed(Key.ShiftLeft) || keyboard.IsKeyPressed(Key.ShiftRight) ? 1.0f : -1f;
|
||||
|
||||
modState = keyboard.IsKeyPressed(Key.ControlLeft) || keyboard.IsKeyPressed(Key.ShiftRight) ? 1 : 0;
|
||||
_moveFront = clamp(_moveFront + tempMoveFront * 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);
|
||||
_moveRight = clamp(_moveRight + tempMoveRight * 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);
|
||||
_moveAccel = clamp(_moveAccel + tempMoveAccel * 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);
|
||||
_moveBack = Clamp(_moveBack + tempMoveBack * 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);
|
||||
_moveDown = Clamp(_moveDown + tempMoveDown * dt * 4.0f, 0, 2.0f);
|
||||
_moveAccel = Clamp(_moveAccel + tempMoveAccel * dt * 4.0f, 0, 2.0f);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWindowUpdate(double dt)
|
||||
{
|
||||
/*
|
||||
* try (MemoryStack stack = stackPush()) { int[] w = stack.mallocInt(1); int[] h =
|
||||
* stack.mallocInt(1); glfwGetWindowSize(win, w, h); width = w.x; height = h.x; }
|
||||
* try (MemoryStack stack = StackPush()) { int[] w = stack.MallocInt(1); int[] h =
|
||||
* 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 bmax = sample.getInputGeom().getMeshBoundsMax();
|
||||
int[] voxels = Recast.calcGridSize(bmin, bmax, settingsUI.getCellSize());
|
||||
settingsUI.setVoxels(voxels);
|
||||
settingsUI.setTiles(tileNavMeshBuilder.getTiles(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()));
|
||||
Vector3f bmin = sample.GetInputGeom().GetMeshBoundsMin();
|
||||
Vector3f bmax = sample.GetInputGeom().GetMeshBoundsMax();
|
||||
int[] voxels = Recast.CalcGridSize(bmin, bmax, settingsUI.GetCellSize());
|
||||
settingsUI.SetVoxels(voxels);
|
||||
settingsUI.SetTiles(tileNavMeshBuilder.GetTiles(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()));
|
||||
}
|
||||
|
||||
UpdateKeyboard((float)dt);
|
||||
|
@ -465,40 +465,40 @@ public class RecastDemo
|
|||
// Update sample simulation.
|
||||
float SIM_RATE = 20;
|
||||
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;
|
||||
while (timeAcc > DELTA_TIME)
|
||||
{
|
||||
timeAcc -= DELTA_TIME;
|
||||
if (simIter < 5 && sample != null)
|
||||
{
|
||||
toolsUI.handleUpdate(DELTA_TIME);
|
||||
toolsUI.HandleUpdate(DELTA_TIME);
|
||||
}
|
||||
|
||||
simIter++;
|
||||
}
|
||||
|
||||
if (settingsUI.isMeshInputTrigerred())
|
||||
if (settingsUI.IsMeshInputTrigerred())
|
||||
{
|
||||
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()) {
|
||||
// PointerBuffer aFilterPatterns = stack.mallocPointer(4);
|
||||
// aFilterPatterns.put(stack.UTF8("*.bin"));
|
||||
// aFilterPatterns.put(stack.UTF8("*.zip"));
|
||||
// aFilterPatterns.put(stack.UTF8("*.bytes"));
|
||||
// aFilterPatterns.put(stack.UTF8("*.navmesh"));
|
||||
// aFilterPatterns.flip();
|
||||
// string filename = TinyFileDialogs.tinyfd_openFileDialog("Open Nav Mesh File", "", aFilterPatterns,
|
||||
// try (MemoryStack stack = StackPush()) {
|
||||
// PointerBuffer aFilterPatterns = stack.MallocPointer(4);
|
||||
// aFilterPatterns.Put(stack.UTF8("*.bin"));
|
||||
// aFilterPatterns.Put(stack.UTF8("*.zip"));
|
||||
// aFilterPatterns.Put(stack.UTF8("*.bytes"));
|
||||
// aFilterPatterns.Put(stack.UTF8("*.navmesh"));
|
||||
// aFilterPatterns.Flip();
|
||||
// string filename = TinyFileDialogs.Tinyfd_openFileDialog("Open Nav Mesh File", "", aFilterPatterns,
|
||||
// "Nav Mesh File", false);
|
||||
// if (filename != null) {
|
||||
// File file = new File(filename);
|
||||
// if (file.exists()) {
|
||||
// if (file.Exists()) {
|
||||
// try {
|
||||
// loadNavMesh(file, filename);
|
||||
// LoadNavMesh(file, filename);
|
||||
// geom = null;
|
||||
// } catch (Exception 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)
|
||||
{
|
||||
float m_cellSize = settingsUI.getCellSize();
|
||||
float m_cellHeight = settingsUI.getCellHeight();
|
||||
float m_agentHeight = settingsUI.getAgentHeight();
|
||||
float m_agentRadius = settingsUI.getAgentRadius();
|
||||
float m_agentMaxClimb = settingsUI.getAgentMaxClimb();
|
||||
float m_agentMaxSlope = settingsUI.getAgentMaxSlope();
|
||||
int m_regionMinSize = settingsUI.getMinRegionSize();
|
||||
int m_regionMergeSize = settingsUI.getMergedRegionSize();
|
||||
float m_edgeMaxLen = settingsUI.getEdgeMaxLen();
|
||||
float m_edgeMaxError = settingsUI.getEdgeMaxError();
|
||||
int m_vertsPerPoly = settingsUI.getVertsPerPoly();
|
||||
float m_detailSampleDist = settingsUI.getDetailSampleDist();
|
||||
float m_detailSampleMaxError = settingsUI.getDetailSampleMaxError();
|
||||
int m_tileSize = settingsUI.getTileSize();
|
||||
float m_cellSize = settingsUI.GetCellSize();
|
||||
float m_cellHeight = settingsUI.GetCellHeight();
|
||||
float m_agentHeight = settingsUI.GetAgentHeight();
|
||||
float m_agentRadius = settingsUI.GetAgentRadius();
|
||||
float m_agentMaxClimb = settingsUI.GetAgentMaxClimb();
|
||||
float m_agentMaxSlope = settingsUI.GetAgentMaxSlope();
|
||||
int m_regionMinSize = settingsUI.GetMinRegionSize();
|
||||
int m_regionMergeSize = settingsUI.GetMergedRegionSize();
|
||||
float m_edgeMaxLen = settingsUI.GetEdgeMaxLen();
|
||||
float m_edgeMaxError = settingsUI.GetEdgeMaxError();
|
||||
int m_vertsPerPoly = settingsUI.GetVertsPerPoly();
|
||||
float m_detailSampleDist = settingsUI.GetDetailSampleDist();
|
||||
float m_detailSampleMaxError = settingsUI.GetDetailSampleMaxError();
|
||||
int m_tileSize = settingsUI.GetTileSize();
|
||||
long t = FrequencyWatch.Ticks;
|
||||
|
||||
Logger.Information($"build");
|
||||
|
||||
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_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist,
|
||||
m_detailSampleMaxError, settingsUI.isFilterLowHangingObstacles(), settingsUI.isFilterLedgeSpans(),
|
||||
settingsUI.isFilterWalkableLowHeightSpans(), m_tileSize);
|
||||
m_detailSampleMaxError, settingsUI.IsFilterLowHangingObstacles(), settingsUI.IsFilterLedgeSpans(),
|
||||
settingsUI.IsFilterWalkableLowHeightSpans(), m_tileSize);
|
||||
}
|
||||
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_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist,
|
||||
m_detailSampleMaxError, settingsUI.isFilterLowHangingObstacles(), settingsUI.isFilterLedgeSpans(),
|
||||
settingsUI.isFilterWalkableLowHeightSpans());
|
||||
m_detailSampleMaxError, settingsUI.IsFilterLowHangingObstacles(), settingsUI.IsFilterLedgeSpans(),
|
||||
settingsUI.IsFilterWalkableLowHeightSpans());
|
||||
}
|
||||
|
||||
sample.update(sample.getInputGeom(), buildResult.Item1, buildResult.Item2);
|
||||
sample.setChanged(false);
|
||||
settingsUI.setBuildTime((FrequencyWatch.Ticks - t) / TimeSpan.TicksPerMillisecond);
|
||||
//settingsUI.setBuildTelemetry(buildResult.Item1.Select(x => x.getTelemetry()).ToList());
|
||||
toolsUI.setSample(sample);
|
||||
sample.Update(sample.GetInputGeom(), buildResult.Item1, buildResult.Item2);
|
||||
sample.SetChanged(false);
|
||||
settingsUI.SetBuildTime((FrequencyWatch.Ticks - t) / TimeSpan.TicksPerMillisecond);
|
||||
//settingsUI.SetBuildTelemetry(buildResult.Item1.Select(x => x.GetTelemetry()).ToList());
|
||||
toolsUI.SetSample(sample);
|
||||
|
||||
Logger.Information($"build times");
|
||||
Logger.Information($"-----------------------------------------");
|
||||
var telemetries = buildResult.Item1
|
||||
.Select(x => x.getTelemetry())
|
||||
.Select(x => x.GetTelemetry())
|
||||
.SelectMany(x => x.ToList())
|
||||
.GroupBy(x => x.Item1)
|
||||
.ToImmutableSortedDictionary(x => x.Key, x => x.Sum(y => y.Item2));
|
||||
|
@ -574,35 +574,35 @@ public class RecastDemo
|
|||
|
||||
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], 1.0f, modelviewMatrix, projectionMatrix, viewport, ref rayEnd);
|
||||
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);
|
||||
|
||||
// Hit test mesh.
|
||||
DemoInputGeomProvider inputGeom = sample.getInputGeom();
|
||||
DemoInputGeomProvider inputGeom = sample.GetInputGeom();
|
||||
if (processHitTest && sample != null)
|
||||
{
|
||||
float? hit = 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 };
|
||||
Tool rayTool = toolsUI.getTool();
|
||||
vNormalize(rayDir);
|
||||
Tool rayTool = toolsUI.GetTool();
|
||||
VNormalize(rayDir);
|
||||
if (rayTool != null)
|
||||
{
|
||||
rayTool.handleClickRay(rayStart, rayDir, processHitTestShift);
|
||||
rayTool.HandleClickRay(rayStart, rayDir, processHitTestShift);
|
||||
}
|
||||
|
||||
if (hit.HasValue)
|
||||
|
@ -624,7 +624,7 @@ public class RecastDemo
|
|||
pos.z = rayStart.z + (rayEnd.z - rayStart.z) * hitTime;
|
||||
if (rayTool != null)
|
||||
{
|
||||
rayTool.handleClick(rayStart, pos, processHitTestShift);
|
||||
rayTool.HandleClick(rayStart, pos, processHitTestShift);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -641,26 +641,26 @@ public class RecastDemo
|
|||
processHitTest = false;
|
||||
}
|
||||
|
||||
if (sample.isChanged())
|
||||
if (sample.IsChanged())
|
||||
{
|
||||
Vector3f? bminN = null;
|
||||
Vector3f? bmaxN = null;
|
||||
if (sample.getInputGeom() != null)
|
||||
if (sample.GetInputGeom() != null)
|
||||
{
|
||||
bminN = sample.getInputGeom().getMeshBoundsMin();
|
||||
bmaxN = sample.getInputGeom().getMeshBoundsMax();
|
||||
bminN = sample.GetInputGeom().GetMeshBoundsMin();
|
||||
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];
|
||||
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)
|
||||
{
|
||||
|
@ -669,15 +669,15 @@ public class RecastDemo
|
|||
}
|
||||
|
||||
bminN = Vector3f.Of(
|
||||
Math.Min(bminN.Value.x, result.getSolidHeightfield().bmin.x),
|
||||
Math.Min(bminN.Value.y, result.getSolidHeightfield().bmin.y),
|
||||
Math.Min(bminN.Value.z, result.getSolidHeightfield().bmin.z)
|
||||
Math.Min(bminN.Value.x, result.GetSolidHeightfield().bmin.x),
|
||||
Math.Min(bminN.Value.y, result.GetSolidHeightfield().bmin.y),
|
||||
Math.Min(bminN.Value.z, result.GetSolidHeightfield().bmin.z)
|
||||
);
|
||||
|
||||
bmaxN = Vector3f.Of(
|
||||
Math.Max(bmaxN.Value.x, result.getSolidHeightfield().bmax.x),
|
||||
Math.Max(bmaxN.Value.y, result.getSolidHeightfield().bmax.y),
|
||||
Math.Max(bmaxN.Value.z, result.getSolidHeightfield().bmax.z)
|
||||
Math.Max(bmaxN.Value.x, result.GetSolidHeightfield().bmax.x),
|
||||
Math.Max(bmaxN.Value.y, result.GetSolidHeightfield().bmax.y),
|
||||
Math.Max(bmaxN.Value.z, result.GetSolidHeightfield().bmax.z)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -689,7 +689,7 @@ public class RecastDemo
|
|||
Vector3f bmax = bmaxN.Value;
|
||||
|
||||
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);
|
||||
cameraPos.x = (bmax.x + bmin.x) / 2 + camr;
|
||||
cameraPos.y = (bmax.y + bmin.y) / 2 + camr;
|
||||
|
@ -699,8 +699,8 @@ public class RecastDemo
|
|||
cameraEulers[1] = -45;
|
||||
}
|
||||
|
||||
sample.setChanged(false);
|
||||
toolsUI.setSample(sample);
|
||||
sample.SetChanged(false);
|
||||
toolsUI.SetSample(sample);
|
||||
}
|
||||
|
||||
|
||||
|
@ -717,19 +717,19 @@ public class RecastDemo
|
|||
private void OnWindowRender(double dt)
|
||||
{
|
||||
// Clear the screen
|
||||
dd.clear();
|
||||
projectionMatrix = dd.projectionMatrix(50f, (float)width / (float)height, 1.0f, camr);
|
||||
modelviewMatrix = dd.viewMatrix(cameraPos, cameraEulers);
|
||||
dd.Clear();
|
||||
projectionMatrix = dd.ProjectionMatrix(50f, (float)width / (float)height, 1.0f, camr);
|
||||
modelviewMatrix = dd.ViewMatrix(cameraPos, cameraEulers);
|
||||
|
||||
dd.fog(camr * 0.1f, camr * 1.25f);
|
||||
renderer.render(sample);
|
||||
Tool tool = toolsUI.getTool();
|
||||
dd.Fog(camr * 0.1f, camr * 1.25f);
|
||||
renderer.Render(sample);
|
||||
Tool tool = toolsUI.GetTool();
|
||||
if (tool != null)
|
||||
{
|
||||
tool.handleRender(renderer);
|
||||
tool.HandleRender(renderer);
|
||||
}
|
||||
|
||||
dd.fog(false);
|
||||
dd.Fog(false);
|
||||
|
||||
_canvas.Draw(dt);
|
||||
_mouseOverMenu = _canvas.IsMouseOverUI();
|
||||
|
|
|
@ -43,56 +43,56 @@ public class Sample
|
|||
this.recastResults = recastResults;
|
||||
this.navMesh = navMesh;
|
||||
_settingsView = settingsView;
|
||||
setQuery(navMesh);
|
||||
SetQuery(navMesh);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
private void setQuery(NavMesh navMesh)
|
||||
private void SetQuery(NavMesh navMesh)
|
||||
{
|
||||
navMeshQuery = navMesh != null ? new NavMeshQuery(navMesh) : null;
|
||||
}
|
||||
|
||||
public DemoInputGeomProvider getInputGeom()
|
||||
public DemoInputGeomProvider GetInputGeom()
|
||||
{
|
||||
return inputGeom;
|
||||
}
|
||||
|
||||
public IList<RecastBuilderResult> getRecastResults()
|
||||
public IList<RecastBuilderResult> GetRecastResults()
|
||||
{
|
||||
return recastResults;
|
||||
}
|
||||
|
||||
public NavMesh getNavMesh()
|
||||
public NavMesh GetNavMesh()
|
||||
{
|
||||
return navMesh;
|
||||
}
|
||||
|
||||
public RcSettingsView getSettingsUI()
|
||||
public RcSettingsView GetSettingsUI()
|
||||
{
|
||||
return _settingsView;
|
||||
}
|
||||
|
||||
public NavMeshQuery getNavMeshQuery()
|
||||
public NavMeshQuery GetNavMeshQuery()
|
||||
{
|
||||
return navMeshQuery;
|
||||
}
|
||||
|
||||
public bool isChanged()
|
||||
public bool IsChanged()
|
||||
{
|
||||
return changed;
|
||||
}
|
||||
|
||||
public void setChanged(bool changed)
|
||||
public void SetChanged(bool 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;
|
||||
this.recastResults = recastResults;
|
||||
this.navMesh = navMesh;
|
||||
setQuery(navMesh);
|
||||
SetQuery(navMesh);
|
||||
changed = true;
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ public class ConsoleTextWriterHook : TextWriter
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -42,14 +42,14 @@ public class ConvexVolumeTool : Tool
|
|||
private readonly List<float> pts = new();
|
||||
private readonly List<int> hull = new();
|
||||
|
||||
public override void setSample(Sample m_sample)
|
||||
public override void SetSample(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)
|
||||
{
|
||||
return;
|
||||
|
@ -59,10 +59,10 @@ public class ConvexVolumeTool : Tool
|
|||
{
|
||||
// Delete
|
||||
int nearestIndex = -1;
|
||||
IList<ConvexVolume> vols = geom.convexVolumes();
|
||||
IList<ConvexVolume> vols = geom.ConvexVolumes();
|
||||
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)
|
||||
{
|
||||
nearestIndex = i;
|
||||
|
@ -72,7 +72,7 @@ public class ConvexVolumeTool : Tool
|
|||
// If end point close enough, delete it.
|
||||
if (nearestIndex != -1)
|
||||
{
|
||||
geom.convexVolumes().RemoveAt(nearestIndex);
|
||||
geom.ConvexVolumes().RemoveAt(nearestIndex);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -80,7 +80,7 @@ public class ConvexVolumeTool : Tool
|
|||
// Create
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -105,15 +105,15 @@ public class ConvexVolumeTool : Tool
|
|||
if (polyOffset > 0.01f)
|
||||
{
|
||||
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)
|
||||
{
|
||||
geom.addConvexVolume(ArrayUtils.CopyOf(offset, 0, noffset * 3), minh, maxh, areaType);
|
||||
geom.AddConvexVolume(ArrayUtils.CopyOf(offset, 0, noffset * 3), minh, maxh, areaType);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
hull.Clear();
|
||||
hull.AddRange(ConvexUtils.convexhull(pts));
|
||||
hull.AddRange(ConvexUtils.Convexhull(pts));
|
||||
}
|
||||
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.
|
||||
float minh = float.MaxValue, maxh = 0;
|
||||
for (int i = 0; i < pts.Count; i += 3)
|
||||
|
@ -153,37 +153,37 @@ public class ConvexVolumeTool : Tool
|
|||
minh -= boxDescent;
|
||||
maxh = minh + boxHeight;
|
||||
|
||||
dd.begin(POINTS, 4.0f);
|
||||
dd.Begin(POINTS, 4.0f);
|
||||
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)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
int vi = hull[j] * 3;
|
||||
int vj = hull[i] * 3;
|
||||
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[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[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], 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[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[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.end();
|
||||
dd.End();
|
||||
}
|
||||
|
||||
public override void layout()
|
||||
public override void Layout()
|
||||
{
|
||||
ImGui.SliderFloat("Shape Height", ref boxHeight, 0.1f, 20f, "%.1f");
|
||||
ImGui.SliderFloat("Shape Descent", ref boxDescent, 0.1f, 20f, "%.1f");
|
||||
|
@ -217,20 +217,20 @@ public class ConvexVolumeTool : Tool
|
|||
hull.Clear();
|
||||
pts.Clear();
|
||||
|
||||
DemoInputGeomProvider geom = sample.getInputGeom();
|
||||
DemoInputGeomProvider geom = sample.GetInputGeom();
|
||||
if (geom != null)
|
||||
{
|
||||
geom.clearConvexVolumes();
|
||||
geom.ClearConvexVolumes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string getName()
|
||||
public override string GetName()
|
||||
{
|
||||
return "Create Convex Volumes";
|
||||
}
|
||||
|
||||
public override void handleUpdate(float dt)
|
||||
public override void HandleUpdate(float dt)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class CrowdProfilingTool
|
|||
this.agentParamsSupplier = agentParamsSupplier;
|
||||
}
|
||||
|
||||
public void layout()
|
||||
public void Layout()
|
||||
{
|
||||
ImGui.Text("Simulation Options");
|
||||
ImGui.Separator();
|
||||
|
@ -80,18 +80,18 @@ public class CrowdProfilingTool
|
|||
if (navMesh != null)
|
||||
{
|
||||
rnd = new FRand(randomSeed);
|
||||
createCrowd();
|
||||
createZones();
|
||||
CreateCrowd();
|
||||
CreateZones();
|
||||
NavMeshQuery navquery = new NavMeshQuery(navMesh);
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
for (int i = 0; i < agents; i++)
|
||||
{
|
||||
float tr = rnd.frand();
|
||||
float tr = rnd.Frand();
|
||||
AgentType type = AgentType.MOB;
|
||||
float mobsPcnt = percentMobs / 100f;
|
||||
if (tr > mobsPcnt)
|
||||
{
|
||||
tr = rnd.frand();
|
||||
tr = rnd.Frand();
|
||||
float travellerPcnt = percentTravellers / 100f;
|
||||
if (tr > travellerPcnt)
|
||||
{
|
||||
|
@ -107,19 +107,19 @@ public class CrowdProfilingTool
|
|||
switch (type)
|
||||
{
|
||||
case AgentType.MOB:
|
||||
pos = getMobPosition(navquery, filter);
|
||||
pos = GetMobPosition(navquery, filter);
|
||||
break;
|
||||
case AgentType.VILLAGER:
|
||||
pos = getVillagerPosition(navquery, filter);
|
||||
pos = GetVillagerPosition(navquery, filter);
|
||||
break;
|
||||
case AgentType.TRAVELLER:
|
||||
pos = getVillagerPosition(navquery, filter);
|
||||
pos = GetVillagerPosition(navquery, filter);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos != null)
|
||||
{
|
||||
addAgent(pos.Value, type);
|
||||
AddAgent(pos.Value, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,10 +129,10 @@ public class CrowdProfilingTool
|
|||
ImGui.Separator();
|
||||
if (crowd != null)
|
||||
{
|
||||
ImGui.Text($"Max time to enqueue request: {crowd.telemetry().maxTimeToEnqueueRequest()} s");
|
||||
ImGui.Text($"Max time to find path: {crowd.telemetry().maxTimeToFindPath()} s");
|
||||
List<Tuple<string, long>> timings = crowd.telemetry()
|
||||
.executionTimings()
|
||||
ImGui.Text($"Max time to enqueue request: {crowd.Telemetry().MaxTimeToEnqueueRequest()} s");
|
||||
ImGui.Text($"Max time to find path: {crowd.Telemetry().MaxTimeToFindPath()} s");
|
||||
List<Tuple<string, long>> timings = crowd.Telemetry()
|
||||
.ExecutionTimings()
|
||||
.Select(e => Tuple.Create(e.Key, e.Value))
|
||||
.OrderBy(x => x.Item2)
|
||||
.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())
|
||||
{
|
||||
return result.result.getRandomPt();
|
||||
return result.result.GetRandomPt();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Vector3f? getVillagerPosition(NavMeshQuery navquery, QueryFilter filter)
|
||||
private Vector3f? GetVillagerPosition(NavMeshQuery navquery, QueryFilter filter)
|
||||
{
|
||||
if (0 < zones.Count)
|
||||
{
|
||||
int zone = (int)(rnd.frand() * zones.Count);
|
||||
Result<FindRandomPointResult> result = navquery.findRandomPointWithinCircle(zones[zone].getRandomRef(),
|
||||
zones[zone].getRandomPt(), zoneRadius, filter, rnd);
|
||||
int zone = (int)(rnd.Frand() * zones.Count);
|
||||
Result<FindRandomPointResult> result = navquery.FindRandomPointWithinCircle(zones[zone].GetRandomRef(),
|
||||
zones[zone].GetRandomPt(), zoneRadius, filter, rnd);
|
||||
if (result.Succeeded())
|
||||
{
|
||||
return result.result.getRandomPt();
|
||||
return result.result.GetRandomPt();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void createZones()
|
||||
private void CreateZones()
|
||||
{
|
||||
zones.Clear();
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
|
@ -183,13 +183,13 @@ public class CrowdProfilingTool
|
|||
float zoneSeparation = zoneRadius * zoneRadius * 16;
|
||||
for (int k = 0; k < 100; k++)
|
||||
{
|
||||
Result<FindRandomPointResult> result = navquery.findRandomPoint(filter, rnd);
|
||||
Result<FindRandomPointResult> result = navquery.FindRandomPoint(filter, rnd);
|
||||
if (result.Succeeded())
|
||||
{
|
||||
bool valid = true;
|
||||
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;
|
||||
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,
|
||||
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)
|
||||
option.velBias = 0.5f;
|
||||
option.adaptiveDivs = 5;
|
||||
option.adaptiveRings = 2;
|
||||
option.adaptiveDepth = 1;
|
||||
crowd.setObstacleAvoidanceParams(0, option);
|
||||
crowd.SetObstacleAvoidanceParams(0, option);
|
||||
// Medium (22)
|
||||
option.velBias = 0.5f;
|
||||
option.adaptiveDivs = 5;
|
||||
option.adaptiveRings = 2;
|
||||
option.adaptiveDepth = 2;
|
||||
crowd.setObstacleAvoidanceParams(1, option);
|
||||
crowd.SetObstacleAvoidanceParams(1, option);
|
||||
// Good (45)
|
||||
option.velBias = 0.5f;
|
||||
option.adaptiveDivs = 7;
|
||||
option.adaptiveRings = 2;
|
||||
option.adaptiveDepth = 3;
|
||||
crowd.setObstacleAvoidanceParams(2, option);
|
||||
crowd.SetObstacleAvoidanceParams(2, option);
|
||||
// High (66)
|
||||
option.velBias = 0.5f;
|
||||
option.adaptiveDivs = 7;
|
||||
option.adaptiveRings = 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;
|
||||
if (crowd != null)
|
||||
{
|
||||
crowd.config().pathQueueSize = pathQueueSize;
|
||||
crowd.config().maxFindPathIterations = maxIterations;
|
||||
crowd.update(dt, null);
|
||||
crowd.Config().pathQueueSize = pathQueueSize;
|
||||
crowd.Config().maxFindPathIterations = maxIterations;
|
||||
crowd.Update(dt, null);
|
||||
}
|
||||
|
||||
long endTime = FrequencyWatch.Ticks;
|
||||
|
@ -253,21 +253,21 @@ public class CrowdProfilingTool
|
|||
{
|
||||
NavMeshQuery navquery = new NavMeshQuery(navMesh);
|
||||
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;
|
||||
switch (agentData.type)
|
||||
{
|
||||
case AgentType.MOB:
|
||||
moveMob(navquery, filter, ag, agentData);
|
||||
MoveMob(navquery, filter, ag, agentData);
|
||||
break;
|
||||
case AgentType.VILLAGER:
|
||||
moveVillager(navquery, filter, ag, agentData);
|
||||
MoveVillager(navquery, filter, ag, agentData);
|
||||
break;
|
||||
case AgentType.TRAVELLER:
|
||||
moveTraveller(navquery, filter, ag, agentData);
|
||||
MoveTraveller(navquery, filter, ag, agentData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -277,43 +277,43 @@ public class CrowdProfilingTool
|
|||
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
|
||||
Result<FindNearestPolyResult> nearestPoly = navquery.findNearestPoly(ag.npos, crowd.getQueryExtents(), filter);
|
||||
Result<FindNearestPolyResult> nearestPoly = navquery.FindNearestPoly(ag.npos, crowd.GetQueryExtents(), filter);
|
||||
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);
|
||||
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
|
||||
Result<FindNearestPolyResult> nearestPoly = navquery.findNearestPoly(ag.npos, crowd.getQueryExtents(), filter);
|
||||
Result<FindNearestPolyResult> nearestPoly = navquery.FindNearestPoly(ag.npos, crowd.GetQueryExtents(), filter);
|
||||
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);
|
||||
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
|
||||
List<FindRandomPointResult> potentialTargets = new();
|
||||
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);
|
||||
}
|
||||
|
@ -322,11 +322,11 @@ public class CrowdProfilingTool
|
|||
if (0 < potentialTargets.Count)
|
||||
{
|
||||
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
|
||||
|| ag.targetState == MoveRequestState.DT_CROWDAGENT_TARGET_FAILED)
|
||||
|
@ -345,7 +345,7 @@ public class CrowdProfilingTool
|
|||
return false;
|
||||
}
|
||||
|
||||
public void setup(float maxAgentRadius, NavMesh nav)
|
||||
public void Setup(float maxAgentRadius, NavMesh nav)
|
||||
{
|
||||
navMesh = nav;
|
||||
if (nav != null)
|
||||
|
@ -354,20 +354,20 @@ public class CrowdProfilingTool
|
|||
}
|
||||
}
|
||||
|
||||
public void handleRender(NavMeshRenderer renderer)
|
||||
public void HandleRender(NavMeshRenderer renderer)
|
||||
{
|
||||
RecastDebugDraw dd = renderer.getDebugDraw();
|
||||
dd.depthMask(false);
|
||||
RecastDebugDraw dd = renderer.GetDebugDraw();
|
||||
dd.DepthMask(false);
|
||||
if (crowd != null)
|
||||
{
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
float radius = ag.option.radius;
|
||||
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;
|
||||
|
||||
|
@ -375,40 +375,40 @@ public class CrowdProfilingTool
|
|||
float radius = ag.option.radius;
|
||||
Vector3f pos = ag.npos;
|
||||
|
||||
int col = duRGBA(220, 220, 220, 128);
|
||||
int col = DuRGBA(220, 220, 220, 128);
|
||||
if (agentData.type == AgentType.TRAVELLER)
|
||||
{
|
||||
col = duRGBA(100, 160, 100, 128);
|
||||
col = DuRGBA(100, 160, 100, 128);
|
||||
}
|
||||
|
||||
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
|
||||
|| 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)
|
||||
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)
|
||||
col = duRGBA(255, 32, 16, 128);
|
||||
col = DuRGBA(255, 32, 16, 128);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
dd.depthMask(true);
|
||||
dd.DepthMask(true);
|
||||
}
|
||||
|
||||
private CrowdAgent addAgent(Vector3f p, AgentType type)
|
||||
private CrowdAgent AddAgent(Vector3f p, AgentType type)
|
||||
{
|
||||
CrowdAgentParams ap = agentParamsSupplier.Invoke();
|
||||
ap.userData = new AgentData(type, p);
|
||||
return crowd.addAgent(p, ap);
|
||||
return crowd.AddAgent(p, ap);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
CrowdAgentParams option = new CrowdAgentParams();
|
||||
option.radius = ag.option.radius;
|
||||
|
@ -448,7 +448,7 @@ public class CrowdProfilingTool
|
|||
option.updateFlags = updateFlags;
|
||||
option.obstacleAvoidanceType = obstacleAvoidanceType;
|
||||
option.separationWeight = separationWeight;
|
||||
crowd.updateAgentParameters(ag, option);
|
||||
crowd.UpdateAgentParameters(ag, option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,51 +89,51 @@ public class CrowdTool : Tool
|
|||
public CrowdTool()
|
||||
{
|
||||
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)
|
||||
{
|
||||
sample = psample;
|
||||
}
|
||||
|
||||
NavMesh nav = sample.getNavMesh();
|
||||
NavMesh nav = sample.GetNavMesh();
|
||||
|
||||
if (nav != null && 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,
|
||||
SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED, new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f }));
|
||||
|
||||
// Setup local avoidance option to different qualities.
|
||||
// Use mostly default settings, copy from dtCrowd.
|
||||
ObstacleAvoidanceParams option = new ObstacleAvoidanceParams(crowd.getObstacleAvoidanceParams(0));
|
||||
ObstacleAvoidanceParams option = new ObstacleAvoidanceParams(crowd.GetObstacleAvoidanceParams(0));
|
||||
|
||||
// Low (11)
|
||||
option.velBias = 0.5f;
|
||||
option.adaptiveDivs = 5;
|
||||
option.adaptiveRings = 2;
|
||||
option.adaptiveDepth = 1;
|
||||
crowd.setObstacleAvoidanceParams(0, option);
|
||||
crowd.SetObstacleAvoidanceParams(0, option);
|
||||
|
||||
// Medium (22)
|
||||
option.velBias = 0.5f;
|
||||
option.adaptiveDivs = 5;
|
||||
option.adaptiveRings = 2;
|
||||
option.adaptiveDepth = 2;
|
||||
crowd.setObstacleAvoidanceParams(1, option);
|
||||
crowd.SetObstacleAvoidanceParams(1, option);
|
||||
|
||||
// Good (45)
|
||||
option.velBias = 0.5f;
|
||||
option.adaptiveDivs = 7;
|
||||
option.adaptiveRings = 2;
|
||||
option.adaptiveDepth = 3;
|
||||
crowd.setObstacleAvoidanceParams(2, option);
|
||||
crowd.SetObstacleAvoidanceParams(2, option);
|
||||
|
||||
// High (66)
|
||||
option.velBias = 0.5f;
|
||||
|
@ -141,13 +141,13 @@ public class CrowdTool : Tool
|
|||
option.adaptiveRings = 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)
|
||||
{
|
||||
|
@ -164,67 +164,67 @@ public class CrowdTool : Tool
|
|||
if (shift)
|
||||
{
|
||||
// Delete
|
||||
CrowdAgent ahit = hitTestAgents(s, p);
|
||||
CrowdAgent ahit = HitTestAgents(s, p);
|
||||
if (ahit != null)
|
||||
{
|
||||
removeAgent(ahit);
|
||||
RemoveAgent(ahit);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add
|
||||
addAgent(p);
|
||||
AddAgent(p);
|
||||
}
|
||||
}
|
||||
else if (m_mode == CrowdToolMode.MOVE_TARGET)
|
||||
{
|
||||
setMoveTarget(p, shift);
|
||||
SetMoveTarget(p, shift);
|
||||
}
|
||||
else if (m_mode == CrowdToolMode.SELECT)
|
||||
{
|
||||
// Highlight
|
||||
CrowdAgent ahit = hitTestAgents(s, p);
|
||||
hilightAgent(ahit);
|
||||
CrowdAgent ahit = HitTestAgents(s, p);
|
||||
HilightAgent(ahit);
|
||||
}
|
||||
else if (m_mode == CrowdToolMode.TOGGLE_POLYS)
|
||||
{
|
||||
NavMesh nav = sample.getNavMesh();
|
||||
NavMeshQuery navquery = sample.getNavMeshQuery();
|
||||
NavMesh nav = sample.GetNavMesh();
|
||||
NavMeshQuery navquery = sample.GetNavMeshQuery();
|
||||
if (nav != null && navquery != null)
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
Vector3f halfExtents = crowd.getQueryExtents();
|
||||
Result<FindNearestPolyResult> result = navquery.findNearestPoly(p, halfExtents, filter);
|
||||
long refs = result.result.getNearestRef();
|
||||
Vector3f halfExtents = crowd.GetQueryExtents();
|
||||
Result<FindNearestPolyResult> result = navquery.FindNearestPoly(p, halfExtents, filter);
|
||||
long refs = result.result.GetNearestRef();
|
||||
if (refs != 0)
|
||||
{
|
||||
Result<int> flags = nav.getPolyFlags(refs);
|
||||
Result<int> flags = nav.GetPolyFlags(refs);
|
||||
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)
|
||||
{
|
||||
m_agentDebug.agent = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void addAgent(Vector3f p)
|
||||
private void AddAgent(Vector3f p)
|
||||
{
|
||||
CrowdAgentParams ap = getAgentParams();
|
||||
CrowdAgent ag = crowd.addAgent(p, ap);
|
||||
CrowdAgentParams ap = GetAgentParams();
|
||||
CrowdAgent ag = crowd.AddAgent(p, ap);
|
||||
if (ag != null)
|
||||
{
|
||||
if (m_targetRef != 0)
|
||||
crowd.requestMoveTarget(ag, m_targetRef, m_targetPos);
|
||||
crowd.RequestMoveTarget(ag, m_targetRef, m_targetPos);
|
||||
|
||||
// Init 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();
|
||||
ap.radius = sample.getSettingsUI().getAgentRadius();
|
||||
ap.height = sample.getSettingsUI().getAgentHeight();
|
||||
ap.radius = sample.GetSettingsUI().GetAgentRadius();
|
||||
ap.height = sample.GetSettingsUI().GetAgentHeight();
|
||||
ap.maxAcceleration = 8.0f;
|
||||
ap.maxSpeed = 3.5f;
|
||||
ap.collisionQueryRange = ap.radius * 12.0f;
|
||||
ap.pathOptimizationRange = ap.radius * 30.0f;
|
||||
ap.updateFlags = getUpdateFlags();
|
||||
ap.updateFlags = GetUpdateFlags();
|
||||
ap.obstacleAvoidanceType = toolParams.m_obstacleAvoidanceType;
|
||||
ap.separationWeight = toolParams.m_separationWeight;
|
||||
return ap;
|
||||
}
|
||||
|
||||
private CrowdAgent hitTestAgents(Vector3f s, Vector3f p)
|
||||
private CrowdAgent HitTestAgents(Vector3f s, Vector3f p)
|
||||
{
|
||||
CrowdAgent isel = null;
|
||||
float tsel = float.MaxValue;
|
||||
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
Vector3f bmin = new Vector3f();
|
||||
Vector3f bmax = new Vector3f();
|
||||
getAgentBounds(ag, ref bmin, ref bmax);
|
||||
float[] isect = Intersections.intersectSegmentAABB(s, p, bmin, bmax);
|
||||
GetAgentBounds(ag, ref bmin, ref bmax);
|
||||
float[] isect = Intersections.IntersectSegmentAABB(s, p, bmin, bmax);
|
||||
if (null != isect)
|
||||
{
|
||||
float tmin = isect[0];
|
||||
|
@ -284,7 +284,7 @@ public class CrowdTool : Tool
|
|||
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;
|
||||
float r = ag.option.radius;
|
||||
|
@ -297,141 +297,141 @@ public class CrowdTool : Tool
|
|||
bmax.z = p.z + r;
|
||||
}
|
||||
|
||||
private void setMoveTarget(Vector3f p, bool adjust)
|
||||
private void SetMoveTarget(Vector3f p, bool adjust)
|
||||
{
|
||||
if (sample == null || crowd == null)
|
||||
return;
|
||||
|
||||
// Find nearest point on navmesh and set move request to that location.
|
||||
NavMeshQuery navquery = sample.getNavMeshQuery();
|
||||
QueryFilter filter = crowd.getFilter(0);
|
||||
Vector3f halfExtents = crowd.getQueryExtents();
|
||||
NavMeshQuery navquery = sample.GetNavMeshQuery();
|
||||
QueryFilter filter = crowd.GetFilter(0);
|
||||
Vector3f halfExtents = crowd.GetQueryExtents();
|
||||
|
||||
if (adjust)
|
||||
{
|
||||
// Request velocity
|
||||
if (m_agentDebug.agent != null)
|
||||
{
|
||||
Vector3f vel = calcVel(m_agentDebug.agent.npos, p, m_agentDebug.agent.option.maxSpeed);
|
||||
crowd.requestMoveVelocity(m_agentDebug.agent, vel);
|
||||
Vector3f vel = CalcVel(m_agentDebug.agent.npos, p, m_agentDebug.agent.option.maxSpeed);
|
||||
crowd.RequestMoveVelocity(m_agentDebug.agent, vel);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
Vector3f vel = calcVel(ag.npos, p, ag.option.maxSpeed);
|
||||
crowd.requestMoveVelocity(ag, vel);
|
||||
Vector3f vel = CalcVel(ag.npos, p, ag.option.maxSpeed);
|
||||
crowd.RequestMoveVelocity(ag, vel);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Result<FindNearestPolyResult> result = navquery.findNearestPoly(p, halfExtents, filter);
|
||||
m_targetRef = result.result.getNearestRef();
|
||||
m_targetPos = result.result.getNearestPos();
|
||||
Result<FindNearestPolyResult> result = navquery.FindNearestPoly(p, halfExtents, filter);
|
||||
m_targetRef = result.result.GetNearestRef();
|
||||
m_targetPos = result.result.GetNearestPos();
|
||||
if (m_agentDebug.agent != null)
|
||||
{
|
||||
crowd.requestMoveTarget(m_agentDebug.agent, m_targetRef, m_targetPos);
|
||||
crowd.RequestMoveTarget(m_agentDebug.agent, m_targetRef, m_targetPos);
|
||||
}
|
||||
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;
|
||||
vNormalize(ref vel);
|
||||
return vScale(vel, speed);
|
||||
VNormalize(ref vel);
|
||||
return VScale(vel, speed);
|
||||
}
|
||||
|
||||
public override void handleRender(NavMeshRenderer renderer)
|
||||
public override void HandleRender(NavMeshRenderer renderer)
|
||||
{
|
||||
if (m_mode == CrowdToolMode.PROFILING)
|
||||
{
|
||||
profilingTool.handleRender(renderer);
|
||||
profilingTool.HandleRender(renderer);
|
||||
return;
|
||||
}
|
||||
|
||||
RecastDebugDraw dd = renderer.getDebugDraw();
|
||||
float rad = sample.getSettingsUI().getAgentRadius();
|
||||
NavMesh nav = sample.getNavMesh();
|
||||
RecastDebugDraw dd = renderer.GetDebugDraw();
|
||||
float rad = sample.GetSettingsUI().GetAgentRadius();
|
||||
NavMesh nav = sample.GetNavMesh();
|
||||
if (nav == null || crowd == null)
|
||||
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) {
|
||||
// dd.debugDrawNavMeshNodes(navquery);
|
||||
// dd.DebugDrawNavMeshNodes(navquery);
|
||||
// }
|
||||
}
|
||||
|
||||
dd.depthMask(false);
|
||||
dd.DepthMask(false);
|
||||
|
||||
// Draw paths
|
||||
if (toolParams.m_showPath)
|
||||
{
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
if (!toolParams.m_showDetailAll && ag != m_agentDebug.agent)
|
||||
continue;
|
||||
List<long> path = ag.corridor.getPath();
|
||||
int npath = ag.corridor.getPathCount();
|
||||
List<long> path = ag.corridor.GetPath();
|
||||
int npath = ag.corridor.GetPathCount();
|
||||
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)
|
||||
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.
|
||||
if (toolParams.m_showGrid)
|
||||
{
|
||||
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 += 1.0f;
|
||||
|
||||
dd.begin(QUADS);
|
||||
ProximityGrid grid = crowd.getGrid();
|
||||
dd.Begin(QUADS);
|
||||
ProximityGrid grid = crowd.GetGrid();
|
||||
float cs = grid.GetCellSize();
|
||||
foreach (var (combinedKey, count) in grid.GetItemCounts())
|
||||
{
|
||||
ProximityGrid.DecomposeKey(combinedKey, out var x, out var y);
|
||||
if (count != 0)
|
||||
{
|
||||
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 + cs, col);
|
||||
dd.vertex(x * cs + cs, gridy, y * cs + cs, col);
|
||||
dd.vertex(x * cs + cs, gridy, y * cs, col);
|
||||
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 + cs, col);
|
||||
dd.Vertex(x * cs + cs, gridy, y * cs + cs, col);
|
||||
dd.Vertex(x * cs + cs, gridy, y * cs, col);
|
||||
}
|
||||
}
|
||||
|
||||
dd.end();
|
||||
dd.End();
|
||||
}
|
||||
|
||||
// Trail
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
AgentTrail trail = m_trails[ag.idx];
|
||||
Vector3f pos = ag.npos;
|
||||
|
||||
dd.begin(LINES, 3.0f);
|
||||
dd.Begin(LINES, 3.0f);
|
||||
Vector3f prev = new Vector3f();
|
||||
float preva = 1;
|
||||
prev = pos;
|
||||
|
@ -440,17 +440,17 @@ public class CrowdTool : Tool
|
|||
int idx = (trail.htrail + AGENT_MAX_TRAIL - j) % AGENT_MAX_TRAIL;
|
||||
int v = idx * 3;
|
||||
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(trail.trail[v], trail.trail[v + 1] + 0.1f, trail.trail[v + 2], duRGBA(0, 0, 0, (int)(128 * a)));
|
||||
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)));
|
||||
preva = a;
|
||||
vCopy(ref prev, trail.trail, v);
|
||||
VCopy(ref prev, trail.trail, v);
|
||||
}
|
||||
|
||||
dd.end();
|
||||
dd.End();
|
||||
}
|
||||
|
||||
// Corners & co
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
if (toolParams.m_showDetailAll == false && ag != m_agentDebug.agent)
|
||||
continue;
|
||||
|
@ -462,29 +462,29 @@ public class CrowdTool : Tool
|
|||
{
|
||||
if (0 < ag.corners.Count)
|
||||
{
|
||||
dd.begin(LINES, 2.0f);
|
||||
dd.Begin(LINES, 2.0f);
|
||||
for (int j = 0; j < ag.corners.Count; ++j)
|
||||
{
|
||||
Vector3f va = j == 0 ? pos : ag.corners[j - 1].getPos();
|
||||
Vector3f vb = ag.corners[j].getPos();
|
||||
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));
|
||||
Vector3f va = j == 0 ? pos : ag.corners[j - 1].GetPos();
|
||||
Vector3f vb = ag.corners[j].GetPos();
|
||||
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));
|
||||
}
|
||||
|
||||
if ((ag.corners[ag.corners.Count - 1].getFlags()
|
||||
if ((ag.corners[ag.corners.Count - 1].GetFlags()
|
||||
& NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|
||||
{
|
||||
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 + radius * 2, v.z, duRGBA(192, 0, 0, 192));
|
||||
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 + radius * 2, v.z, DuRGBA(192, 0, 0, 192));
|
||||
}
|
||||
|
||||
dd.end();
|
||||
dd.End();
|
||||
|
||||
if (toolParams.m_anticipateTurns)
|
||||
{
|
||||
/* 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.y = ag.pos.y + dvel.y;
|
||||
pos.z = ag.pos.z + dvel.z;
|
||||
|
@ -493,107 +493,107 @@ public class CrowdTool : Tool
|
|||
float[] tgt = &ag.cornerVerts.x;
|
||||
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(pos.x,y,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(tgt.x,y,tgt.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.end();*/
|
||||
dd.End();*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (toolParams.m_showCollisionSegments)
|
||||
{
|
||||
Vector3f center = ag.boundary.getCenter();
|
||||
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);
|
||||
Vector3f center = ag.boundary.GetCenter();
|
||||
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.begin(LINES, 3.0f);
|
||||
for (int j = 0; j < ag.boundary.getSegmentCount(); ++j)
|
||||
dd.Begin(LINES, 3.0f);
|
||||
for (int j = 0; j < ag.boundary.GetSegmentCount(); ++j)
|
||||
{
|
||||
int col = duRGBA(192, 0, 128, 192);
|
||||
Vector3f[] s = ag.boundary.getSegment(j);
|
||||
int col = DuRGBA(192, 0, 128, 192);
|
||||
Vector3f[] s = ag.boundary.GetSegment(j);
|
||||
Vector3f s0 = s[0];
|
||||
Vector3f s3 = s[1];
|
||||
if (triArea2D(pos, s0, s3) < 0.0f)
|
||||
col = duDarkenCol(col);
|
||||
if (TriArea2D(pos, s0, s3) < 0.0f)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
dd.begin(LINES, 2.0f);
|
||||
dd.Begin(LINES, 2.0f);
|
||||
for (int j = 0; j < ag.neis.Count; ++j)
|
||||
{
|
||||
CrowdAgent nei = ag.neis[j].agent;
|
||||
if (nei != null)
|
||||
{
|
||||
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(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.end();
|
||||
dd.End();
|
||||
}
|
||||
|
||||
if (toolParams.m_showOpt)
|
||||
{
|
||||
dd.begin(LINES, 2.0f);
|
||||
dd.vertex(m_agentDebug.optStart.x, m_agentDebug.optStart.y + 0.3f, m_agentDebug.optStart.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.Begin(LINES, 2.0f);
|
||||
dd.Vertex(m_agentDebug.optStart.x, m_agentDebug.optStart.y + 0.3f, m_agentDebug.optStart.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();
|
||||
}
|
||||
}
|
||||
|
||||
// Agent cylinders.
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
float radius = ag.option.radius;
|
||||
Vector3f pos = ag.npos;
|
||||
|
||||
int col = duRGBA(0, 0, 0, 32);
|
||||
int col = DuRGBA(0, 0, 0, 32);
|
||||
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 radius = ag.option.radius;
|
||||
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
|
||||
|| 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)
|
||||
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)
|
||||
col = duRGBA(255, 32, 16, 128);
|
||||
col = DuRGBA(255, 32, 16, 128);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
continue;
|
||||
|
@ -605,29 +605,29 @@ public class CrowdTool : Tool
|
|||
float dy = ag.npos.y + ag.option.height;
|
||||
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);
|
||||
for (int j = 0; j < vod.getSampleCount(); ++j)
|
||||
dd.Begin(QUADS);
|
||||
for (int j = 0; j < vod.GetSampleCount(); ++j)
|
||||
{
|
||||
Vector3f p = vod.getSampleVelocity(j);
|
||||
float sr = vod.getSampleSize(j);
|
||||
float pen = vod.getSamplePenalty(j);
|
||||
float pen2 = vod.getSamplePreferredSidePenalty(j);
|
||||
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));
|
||||
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);
|
||||
Vector3f p = vod.GetSampleVelocity(j);
|
||||
float sr = vod.GetSampleSize(j);
|
||||
float pen = vod.GetSamplePenalty(j);
|
||||
float pen2 = vod.GetSamplePreferredSidePenalty(j);
|
||||
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));
|
||||
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.
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
float radius = ag.option.radius;
|
||||
float height = ag.option.height;
|
||||
|
@ -635,54 +635,54 @@ public class CrowdTool : Tool
|
|||
Vector3f vel = ag.vel;
|
||||
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
|
||||
|| 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)
|
||||
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)
|
||||
col = duRGBA(255, 32, 16, 192);
|
||||
col = DuRGBA(255, 32, 16, 192);
|
||||
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,
|
||||
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 + 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);
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
profilingTool.update(dt);
|
||||
profilingTool.Update(dt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (crowd == null)
|
||||
return;
|
||||
NavMesh nav = sample.getNavMesh();
|
||||
NavMesh nav = sample.GetNavMesh();
|
||||
if (nav == null)
|
||||
return;
|
||||
|
||||
long startTime = FrequencyWatch.Ticks;
|
||||
crowd.update(dt, m_agentDebug);
|
||||
crowd.Update(dt, m_agentDebug);
|
||||
long endTime = FrequencyWatch.Ticks;
|
||||
|
||||
// Update agent trails
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
AgentTrail trail = m_trails[ag.idx];
|
||||
// Update agent movement trail.
|
||||
|
@ -692,18 +692,18 @@ public class CrowdTool : Tool
|
|||
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;
|
||||
}
|
||||
|
||||
private void hilightAgent(CrowdAgent agent)
|
||||
private void HilightAgent(CrowdAgent agent)
|
||||
{
|
||||
m_agentDebug.agent = agent;
|
||||
}
|
||||
|
||||
public override void layout()
|
||||
public override void Layout()
|
||||
{
|
||||
ImGui.Text($"Crowd Tool Mode");
|
||||
ImGui.Separator();
|
||||
|
@ -744,13 +744,13 @@ public class CrowdTool : Tool
|
|||
|| m_obstacleAvoidanceType != toolParams.m_obstacleAvoidanceType
|
||||
|| m_separationWeight != toolParams.m_separationWeight)
|
||||
{
|
||||
updateAgentParams();
|
||||
UpdateAgentParams();
|
||||
}
|
||||
|
||||
|
||||
if (m_mode == CrowdToolMode.PROFILING)
|
||||
{
|
||||
profilingTool.layout();
|
||||
profilingTool.Layout();
|
||||
}
|
||||
|
||||
if (m_mode != CrowdToolMode.PROFILING)
|
||||
|
@ -773,16 +773,16 @@ public class CrowdTool : Tool
|
|||
}
|
||||
}
|
||||
|
||||
private void updateAgentParams()
|
||||
private void UpdateAgentParams()
|
||||
{
|
||||
if (crowd == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int updateFlags = getUpdateFlags();
|
||||
profilingTool.updateAgentParams(updateFlags, toolParams.m_obstacleAvoidanceType, toolParams.m_separationWeight);
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
int updateFlags = GetUpdateFlags();
|
||||
profilingTool.UpdateAgentParams(updateFlags, toolParams.m_obstacleAvoidanceType, toolParams.m_separationWeight);
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
CrowdAgentParams option = new CrowdAgentParams();
|
||||
option.radius = ag.option.radius;
|
||||
|
@ -797,11 +797,11 @@ public class CrowdTool : Tool
|
|||
option.updateFlags = updateFlags;
|
||||
option.obstacleAvoidanceType = toolParams.m_obstacleAvoidanceType;
|
||||
option.separationWeight = toolParams.m_separationWeight;
|
||||
crowd.updateAgentParameters(ag, option);
|
||||
crowd.UpdateAgentParameters(ag, option);
|
||||
}
|
||||
}
|
||||
|
||||
private int getUpdateFlags()
|
||||
private int GetUpdateFlags()
|
||||
{
|
||||
int updateFlags = 0;
|
||||
if (toolParams.m_anticipateTurns)
|
||||
|
@ -832,7 +832,7 @@ public class CrowdTool : Tool
|
|||
return updateFlags;
|
||||
}
|
||||
|
||||
public override string getName()
|
||||
public override string GetName()
|
||||
{
|
||||
return "Crowd";
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ namespace DotRecast.Recast.Demo.Tools;
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
@ -125,17 +126,17 @@ public class DynamicUpdateTool : Tool
|
|||
public DynamicUpdateTool()
|
||||
{
|
||||
executor = Task.Factory;
|
||||
bridgeGeom = DemoObjImporter.load(Loader.ToBytes("bridge.obj"));
|
||||
houseGeom = DemoObjImporter.load(Loader.ToBytes("house.obj"));
|
||||
convexGeom = DemoObjImporter.load(Loader.ToBytes("convex.obj"));
|
||||
bridgeGeom = DemoObjImporter.Load(Loader.ToBytes("bridge.obj"));
|
||||
houseGeom = DemoObjImporter.Load(Loader.ToBytes("house.obj"));
|
||||
convexGeom = DemoObjImporter.Load(Loader.ToBytes("convex.obj"));
|
||||
}
|
||||
|
||||
public override void setSample(Sample sample)
|
||||
public override void SetSample(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)
|
||||
{
|
||||
|
@ -146,41 +147,41 @@ public class DynamicUpdateTool : Tool
|
|||
{
|
||||
if (colliderShape == ColliderShape.SPHERE)
|
||||
{
|
||||
colliderWithGizmo = sphereCollider(p);
|
||||
colliderWithGizmo = SphereCollider(p);
|
||||
}
|
||||
else if (colliderShape == ColliderShape.CAPSULE)
|
||||
{
|
||||
colliderWithGizmo = capsuleCollider(p);
|
||||
colliderWithGizmo = CapsuleCollider(p);
|
||||
}
|
||||
else if (colliderShape == ColliderShape.BOX)
|
||||
{
|
||||
colliderWithGizmo = boxCollider(p);
|
||||
colliderWithGizmo = BoxCollider(p);
|
||||
}
|
||||
else if (colliderShape == ColliderShape.CYLINDER)
|
||||
{
|
||||
colliderWithGizmo = cylinderCollider(p);
|
||||
colliderWithGizmo = CylinderCollider(p);
|
||||
}
|
||||
else if (colliderShape == ColliderShape.COMPOSITE)
|
||||
{
|
||||
colliderWithGizmo = compositeCollider(p);
|
||||
colliderWithGizmo = CompositeCollider(p);
|
||||
}
|
||||
else if (colliderShape == ColliderShape.TRIMESH_BRIDGE)
|
||||
{
|
||||
colliderWithGizmo = trimeshBridge(p);
|
||||
colliderWithGizmo = TrimeshBridge(p);
|
||||
}
|
||||
else if (colliderShape == ColliderShape.TRIMESH_HOUSE)
|
||||
{
|
||||
colliderWithGizmo = trimeshHouse(p);
|
||||
colliderWithGizmo = TrimeshHouse(p);
|
||||
}
|
||||
else if (colliderShape == ColliderShape.CONVEX)
|
||||
{
|
||||
colliderWithGizmo = convexTrimesh(p);
|
||||
colliderWithGizmo = ConvexTrimesh(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (colliderWithGizmo != null)
|
||||
{
|
||||
long id = dynaMesh.addCollider(colliderWithGizmo.Item1);
|
||||
long id = dynaMesh.AddCollider(colliderWithGizmo.Item1);
|
||||
colliders.Add(id, colliderWithGizmo.Item1);
|
||||
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 ep = Vector3f.Of(epos.x, epos.y + 1.3f, epos.z);
|
||||
long t1 = FrequencyWatch.Ticks;
|
||||
float? hitPos = dynaMesh.voxelQuery().raycast(sp, ep);
|
||||
float? hitPos = dynaMesh.VoxelQuery().Raycast(sp, ep);
|
||||
long t2 = FrequencyWatch.Ticks;
|
||||
raycastTime = (t2 - t1) / TimeSpan.TicksPerMillisecond;
|
||||
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;
|
||||
return Tuple.Create<Collider, ColliderGizmo>(
|
||||
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;
|
||||
Vector3f a = Vector3f.Of(
|
||||
|
@ -232,7 +233,7 @@ public class DynamicUpdateTool : Tool
|
|||
0.01f + (float)random.NextDouble(),
|
||||
(1f - 2 * (float)random.NextDouble())
|
||||
);
|
||||
vNormalize(ref a);
|
||||
VNormalize(ref a);
|
||||
float len = 1f + (float)random.NextDouble() * 20f;
|
||||
a.x *= len;
|
||||
a.y *= len;
|
||||
|
@ -240,10 +241,10 @@ public class DynamicUpdateTool : Tool
|
|||
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);
|
||||
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(
|
||||
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 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>(
|
||||
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[] 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;
|
||||
a[0] *= len;
|
||||
a[1] *= len;
|
||||
|
@ -269,25 +270,25 @@ public class DynamicUpdateTool : Tool
|
|||
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]);
|
||||
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 baseCenter = Vector3f.Of(p.x, p.y + 3, p.z);
|
||||
Vector3f baseUp = Vector3f.Of(0, 1, 0);
|
||||
Vector3f forward = Vector3f.Of((1f - 2 * (float)random.NextDouble()), 0, (1f - 2 * (float)random.NextDouble()));
|
||||
vNormalize(ref forward);
|
||||
Vector3f side = vCross(forward, baseUp);
|
||||
BoxCollider @base = new BoxCollider(baseCenter, BoxCollider.getHalfEdges(baseUp, forward, baseExtent),
|
||||
VNormalize(ref forward);
|
||||
Vector3f side = VCross(forward, baseUp);
|
||||
BoxCollider @base = new BoxCollider(baseCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(baseUp, forward, baseExtent),
|
||||
SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, dynaMesh.config.walkableClimb);
|
||||
var roofUp = Vector3f.Zero;
|
||||
Vector3f roofExtent = Vector3f.Of(4.5f, 4.5f, 8f);
|
||||
float[] rx = GLU.build_4x4_rotation_matrix(45, forward.x, forward.y, forward.z);
|
||||
roofUp = mulMatrixVector(ref roofUp, rx, baseUp);
|
||||
float[] rx = GLU.Build_4x4_rotation_matrix(45, forward.x, forward.y, forward.z);
|
||||
roofUp = MulMatrixVector(ref roofUp, rx, baseUp);
|
||||
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);
|
||||
Vector3f trunkStart = Vector3f.Of(
|
||||
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,
|
||||
dynaMesh.config.walkableClimb);
|
||||
CompositeCollider collider = new CompositeCollider(@base, roof, trunk, crown);
|
||||
ColliderGizmo baseGizmo = GizmoFactory.box(baseCenter, BoxCollider.getHalfEdges(baseUp, forward, baseExtent));
|
||||
ColliderGizmo roofGizmo = GizmoFactory.box(roofCenter, BoxCollider.getHalfEdges(roofUp, forward, roofExtent));
|
||||
ColliderGizmo trunkGizmo = GizmoFactory.capsule(trunkStart, trunkEnd, 0.5f);
|
||||
ColliderGizmo crownGizmo = GizmoFactory.sphere(crownCenter, 4f);
|
||||
ColliderGizmo gizmo = GizmoFactory.composite(baseGizmo, roofGizmo, trunkGizmo, crownGizmo);
|
||||
ColliderGizmo baseGizmo = GizmoFactory.Box(baseCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(baseUp, forward, baseExtent));
|
||||
ColliderGizmo roofGizmo = GizmoFactory.Box(roofCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(roofUp, forward, roofExtent));
|
||||
ColliderGizmo trunkGizmo = GizmoFactory.Capsule(trunkStart, trunkEnd, 0.5f);
|
||||
ColliderGizmo crownGizmo = GizmoFactory.Sphere(crownCenter, 4f);
|
||||
ColliderGizmo gizmo = GizmoFactory.Composite(baseGizmo, roofGizmo, trunkGizmo, crownGizmo);
|
||||
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,
|
||||
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,
|
||||
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[] ry = GLU.build_4x4_rotation_matrix((float)random.NextDouble() * 360, 0, 1, 0);
|
||||
float[] m = GLU.mul(rx, ry);
|
||||
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[] m = GLU.Mul(rx, ry);
|
||||
float[] verts = new float[geom.vertices.Length];
|
||||
Vector3f v = new Vector3f();
|
||||
Vector3f vr = new Vector3f();
|
||||
|
@ -351,7 +352,7 @@ public class DynamicUpdateTool : Tool
|
|||
v.x = geom.vertices[i];
|
||||
v.y = geom.vertices[i + 1];
|
||||
v.z = geom.vertices[i + 2];
|
||||
mulMatrixVector(ref vr, m, v);
|
||||
MulMatrixVector(ref vr, m, v);
|
||||
vr.x += p.x;
|
||||
vr.y += p.y - 0.1f;
|
||||
vr.z += p.z;
|
||||
|
@ -363,7 +364,7 @@ public class DynamicUpdateTool : Tool
|
|||
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[1] = matrix[1] * pvector[0] + matrix[5] * pvector[1] + matrix[9] * pvector[2];
|
||||
|
@ -371,7 +372,7 @@ public class DynamicUpdateTool : Tool
|
|||
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.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)
|
||||
{
|
||||
|
@ -388,9 +389,9 @@ public class DynamicUpdateTool : Tool
|
|||
{
|
||||
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);
|
||||
colliderGizmos.Remove(e.Key);
|
||||
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 cy = 0.5f * (bounds[1] + bounds[4]);
|
||||
|
@ -428,85 +429,85 @@ public class DynamicUpdateTool : Tool
|
|||
return disc >= 0.0f;
|
||||
}
|
||||
|
||||
public override void handleRender(NavMeshRenderer renderer)
|
||||
public override void HandleRender(NavMeshRenderer renderer)
|
||||
{
|
||||
if (mode == DynamicUpdateToolMode.COLLIDERS)
|
||||
{
|
||||
if (showColliders)
|
||||
{
|
||||
colliderGizmos.Values.forEach(g => g.render(renderer.getDebugDraw()));
|
||||
colliderGizmos.Values.ForEach(g => g.Render(renderer.GetDebugDraw()));
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == DynamicUpdateToolMode.RAYCAST)
|
||||
{
|
||||
RecastDebugDraw dd = renderer.getDebugDraw();
|
||||
int startCol = duRGBA(128, 25, 0, 192);
|
||||
int endCol = duRGBA(51, 102, 0, 129);
|
||||
RecastDebugDraw dd = renderer.GetDebugDraw();
|
||||
int startCol = DuRGBA(128, 25, 0, 192);
|
||||
int endCol = DuRGBA(51, 102, 0, 129);
|
||||
if (sposSet)
|
||||
{
|
||||
drawAgent(dd, spos, startCol);
|
||||
DrawAgent(dd, spos, startCol);
|
||||
}
|
||||
|
||||
if (eposSet)
|
||||
{
|
||||
drawAgent(dd, epos, endCol);
|
||||
DrawAgent(dd, epos, endCol);
|
||||
}
|
||||
|
||||
dd.depthMask(false);
|
||||
dd.DepthMask(false);
|
||||
if (raycastHitPos != Vector3f.Zero)
|
||||
{
|
||||
int spathCol = raycastHit ? duRGBA(128, 32, 16, 220) : duRGBA(64, 128, 240, 220);
|
||||
dd.begin(LINES, 2.0f);
|
||||
dd.vertex(spos.x, spos.y + 1.3f, spos.z, spathCol);
|
||||
dd.vertex(raycastHitPos.x, raycastHitPos.y, raycastHitPos.z, spathCol);
|
||||
dd.end();
|
||||
int spathCol = raycastHit ? DuRGBA(128, 32, 16, 220) : DuRGBA(64, 128, 240, 220);
|
||||
dd.Begin(LINES, 2.0f);
|
||||
dd.Vertex(spos.x, spos.y + 1.3f, spos.z, spathCol);
|
||||
dd.Vertex(raycastHitPos.x, raycastHitPos.y, raycastHitPos.z, spathCol);
|
||||
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 h = sample.getSettingsUI().getAgentHeight();
|
||||
float c = sample.getSettingsUI().getAgentMaxClimb();
|
||||
dd.depthMask(false);
|
||||
float r = sample.GetSettingsUI().GetAgentRadius();
|
||||
float h = sample.GetSettingsUI().GetAgentHeight();
|
||||
float c = sample.GetSettingsUI().GetAgentMaxClimb();
|
||||
dd.DepthMask(false);
|
||||
// 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.debugDrawCircle(pos.x, pos.y + c, pos.z, r, duRGBA(0, 0, 0, 64), 1.0f);
|
||||
int colb = duRGBA(0, 0, 0, 196);
|
||||
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 - 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.end();
|
||||
dd.depthMask(true);
|
||||
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);
|
||||
int colb = DuRGBA(0, 0, 0, 196);
|
||||
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 - 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.End();
|
||||
dd.DepthMask(true);
|
||||
}
|
||||
|
||||
public override void handleUpdate(float dt)
|
||||
public override void HandleUpdate(float dt)
|
||||
{
|
||||
if (dynaMesh != null)
|
||||
{
|
||||
updateDynaMesh();
|
||||
UpdateDynaMesh();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDynaMesh()
|
||||
private void UpdateDynaMesh()
|
||||
{
|
||||
long t = FrequencyWatch.Ticks;
|
||||
try
|
||||
{
|
||||
bool updated = dynaMesh.update(executor).Result;
|
||||
bool updated = dynaMesh.Update(executor).Result;
|
||||
if (updated)
|
||||
{
|
||||
buildTime = (FrequencyWatch.Ticks - t) / TimeSpan.TicksPerMillisecond;
|
||||
sample.update(null, dynaMesh.recastResults(), dynaMesh.navMesh());
|
||||
sample.setChanged(false);
|
||||
sample.Update(null, dynaMesh.RecastResults(), dynaMesh.NavMesh());
|
||||
sample.SetChanged(false);
|
||||
}
|
||||
}
|
||||
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.Separator();
|
||||
|
@ -548,7 +549,7 @@ public class DynamicUpdateTool : Tool
|
|||
var picker = ImFilePicker.GetFilePicker(loadVoxelPopupStrId, Path.Combine(Environment.CurrentDirectory), ".voxels");
|
||||
if (picker.Draw())
|
||||
{
|
||||
load(picker.SelectedFile);
|
||||
Load(picker.SelectedFile);
|
||||
ImFilePicker.RemoveFilePicker(loadVoxelPopupStrId);
|
||||
}
|
||||
|
||||
|
@ -571,7 +572,7 @@ public class DynamicUpdateTool : Tool
|
|||
if (picker.Draw())
|
||||
{
|
||||
if (string.IsNullOrEmpty(picker.SelectedFile))
|
||||
save(picker.SelectedFile);
|
||||
Save(picker.SelectedFile);
|
||||
|
||||
ImFilePicker.RemoveFilePicker(saveVoxelPopupStrId);
|
||||
}
|
||||
|
@ -597,7 +598,7 @@ public class DynamicUpdateTool : Tool
|
|||
|
||||
ImGui.Text("Partitioning");
|
||||
ImGui.Separator();
|
||||
PartitionType.Values.forEach(partition =>
|
||||
PartitionType.Values.ForEach(partition =>
|
||||
{
|
||||
var label = partition.Name.Substring(0, 1).ToUpper()
|
||||
+ partition.Name.Substring(1).ToLower();
|
||||
|
@ -636,8 +637,8 @@ public class DynamicUpdateTool : Tool
|
|||
{
|
||||
if (dynaMesh != null)
|
||||
{
|
||||
buildDynaMesh();
|
||||
sample.setChanged(false);
|
||||
BuildDynaMesh();
|
||||
sample.SetChanged(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -692,18 +693,18 @@ public class DynamicUpdateTool : Tool
|
|||
}
|
||||
|
||||
|
||||
private void load(string filename)
|
||||
private void Load(string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
|
||||
using var br = new BinaryReader(fs);
|
||||
VoxelFileReader reader = new VoxelFileReader();
|
||||
VoxelFile voxelFile = reader.read(br);
|
||||
VoxelFile voxelFile = reader.Read(br);
|
||||
dynaMesh = new DynamicNavMesh(voxelFile);
|
||||
dynaMesh.config.keepIntermediateResults = true;
|
||||
updateUI();
|
||||
buildDynaMesh();
|
||||
UpdateUI();
|
||||
BuildDynaMesh();
|
||||
|
||||
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 bw = new BinaryWriter(fs);
|
||||
VoxelFile voxelFile = VoxelFile.from(dynaMesh);
|
||||
VoxelFile voxelFile = VoxelFile.From(dynaMesh);
|
||||
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;
|
||||
try
|
||||
{
|
||||
var _ = dynaMesh.build(executor).Result;
|
||||
var _ = dynaMesh.Build(executor).Result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -738,10 +739,10 @@ public class DynamicUpdateTool : Tool
|
|||
}
|
||||
|
||||
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.walkableHeight = walkableHeight;
|
||||
|
@ -761,7 +762,7 @@ public class DynamicUpdateTool : Tool
|
|||
dynaMesh.config.detailSampleMaxError = detailSampleMaxError;
|
||||
}
|
||||
|
||||
private void updateUI()
|
||||
private void UpdateUI()
|
||||
{
|
||||
cellSize = dynaMesh.config.cellSize;
|
||||
partitioning = dynaMesh.config.partitionType;
|
||||
|
@ -782,7 +783,7 @@ public class DynamicUpdateTool : Tool
|
|||
filterWalkableLowHeightSpans = dynaMesh.config.filterWalkableLowHeightSpans;
|
||||
}
|
||||
|
||||
public override string getName()
|
||||
public override string GetName()
|
||||
{
|
||||
return "Dynamic Updates";
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class BoxGizmo : ColliderGizmo
|
|||
private readonly Vector3f[] halfEdges;
|
||||
|
||||
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 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];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
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 + 2] = RecastVectors.dot(VERTS[i], trZ) + center.z;
|
||||
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 + 2] = RecastVectors.Dot(VERTS[i], trZ) + center.z;
|
||||
}
|
||||
|
||||
debugDraw.begin(DebugDrawPrimitives.TRIS);
|
||||
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
||||
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)
|
||||
{
|
||||
col = DebugDraw.duRGBA(160, 160, 40, 160);
|
||||
col = DebugDraw.DuRGBA(160, 160, 40, 160);
|
||||
}
|
||||
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++)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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[] normals = new Vector3f[3];
|
||||
normals[1] = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
|
||||
normalize(ref normals[1]);
|
||||
normals[0] = getSideVector(axis);
|
||||
Normalize(ref normals[1]);
|
||||
normals[0] = GetSideVector(axis);
|
||||
normals[2] = Vector3f.Zero;
|
||||
cross(ref normals[2], normals[0], normals[1]);
|
||||
normalize(ref normals[2]);
|
||||
triangles = generateSphericalTriangles();
|
||||
Cross(ref normals[2], normals[0], normals[1]);
|
||||
Normalize(ref normals[2]);
|
||||
triangles = GenerateSphericalTriangles();
|
||||
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 trZ = Vector3f.Of(normals[0].z, normals[1].z, normals[2].z);
|
||||
float[] spVertices = generateSphericalVertices();
|
||||
float halfLength = 0.5f * vLen(axis);
|
||||
float[] spVertices = GenerateSphericalVertices();
|
||||
float halfLength = 0.5f * VLen(axis);
|
||||
vertices = new float[spVertices.Length];
|
||||
gradient = new float[spVertices.Length / 3];
|
||||
Vector3f v = new Vector3f();
|
||||
|
@ -49,12 +49,12 @@ public class CapsuleGizmo : ColliderGizmo
|
|||
v.x = vertices[i] - center[0];
|
||||
v.y = vertices[i + 1] - center[1];
|
||||
v.z = vertices[i + 2] - center[2];
|
||||
normalize(ref v);
|
||||
gradient[i / 3] = clamp(0.57735026f * (v.x + v.y + v.z), -1, 1);
|
||||
Normalize(ref v);
|
||||
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);
|
||||
if (axis.x > 0.8)
|
||||
|
@ -63,27 +63,27 @@ public class CapsuleGizmo : ColliderGizmo
|
|||
}
|
||||
|
||||
Vector3f forward = new Vector3f();
|
||||
cross(ref forward, side, axis);
|
||||
cross(ref side, axis, forward);
|
||||
normalize(ref side);
|
||||
Cross(ref forward, side, axis);
|
||||
Cross(ref side, axis, forward);
|
||||
Normalize(ref 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 j = 0; j < 3; j++)
|
||||
{
|
||||
int v = triangles[i + j] * 3;
|
||||
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)));
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,5 +4,5 @@ namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
|||
|
||||
public interface ColliderGizmo
|
||||
{
|
||||
void render(RecastDebugDraw debugDraw);
|
||||
void Render(RecastDebugDraw debugDraw);
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using DotRecast.Core;
|
||||
using System;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
||||
|
@ -12,8 +13,8 @@ public class CompositeGizmo : ColliderGizmo
|
|||
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));
|
||||
}
|
||||
}
|
|
@ -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[] normals = new Vector3f[3];
|
||||
normals[1] = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
|
||||
normalize(ref normals[1]);
|
||||
normals[0] = getSideVector(axis);
|
||||
Normalize(ref normals[1]);
|
||||
normals[0] = GetSideVector(axis);
|
||||
normals[2] = Vector3f.Zero;
|
||||
cross(ref normals[2], normals[0], normals[1]);
|
||||
normalize(ref normals[2]);
|
||||
triangles = generateCylindricalTriangles();
|
||||
Cross(ref normals[2], normals[0], normals[1]);
|
||||
Normalize(ref normals[2]);
|
||||
triangles = GenerateCylindricalTriangles();
|
||||
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 trZ = Vector3f.Of(normals[0].z, normals[1].z, normals[2].z);
|
||||
vertices = generateCylindricalVertices();
|
||||
float halfLength = 0.5f * vLen(axis);
|
||||
vertices = GenerateCylindricalVertices();
|
||||
float halfLength = 0.5f * VLen(axis);
|
||||
gradient = new float[vertices.Length / 3];
|
||||
Vector3f v = new Vector3f();
|
||||
for (int i = 0; i < vertices.Length; i += 3)
|
||||
|
@ -54,13 +54,13 @@ public class CylinderGizmo : ColliderGizmo
|
|||
v.x = vertices[i] - center.x;
|
||||
v.y = vertices[i + 1] - center.y;
|
||||
v.z = vertices[i + 2] - center.z;
|
||||
normalize(ref v);
|
||||
gradient[i / 3] = clamp(0.57735026f * (v.x + v.y + v.z), -1, 1);
|
||||
Normalize(ref v);
|
||||
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);
|
||||
if (axis.x > 0.8)
|
||||
|
@ -69,27 +69,27 @@ public class CylinderGizmo : ColliderGizmo
|
|||
}
|
||||
|
||||
Vector3f forward = new Vector3f();
|
||||
cross(ref forward, side, axis);
|
||||
cross(ref side, axis, forward);
|
||||
normalize(ref side);
|
||||
Cross(ref forward, side, axis);
|
||||
Cross(ref side, axis, forward);
|
||||
Normalize(ref 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 j = 0; j < 3; j++)
|
||||
{
|
||||
int v = triangles[i + j] * 3;
|
||||
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)));
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,32 +4,32 @@ namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
public static ColliderGizmo sphere(Vector3f center, float radius)
|
||||
public static ColliderGizmo Sphere(Vector3f center, float 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public static ColliderGizmo trimesh(float[] verts, int[] faces)
|
||||
public static ColliderGizmo Trimesh(float[] verts, int[] faces)
|
||||
{
|
||||
return new TrimeshGizmo(verts, faces);
|
||||
}
|
||||
|
||||
public static ColliderGizmo composite(params ColliderGizmo[] gizmos)
|
||||
public static ColliderGizmo Composite(params ColliderGizmo[] gizmos)
|
||||
{
|
||||
return new CompositeGizmo(gizmos);
|
||||
}
|
||||
|
|
|
@ -12,17 +12,17 @@ public class GizmoHelper
|
|||
|
||||
private static float[] sphericalVertices;
|
||||
|
||||
public static float[] generateSphericalVertices()
|
||||
public static float[] GenerateSphericalVertices()
|
||||
{
|
||||
if (sphericalVertices == null)
|
||||
{
|
||||
sphericalVertices = generateSphericalVertices(SEGMENTS, RINGS);
|
||||
sphericalVertices = GenerateSphericalVertices(SEGMENTS, RINGS);
|
||||
}
|
||||
|
||||
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)];
|
||||
// top
|
||||
|
@ -33,7 +33,7 @@ public class GizmoHelper
|
|||
for (int r = 0; r <= rings; r++)
|
||||
{
|
||||
double theta = Math.PI * (r + 1) / (rings + 2);
|
||||
vi = generateRingVertices(segments, vertices, vi, theta);
|
||||
vi = GenerateRingVertices(segments, vertices, vi, theta);
|
||||
}
|
||||
|
||||
// bottom
|
||||
|
@ -43,24 +43,24 @@ public class GizmoHelper
|
|||
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];
|
||||
int vi = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
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 sinTheta = Math.Sin(theta);
|
||||
|
@ -77,21 +77,21 @@ public class GizmoHelper
|
|||
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 ti = generateSphereUpperCapTriangles(segments, triangles, 0);
|
||||
ti = generateRingTriangles(segments, rings, triangles, 1, ti);
|
||||
generateSphereLowerCapTriangles(segments, rings, triangles, ti);
|
||||
int ti = GenerateSphereUpperCapTriangles(segments, triangles, 0);
|
||||
ti = GenerateRingTriangles(segments, rings, triangles, 1, ti);
|
||||
GenerateSphereLowerCapTriangles(segments, rings, triangles, ti);
|
||||
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++)
|
||||
{
|
||||
|
@ -113,7 +113,7 @@ public class GizmoHelper
|
|||
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++)
|
||||
{
|
||||
|
@ -125,7 +125,7 @@ public class GizmoHelper
|
|||
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);
|
||||
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[] triangles = new int[6 * (circleTriangles + (segments + 1))];
|
||||
int vi = 0;
|
||||
int ti = generateCircleTriangles(segments, triangles, vi, 0, false);
|
||||
ti = generateRingTriangles(segments, 1, triangles, segments + 1, ti);
|
||||
int ti = GenerateCircleTriangles(segments, triangles, vi, 0, false);
|
||||
ti = GenerateRingTriangles(segments, 1, triangles, segments + 1, ti);
|
||||
int vertexCount = (segments + 1) * 4;
|
||||
ti = generateCircleTriangles(segments, triangles, vertexCount - segments, ti, true);
|
||||
ti = GenerateCircleTriangles(segments, triangles, vertexCount - segments, ti, true);
|
||||
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++)
|
||||
{
|
||||
|
@ -174,7 +174,7 @@ public class GizmoHelper
|
|||
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 e1 = new Vector3f();
|
||||
|
@ -188,9 +188,9 @@ public class GizmoHelper
|
|||
normal.x = e0.y * e1.z - e0.z * e1.y;
|
||||
normal.y = e0.z * e1.x - e0.x * e1.z;
|
||||
normal.z = e0.x * e1.y - e0.y * e1.x;
|
||||
RecastVectors.normalize(ref normal);
|
||||
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),
|
||||
RecastVectors.Normalize(ref normal);
|
||||
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)(127 * (1 + c)));
|
||||
return col;
|
||||
}
|
||||
|
|
|
@ -17,26 +17,26 @@ public class SphereGizmo : ColliderGizmo
|
|||
{
|
||||
this.center = center;
|
||||
this.radius = radius;
|
||||
vertices = generateSphericalVertices();
|
||||
triangles = generateSphericalTriangles();
|
||||
vertices = GenerateSphericalVertices();
|
||||
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 j = 0; j < 3; j++)
|
||||
{
|
||||
int v = triangles[i + j] * 3;
|
||||
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),
|
||||
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)(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);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.end();
|
||||
debugDraw.End();
|
||||
}
|
||||
}
|
|
@ -13,20 +13,20 @@ public class TrimeshGizmo : ColliderGizmo
|
|||
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)
|
||||
{
|
||||
int v0 = 3 * triangles[i];
|
||||
int v1 = 3 * triangles[i + 1];
|
||||
int v2 = 3 * triangles[i + 2];
|
||||
int col = GizmoHelper.getColorByNormal(vertices, v0, v1, v2);
|
||||
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[v2], vertices[v2 + 1], vertices[v2 + 2], col);
|
||||
int col = GizmoHelper.GetColorByNormal(vertices, v0, v1, v2);
|
||||
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[v2], vertices[v2 + 1], vertices[v2 + 2], col);
|
||||
}
|
||||
|
||||
debugDraw.end();
|
||||
debugDraw.End();
|
||||
}
|
||||
}
|
|
@ -39,124 +39,124 @@ public class JumpLinkBuilderTool : Tool
|
|||
private readonly int selEdge = -1;
|
||||
private readonly JumpLinkBuilderToolParams option = new JumpLinkBuilderToolParams();
|
||||
|
||||
public override void setSample(Sample sample)
|
||||
public override void SetSample(Sample sample)
|
||||
{
|
||||
this.sample = sample;
|
||||
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 col1 = duRGBA(32, 255, 96, 255);
|
||||
RecastDebugDraw dd = renderer.getDebugDraw();
|
||||
dd.depthMask(false);
|
||||
int col0 = DuLerpCol(DuRGBA(32, 255, 96, 255), DuRGBA(255, 255, 255, 255), 200);
|
||||
int col1 = DuRGBA(32, 255, 96, 255);
|
||||
RecastDebugDraw dd = renderer.GetDebugDraw();
|
||||
dd.DepthMask(false);
|
||||
|
||||
if ((option.flags & JumpLinkBuilderToolParams.DRAW_WALKABLE_BORDER) != 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int col = duRGBA(0, 96, 128, 255);
|
||||
int col = DuRGBA(0, 96, 128, 255);
|
||||
if (i == selEdge)
|
||||
continue;
|
||||
dd.vertex(edges[i].sp, col);
|
||||
dd.vertex(edges[i].sq, col);
|
||||
dd.Vertex(edges[i].sp, 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)
|
||||
{
|
||||
int col = duRGBA(0, 96, 128, 255);
|
||||
int col = DuRGBA(0, 96, 128, 255);
|
||||
if (i == selEdge)
|
||||
continue;
|
||||
dd.vertex(edges[i].sp, col);
|
||||
dd.vertex(edges[i].sq, col);
|
||||
dd.Vertex(edges[i].sp, col);
|
||||
dd.Vertex(edges[i].sq, col);
|
||||
}
|
||||
|
||||
dd.end();
|
||||
dd.End();
|
||||
|
||||
if (selEdge >= 0 && selEdge < edges.Length)
|
||||
{
|
||||
int col = duRGBA(48, 16, 16, 255); // duRGBA(255,192,0,255);
|
||||
dd.begin(LINES, 3.0f);
|
||||
dd.vertex(edges[selEdge].sp, col);
|
||||
dd.vertex(edges[selEdge].sq, col);
|
||||
dd.end();
|
||||
dd.begin(POINTS, 8.0f);
|
||||
dd.vertex(edges[selEdge].sp, col);
|
||||
dd.vertex(edges[selEdge].sq, col);
|
||||
dd.end();
|
||||
int col = DuRGBA(48, 16, 16, 255); // DuRGBA(255,192,0,255);
|
||||
dd.Begin(LINES, 3.0f);
|
||||
dd.Vertex(edges[selEdge].sp, col);
|
||||
dd.Vertex(edges[selEdge].sq, col);
|
||||
dd.End();
|
||||
dd.Begin(POINTS, 8.0f);
|
||||
dd.Vertex(edges[selEdge].sp, col);
|
||||
dd.Vertex(edges[selEdge].sq, col);
|
||||
dd.End();
|
||||
}
|
||||
|
||||
dd.begin(POINTS, 4.0f);
|
||||
dd.Begin(POINTS, 4.0f);
|
||||
for (int i = 0; i < edges.Length; ++i)
|
||||
{
|
||||
int col = duRGBA(190, 190, 190, 255);
|
||||
dd.vertex(edges[i].sp, col);
|
||||
dd.vertex(edges[i].sq, col);
|
||||
int col = DuRGBA(190, 190, 190, 255);
|
||||
dd.Vertex(edges[i].sp, col);
|
||||
dd.Vertex(edges[i].sq, col);
|
||||
}
|
||||
|
||||
dd.end();
|
||||
dd.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((option.flags & JumpLinkBuilderToolParams.DRAW_ANNOTATIONS) != 0)
|
||||
{
|
||||
dd.begin(QUADS);
|
||||
dd.Begin(QUADS);
|
||||
foreach (JumpLink link in links)
|
||||
{
|
||||
for (int j = 0; j < link.nspine - 1; ++j)
|
||||
{
|
||||
int u = (j * 255) / link.nspine;
|
||||
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 + 1) * 3], link.spine1[(j + 1) * 3 + 1], link.spine1[(j + 1) * 3 + 2],
|
||||
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 + 1) * 3], link.spine1[(j + 1) * 3 + 1], link.spine1[(j + 1) * 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);
|
||||
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.begin(LINES, 3.0f);
|
||||
dd.End();
|
||||
dd.Begin(LINES, 3.0f);
|
||||
foreach (JumpLink link in links)
|
||||
{
|
||||
for (int j = 0; j < link.nspine - 1; ++j)
|
||||
{
|
||||
// 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 + 1) * 3], link.spine0[(j + 1) * 3 + 1], link.spine0[(j + 1) * 3 + 2],
|
||||
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],
|
||||
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 * 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],
|
||||
col);
|
||||
}
|
||||
|
||||
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.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.spine0[(link.nspine - 1) * 3], link.spine0[(link.nspine - 1) * 3 + 1],
|
||||
link.spine0[(link.nspine - 1) * 3 + 2], duDarkenCol(col1));
|
||||
dd.vertex(link.spine1[(link.nspine - 1) * 3], link.spine1[(link.nspine - 1) * 3 + 1],
|
||||
link.spine1[(link.nspine - 1) * 3 + 2], duDarkenCol(col1));
|
||||
dd.Vertex(link.spine0[(link.nspine - 1) * 3], link.spine0[(link.nspine - 1) * 3 + 1],
|
||||
link.spine0[(link.nspine - 1) * 3 + 2], DuDarkenCol(col1));
|
||||
dd.Vertex(link.spine1[(link.nspine - 1) * 3], link.spine1[(link.nspine - 1) * 3 + 1],
|
||||
link.spine1[(link.nspine - 1) * 3 + 2], DuDarkenCol(col1));
|
||||
}
|
||||
|
||||
dd.end();
|
||||
dd.End();
|
||||
}
|
||||
|
||||
if (annotationBuilder != null)
|
||||
|
@ -167,97 +167,97 @@ public class JumpLinkBuilderTool : Tool
|
|||
{
|
||||
float r = link.start.height;
|
||||
|
||||
int col = duLerpCol(duRGBA(255, 192, 0, 255),
|
||||
duRGBA(255, 255, 255, 255), 64);
|
||||
int cola = duTransCol(col, 192);
|
||||
int colb = duRGBA(255, 255, 255, 255);
|
||||
int col = DuLerpCol(DuRGBA(255, 192, 0, 255),
|
||||
DuRGBA(255, 255, 255, 255), 64);
|
||||
int cola = DuTransCol(col, 192);
|
||||
int colb = DuRGBA(255, 255, 255, 255);
|
||||
|
||||
// Start segment.
|
||||
dd.begin(LINES, 3.0f);
|
||||
dd.vertex(link.start.p, col);
|
||||
dd.vertex(link.start.q, col);
|
||||
dd.end();
|
||||
dd.Begin(LINES, 3.0f);
|
||||
dd.Vertex(link.start.p, col);
|
||||
dd.Vertex(link.start.q, col);
|
||||
dd.End();
|
||||
|
||||
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 + 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, 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.end();
|
||||
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 + 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, 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.End();
|
||||
|
||||
GroundSegment end = link.end;
|
||||
r = end.height;
|
||||
// End segment.
|
||||
dd.begin(LINES, 3.0f);
|
||||
dd.vertex(end.p, col);
|
||||
dd.vertex(end.q, col);
|
||||
dd.end();
|
||||
dd.Begin(LINES, 3.0f);
|
||||
dd.Vertex(end.p, col);
|
||||
dd.Vertex(end.q, col);
|
||||
dd.End();
|
||||
|
||||
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 + 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, 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.end();
|
||||
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 + 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, 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.End();
|
||||
|
||||
dd.begin(LINES, 4.0f);
|
||||
drawTrajectory(dd, link, link.start.p, end.p, link.trajectory, cola);
|
||||
drawTrajectory(dd, link, link.start.q, end.q, link.trajectory, cola);
|
||||
dd.end();
|
||||
dd.Begin(LINES, 4.0f);
|
||||
DrawTrajectory(dd, link, link.start.p, end.p, link.trajectory, cola);
|
||||
DrawTrajectory(dd, link, link.start.q, end.q, link.trajectory, cola);
|
||||
dd.End();
|
||||
|
||||
dd.begin(LINES, 8.0f);
|
||||
dd.vertex(link.start.p, duDarkenCol(col));
|
||||
dd.vertex(link.start.q, duDarkenCol(col));
|
||||
dd.vertex(end.p, duDarkenCol(col));
|
||||
dd.vertex(end.q, duDarkenCol(col));
|
||||
dd.end();
|
||||
dd.Begin(LINES, 8.0f);
|
||||
dd.Vertex(link.start.p, DuDarkenCol(col));
|
||||
dd.Vertex(link.start.q, DuDarkenCol(col));
|
||||
dd.Vertex(end.p, DuDarkenCol(col));
|
||||
dd.Vertex(end.q, DuDarkenCol(col));
|
||||
dd.End();
|
||||
|
||||
int colm = duRGBA(255, 255, 255, 255);
|
||||
dd.begin(LINES, 3.0f);
|
||||
dd.vertex(link.start.p, colm);
|
||||
dd.vertex(link.start.q, colm);
|
||||
dd.vertex(end.p, colm);
|
||||
dd.vertex(end.q, colm);
|
||||
dd.end();
|
||||
int colm = DuRGBA(255, 255, 255, 255);
|
||||
dd.Begin(LINES, 3.0f);
|
||||
dd.Vertex(link.start.p, colm);
|
||||
dd.Vertex(link.start.q, colm);
|
||||
dd.Vertex(end.p, colm);
|
||||
dd.Vertex(end.q, colm);
|
||||
dd.End();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
GroundSample s = link.start.gsamples[i];
|
||||
float u = i / (float)(link.start.gsamples.Length - 1);
|
||||
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);
|
||||
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);
|
||||
float off = 0.1f;
|
||||
if (!s.validHeight)
|
||||
{
|
||||
off = 0;
|
||||
col = duRGBA(220, 32, 32, 255);
|
||||
col = DuRGBA(220, 32, 32, 255);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
GroundSample s = link.start.gsamples[i];
|
||||
float u = i / (float)(link.start.gsamples.Length - 1);
|
||||
Vector3f spt = vLerp(link.start.p, link.start.q, u);
|
||||
int col = duRGBA(255, 255, 255, 255);
|
||||
Vector3f spt = VLerp(link.start.p, link.start.q, u);
|
||||
int col = DuRGBA(255, 255, 255, 255);
|
||||
float off = 0;
|
||||
if (s.validHeight)
|
||||
{
|
||||
|
@ -265,38 +265,38 @@ public class JumpLinkBuilderTool : Tool
|
|||
}
|
||||
|
||||
spt.y = s.p.y + off;
|
||||
dd.vertex(spt, col);
|
||||
dd.Vertex(spt, col);
|
||||
}
|
||||
|
||||
dd.end();
|
||||
dd.End();
|
||||
{
|
||||
GroundSegment end = link.end;
|
||||
dd.begin(POINTS, 8.0f);
|
||||
dd.Begin(POINTS, 8.0f);
|
||||
for (int i = 0; i < end.gsamples.Length; ++i)
|
||||
{
|
||||
GroundSample s = end.gsamples[i];
|
||||
float u = i / (float)(end.gsamples.Length - 1);
|
||||
Vector3f spt = vLerp(end.p, end.q, u);
|
||||
int col = duRGBA(48, 16, 16, 255); // duRGBA(255,(s->flags & 4)?255:0,0,255);
|
||||
Vector3f spt = VLerp(end.p, end.q, u);
|
||||
int col = DuRGBA(48, 16, 16, 255); // DuRGBA(255,(s->flags & 4)?255:0,0,255);
|
||||
float off = 0.1f;
|
||||
if (!s.validHeight)
|
||||
{
|
||||
off = 0;
|
||||
col = duRGBA(220, 32, 32, 255);
|
||||
col = DuRGBA(220, 32, 32, 255);
|
||||
}
|
||||
|
||||
spt.y = s.p.y + off;
|
||||
dd.vertex(spt, col);
|
||||
dd.Vertex(spt, col);
|
||||
}
|
||||
|
||||
dd.end();
|
||||
dd.begin(POINTS, 4.0f);
|
||||
dd.End();
|
||||
dd.Begin(POINTS, 4.0f);
|
||||
for (int i = 0; i < end.gsamples.Length; ++i)
|
||||
{
|
||||
GroundSample s = end.gsamples[i];
|
||||
float u = i / (float)(end.gsamples.Length - 1);
|
||||
Vector3f spt = vLerp(end.p, end.q, u);
|
||||
int col = duRGBA(255, 255, 255, 255);
|
||||
Vector3f spt = VLerp(end.p, end.q, u);
|
||||
int col = DuRGBA(255, 255, 255, 255);
|
||||
float off = 0;
|
||||
if (s.validHeight)
|
||||
{
|
||||
|
@ -304,29 +304,29 @@ public class JumpLinkBuilderTool : Tool
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
ImGui.Text("Options");
|
||||
|
@ -371,27 +371,27 @@ public class JumpLinkBuilderTool : Tool
|
|||
{
|
||||
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();
|
||||
if (annotationBuilder != null)
|
||||
{
|
||||
float cellSize = sample.getSettingsUI().getCellSize();
|
||||
float agentHeight = sample.getSettingsUI().getAgentHeight();
|
||||
float agentRadius = sample.getSettingsUI().getAgentRadius();
|
||||
float agentClimb = sample.getSettingsUI().getAgentMaxClimb();
|
||||
float cellHeight = sample.getSettingsUI().getCellHeight();
|
||||
float cellSize = sample.GetSettingsUI().GetCellSize();
|
||||
float agentHeight = sample.GetSettingsUI().GetAgentHeight();
|
||||
float agentRadius = sample.GetSettingsUI().GetAgentRadius();
|
||||
float agentClimb = sample.GetSettingsUI().GetAgentMaxClimb();
|
||||
float cellHeight = sample.GetSettingsUI().GetCellHeight();
|
||||
if ((option.buildTypes & JumpLinkType.EDGE_CLIMB_DOWN.Bit) != 0)
|
||||
{
|
||||
JumpLinkBuilderConfig config = new JumpLinkBuilderConfig(cellSize, cellHeight, agentRadius,
|
||||
agentHeight, agentClimb, option.groundTolerance, -agentRadius * 0.2f,
|
||||
cellSize + 2 * agentRadius + option.climbDownDistance,
|
||||
-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)
|
||||
|
@ -400,17 +400,17 @@ public class JumpLinkBuilderTool : Tool
|
|||
agentHeight, agentClimb, option.groundTolerance, -agentRadius * 0.2f,
|
||||
option.edgeJumpEndDistance, -option.edgeJumpDownMaxHeight,
|
||||
option.edgeJumpUpMaxHeight, option.edgeJumpHeight);
|
||||
links.AddRange(annotationBuilder.build(config, JumpLinkType.EDGE_JUMP));
|
||||
links.AddRange(annotationBuilder.Build(config, JumpLinkType.EDGE_JUMP));
|
||||
}
|
||||
|
||||
if (buildOffMeshConnections)
|
||||
{
|
||||
DemoInputGeomProvider geom = sample.getInputGeom();
|
||||
DemoInputGeomProvider geom = sample.GetInputGeom();
|
||||
if (geom != null)
|
||||
{
|
||||
int area = SampleAreaModifications.SAMPLE_POLYAREA_TYPE_JUMP_AUTO;
|
||||
geom.removeOffMeshConnections(c => c.area == area);
|
||||
links.forEach(l => addOffMeshLink(l, geom, agentRadius));
|
||||
geom.RemoveOffMeshConnections(c => c.area == area);
|
||||
links.ForEach(l => AddOffMeshLink(l, geom, agentRadius));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -427,7 +427,7 @@ public class JumpLinkBuilderTool : Tool
|
|||
//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 flags = SampleAreaModifications.SAMPLE_POLYFLAGS_JUMP;
|
||||
|
@ -436,15 +436,15 @@ public class JumpLinkBuilderTool : Tool
|
|||
{
|
||||
Vector3f p = link.startSamples[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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string getName()
|
||||
public override string GetName()
|
||||
{
|
||||
return "Annotation Builder";
|
||||
}
|
||||
|
|
|
@ -36,14 +36,14 @@ public class OffMeshConnectionTool : Tool
|
|||
private Vector3f hitPos;
|
||||
private int bidir;
|
||||
|
||||
public override void setSample(Sample m_sample)
|
||||
public override void SetSample(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)
|
||||
{
|
||||
return;
|
||||
|
@ -55,10 +55,10 @@ public class OffMeshConnectionTool : Tool
|
|||
// Find nearest link end-point
|
||||
float nearestDist = float.MaxValue;
|
||||
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));
|
||||
if (d < nearestDist && Math.Sqrt(d) < sample.getSettingsUI().getAgentRadius())
|
||||
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())
|
||||
{
|
||||
nearestDist = d;
|
||||
nearestConnection = offMeshCon;
|
||||
|
@ -67,7 +67,7 @@ public class OffMeshConnectionTool : Tool
|
|||
|
||||
if (nearestConnection != null)
|
||||
{
|
||||
geom.getOffMeshConnections().Remove(nearestConnection);
|
||||
geom.GetOffMeshConnections().Remove(nearestConnection);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -82,46 +82,46 @@ public class OffMeshConnectionTool : Tool
|
|||
{
|
||||
int area = SampleAreaModifications.SAMPLE_POLYAREA_TYPE_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void handleRender(NavMeshRenderer renderer)
|
||||
public override void HandleRender(NavMeshRenderer renderer)
|
||||
{
|
||||
if (sample == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RecastDebugDraw dd = renderer.getDebugDraw();
|
||||
float s = sample.getSettingsUI().getAgentRadius();
|
||||
RecastDebugDraw dd = renderer.GetDebugDraw();
|
||||
float s = sample.GetSettingsUI().GetAgentRadius();
|
||||
|
||||
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)
|
||||
{
|
||||
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("Bidirectional", ref bidir, 1);
|
||||
}
|
||||
|
||||
public override string getName()
|
||||
public override string GetName()
|
||||
{
|
||||
return "Create Off-Mesh Links";
|
||||
}
|
||||
|
||||
public override void handleUpdate(float dt)
|
||||
public override void HandleUpdate(float dt)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,19 +26,19 @@ namespace DotRecast.Recast.Demo.Tools;
|
|||
|
||||
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)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
|
|
@ -22,5 +22,5 @@ namespace DotRecast.Recast.Demo.Tools;
|
|||
|
||||
public interface ToolUIModule
|
||||
{
|
||||
void layout(IWindow ctx);
|
||||
void Layout(IWindow ctx);
|
||||
}
|
|
@ -59,9 +59,9 @@ public class RcSettingsView : IRcView
|
|||
private bool tiled = false;
|
||||
private int tileSize = 32;
|
||||
|
||||
// public readonly NkColor white = NkColor.create();
|
||||
// public readonly NkColor background = NkColor.create();
|
||||
// public readonly NkColor transparent = NkColor.create();
|
||||
// public readonly NkColor white = NkColor.Create();
|
||||
// public readonly NkColor background = NkColor.Create();
|
||||
// public readonly NkColor transparent = NkColor.Create();
|
||||
private bool buildTriggered;
|
||||
private long buildTime;
|
||||
private readonly int[] voxels = new int[2];
|
||||
|
@ -154,7 +154,7 @@ public class RcSettingsView : IRcView
|
|||
|
||||
ImGui.Text("Partitioning");
|
||||
ImGui.Separator();
|
||||
PartitionType.Values.forEach(partition =>
|
||||
PartitionType.Values.ForEach(partition =>
|
||||
{
|
||||
var label = partition.Name.Substring(0, 1).ToUpper()
|
||||
+ partition.Name.Substring(1).ToLower();
|
||||
|
@ -226,145 +226,145 @@ public class RcSettingsView : IRcView
|
|||
ImGui.Text("Draw");
|
||||
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.End();
|
||||
}
|
||||
|
||||
public float getCellSize()
|
||||
public float GetCellSize()
|
||||
{
|
||||
return cellSize;
|
||||
}
|
||||
|
||||
public float getCellHeight()
|
||||
public float GetCellHeight()
|
||||
{
|
||||
return cellHeight;
|
||||
}
|
||||
|
||||
public float getAgentHeight()
|
||||
public float GetAgentHeight()
|
||||
{
|
||||
return agentHeight;
|
||||
}
|
||||
|
||||
public float getAgentRadius()
|
||||
public float GetAgentRadius()
|
||||
{
|
||||
return agentRadius;
|
||||
}
|
||||
|
||||
public float getAgentMaxClimb()
|
||||
public float GetAgentMaxClimb()
|
||||
{
|
||||
return agentMaxClimb;
|
||||
}
|
||||
|
||||
public float getAgentMaxSlope()
|
||||
public float GetAgentMaxSlope()
|
||||
{
|
||||
return agentMaxSlope;
|
||||
}
|
||||
|
||||
public int getMinRegionSize()
|
||||
public int GetMinRegionSize()
|
||||
{
|
||||
return minRegionSize;
|
||||
}
|
||||
|
||||
public int getMergedRegionSize()
|
||||
public int GetMergedRegionSize()
|
||||
{
|
||||
return mergedRegionSize;
|
||||
}
|
||||
|
||||
public PartitionType getPartitioning()
|
||||
public PartitionType GetPartitioning()
|
||||
{
|
||||
return partitioning;
|
||||
}
|
||||
|
||||
public bool isBuildTriggered()
|
||||
public bool IsBuildTriggered()
|
||||
{
|
||||
return buildTriggered;
|
||||
}
|
||||
|
||||
public bool isFilterLowHangingObstacles()
|
||||
public bool IsFilterLowHangingObstacles()
|
||||
{
|
||||
return filterLowHangingObstacles;
|
||||
}
|
||||
|
||||
public bool isFilterLedgeSpans()
|
||||
public bool IsFilterLedgeSpans()
|
||||
{
|
||||
return filterLedgeSpans;
|
||||
}
|
||||
|
||||
public bool isFilterWalkableLowHeightSpans()
|
||||
public bool IsFilterWalkableLowHeightSpans()
|
||||
{
|
||||
return filterWalkableLowHeightSpans;
|
||||
}
|
||||
|
||||
public void setBuildTime(long buildTime)
|
||||
public void SetBuildTime(long buildTime)
|
||||
{
|
||||
this.buildTime = buildTime;
|
||||
}
|
||||
|
||||
public DrawMode getDrawMode()
|
||||
public DrawMode GetDrawMode()
|
||||
{
|
||||
return DrawMode.Values[drawMode];
|
||||
}
|
||||
|
||||
public float getEdgeMaxLen()
|
||||
public float GetEdgeMaxLen()
|
||||
{
|
||||
return edgeMaxLen;
|
||||
}
|
||||
|
||||
public float getEdgeMaxError()
|
||||
public float GetEdgeMaxError()
|
||||
{
|
||||
return edgeMaxError;
|
||||
}
|
||||
|
||||
public int getVertsPerPoly()
|
||||
public int GetVertsPerPoly()
|
||||
{
|
||||
return vertsPerPoly;
|
||||
}
|
||||
|
||||
public float getDetailSampleDist()
|
||||
public float GetDetailSampleDist()
|
||||
{
|
||||
return detailSampleDist;
|
||||
}
|
||||
|
||||
public float getDetailSampleMaxError()
|
||||
public float GetDetailSampleMaxError()
|
||||
{
|
||||
return detailSampleMaxError;
|
||||
}
|
||||
|
||||
public void setVoxels(int[] voxels)
|
||||
public void SetVoxels(int[] voxels)
|
||||
{
|
||||
this.voxels[0] = voxels[0];
|
||||
this.voxels[1] = voxels[1];
|
||||
}
|
||||
|
||||
public bool isTiled()
|
||||
public bool IsTiled()
|
||||
{
|
||||
return tiled;
|
||||
}
|
||||
|
||||
public int getTileSize()
|
||||
public int GetTileSize()
|
||||
{
|
||||
return tileSize;
|
||||
}
|
||||
|
||||
public void setTiles(int[] tiles)
|
||||
public void SetTiles(int[] tiles)
|
||||
{
|
||||
this.tiles[0] = tiles[0];
|
||||
this.tiles[1] = tiles[1];
|
||||
}
|
||||
|
||||
public void setMaxTiles(int maxTiles)
|
||||
public void SetMaxTiles(int maxTiles)
|
||||
{
|
||||
this.maxTiles = maxTiles;
|
||||
}
|
||||
|
||||
public void setMaxPolys(int maxPolys)
|
||||
public void SetMaxPolys(int maxPolys)
|
||||
{
|
||||
this.maxPolys = maxPolys;
|
||||
}
|
||||
|
||||
public bool isMeshInputTrigerred()
|
||||
public bool IsMeshInputTrigerred()
|
||||
{
|
||||
return meshInputTrigerred;
|
||||
}
|
||||
|
@ -374,7 +374,7 @@ public class RcSettingsView : IRcView
|
|||
return meshInputFilePath;
|
||||
}
|
||||
|
||||
public bool isNavMeshInputTrigerred()
|
||||
public bool IsNavMeshInputTrigerred()
|
||||
{
|
||||
return navMeshInputTrigerred;
|
||||
}
|
||||
|
|
|
@ -47,54 +47,54 @@ public class RecastDemoCanvas
|
|||
view.Bind(this);
|
||||
}
|
||||
|
||||
// setupClipboard(window);
|
||||
// glfwSetCharCallback(window, (w, codepoint) => nk_input_unicode(ctx, codepoint));
|
||||
// SetupClipboard(window);
|
||||
// GlfwSetCharCallback(window, (w, codepoint) => Nk_input_unicode(ctx, codepoint));
|
||||
// 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) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// try (MemoryStack stack = stackPush()) {
|
||||
// ByteBuffer str = stack.malloc(len + 1);
|
||||
// memCopy(text, memAddress(str), len);
|
||||
// str.put(len, (byte) 0);
|
||||
// glfwSetClipboardString(window, str);
|
||||
// try (MemoryStack stack = StackPush()) {
|
||||
// ByteBuffer str = stack.Malloc(len + 1);
|
||||
// MemCopy(text, MemAddress(str), len);
|
||||
// str.Put(len, (byte) 0);
|
||||
// GlfwSetClipboardString(window, str);
|
||||
// }
|
||||
// });
|
||||
// ctx.clip().paste((handle, edit) => {
|
||||
// long text = nglfwGetClipboardString(window);
|
||||
// ctx.Clip().paste((handle, edit) => {
|
||||
// long text = NglfwGetClipboardString(window);
|
||||
// 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();
|
||||
// if (mouse.grab()) {
|
||||
// glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
// } else if (mouse.grabbed()) {
|
||||
// float prevX = mouse.prev().x();
|
||||
// float prevY = mouse.prev().y();
|
||||
// glfwSetCursorPos(win, prevX, prevY);
|
||||
// mouse.pos().x(prevX);
|
||||
// mouse.pos().y(prevY);
|
||||
// } else if (mouse.ungrab()) {
|
||||
// glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
// NkMouse mouse = ctx.Input().Mouse();
|
||||
// if (mouse.Grab()) {
|
||||
// GlfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
// } else if (mouse.Grabbed()) {
|
||||
// float prevX = mouse.Prev().x();
|
||||
// float prevY = mouse.Prev().y();
|
||||
// GlfwSetCursorPos(win, prevX, prevY);
|
||||
// mouse.Pos().x(prevX);
|
||||
// mouse.Pos().y(prevY);
|
||||
// } else if (mouse.Ungrab()) {
|
||||
// GlfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
// }
|
||||
// nk_input_end(ctx);
|
||||
// Nk_input_end(ctx);
|
||||
}
|
||||
|
||||
public void Update(double dt)
|
||||
|
|
|
@ -17,17 +17,17 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Recast.Demo.Tools;
|
||||
using DotRecast.Recast.Demo.UI;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace DotRecast.Recast.Demo.UI;
|
||||
|
||||
public class ToolsView : IRcView
|
||||
{
|
||||
//private readonly NkColor white = NkColor.create();
|
||||
//private readonly NkColor white = NkColor.Create();
|
||||
private int _currentToolIdx = 0;
|
||||
private Tool currentTool;
|
||||
private bool enabled;
|
||||
|
@ -64,7 +64,7 @@ public class ToolsView : IRcView
|
|||
for (int i = 0; i < tools.Length; ++i)
|
||||
{
|
||||
var tool = tools[i];
|
||||
ImGui.RadioButton(tool.getName(), ref _currentToolIdx, i);
|
||||
ImGui.RadioButton(tool.GetName(), ref _currentToolIdx, i);
|
||||
}
|
||||
|
||||
ImGui.NewLine();
|
||||
|
@ -76,30 +76,30 @@ public class ToolsView : IRcView
|
|||
}
|
||||
|
||||
currentTool = tools[_currentToolIdx];
|
||||
ImGui.Text(currentTool.getName());
|
||||
ImGui.Text(currentTool.GetName());
|
||||
ImGui.Separator();
|
||||
currentTool.layout();
|
||||
currentTool.Layout();
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
|
||||
public void setEnabled(bool enabled)
|
||||
public void SetEnabled(bool enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public Tool getTool()
|
||||
public Tool GetTool()
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
|
@ -58,12 +58,12 @@ namespace DotRecast.Recast
|
|||
Mask = other.Mask;
|
||||
}
|
||||
|
||||
public int getMaskedValue()
|
||||
public int GetMaskedValue()
|
||||
{
|
||||
return Value & Mask;
|
||||
}
|
||||
|
||||
public int apply(int area)
|
||||
public int Apply(int area)
|
||||
{
|
||||
return ((Value & Mask) | (area & ~Mask));
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace DotRecast.Recast.Geom
|
|||
int ntris;
|
||||
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.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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -101,7 +101,7 @@ namespace DotRecast.Recast.Geom
|
|||
if (inum <= trisPerChunk)
|
||||
{
|
||||
// Leaf
|
||||
calcExtends(items, imin, imax, ref node.bmin, ref node.bmax);
|
||||
CalcExtends(items, imin, imax, ref node.bmin, ref node.bmax);
|
||||
|
||||
// Copy triangles.
|
||||
node.i = nodes.Count;
|
||||
|
@ -119,9 +119,9 @@ namespace DotRecast.Recast.Geom
|
|||
else
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
|
@ -137,9 +137,9 @@ namespace DotRecast.Recast.Geom
|
|||
int isplit = imin + inum / 2;
|
||||
|
||||
// Left
|
||||
subdivide(items, imin, isplit, trisPerChunk, nodes, inTris);
|
||||
Subdivide(items, imin, isplit, trisPerChunk, nodes, inTris);
|
||||
// Right
|
||||
subdivide(items, isplit, imax, trisPerChunk, nodes, inTris);
|
||||
Subdivide(items, isplit, imax, trisPerChunk, nodes, inTris);
|
||||
|
||||
// Negative index means escape.
|
||||
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.
|
||||
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;
|
||||
overlap = (amin[0] > bmax.x || amax[0] < bmin.x) ? false : overlap;
|
||||
|
@ -216,7 +216,7 @@ namespace DotRecast.Recast.Geom
|
|||
return overlap;
|
||||
}
|
||||
|
||||
public List<ChunkyTriMeshNode> getChunksOverlappingRect(float[] bmin, float[] bmax)
|
||||
public List<ChunkyTriMeshNode> GetChunksOverlappingRect(float[] bmin, float[] bmax)
|
||||
{
|
||||
// Traverse tree
|
||||
List<ChunkyTriMeshNode> ids = new List<ChunkyTriMeshNode>();
|
||||
|
@ -224,7 +224,7 @@ namespace DotRecast.Recast.Geom
|
|||
while (i < nodes.Count)
|
||||
{
|
||||
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;
|
||||
|
||||
if (isLeafNode && overlap)
|
||||
|
@ -245,7 +245,7 @@ namespace DotRecast.Recast.Geom
|
|||
return ids;
|
||||
}
|
||||
|
||||
public List<ChunkyTriMeshNode> getChunksOverlappingSegment(float[] p, float[] q)
|
||||
public List<ChunkyTriMeshNode> GetChunksOverlappingSegment(float[] p, float[] q)
|
||||
{
|
||||
// Traverse tree
|
||||
List<ChunkyTriMeshNode> ids = new List<ChunkyTriMeshNode>();
|
||||
|
@ -253,7 +253,7 @@ namespace DotRecast.Recast.Geom
|
|||
while (i < nodes.Count)
|
||||
{
|
||||
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;
|
||||
|
||||
if (isLeafNode && overlap)
|
||||
|
@ -274,7 +274,7 @@ namespace DotRecast.Recast.Geom
|
|||
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;
|
||||
|
||||
|
|
|
@ -22,6 +22,6 @@ namespace DotRecast.Recast.Geom
|
|||
{
|
||||
public interface ConvexVolumeProvider
|
||||
{
|
||||
IList<ConvexVolume> convexVolumes();
|
||||
IList<ConvexVolume> ConvexVolumes();
|
||||
}
|
||||
}
|
|
@ -25,10 +25,10 @@ namespace DotRecast.Recast.Geom
|
|||
{
|
||||
public interface InputGeomProvider : ConvexVolumeProvider
|
||||
{
|
||||
Vector3f getMeshBoundsMin();
|
||||
Vector3f GetMeshBoundsMin();
|
||||
|
||||
Vector3f getMeshBoundsMax();
|
||||
Vector3f GetMeshBoundsMax();
|
||||
|
||||
IEnumerable<TriMesh> meshes();
|
||||
IEnumerable<TriMesh> Meshes();
|
||||
}
|
||||
}
|
|
@ -36,11 +36,11 @@ namespace DotRecast.Recast.Geom
|
|||
private readonly TriMesh _mesh;
|
||||
|
||||
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];
|
||||
for (int i = 0; i < faces.Length; i++)
|
||||
|
@ -51,7 +51,7 @@ namespace DotRecast.Recast.Geom
|
|||
return faces;
|
||||
}
|
||||
|
||||
private static float[] mapVertices(List<float> vertexPositions)
|
||||
private static float[] MapVertices(List<float> vertexPositions)
|
||||
{
|
||||
float[] vertices = new float[vertexPositions.Count];
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
|
@ -67,36 +67,36 @@ namespace DotRecast.Recast.Geom
|
|||
this.vertices = vertices;
|
||||
this.faces = faces;
|
||||
normals = new float[faces.Length];
|
||||
calculateNormals();
|
||||
CalculateNormals();
|
||||
bmin = Vector3f.Zero;
|
||||
bmax = Vector3f.Zero;
|
||||
RecastVectors.copy(ref bmin, vertices, 0);
|
||||
RecastVectors.copy(ref bmax, vertices, 0);
|
||||
RecastVectors.Copy(ref bmin, vertices, 0);
|
||||
RecastVectors.Copy(ref bmax, vertices, 0);
|
||||
for (int i = 1; i < vertices.Length / 3; i++)
|
||||
{
|
||||
RecastVectors.min(ref bmin, vertices, i * 3);
|
||||
RecastVectors.max(ref bmax, vertices, i * 3);
|
||||
RecastVectors.Min(ref bmin, vertices, i * 3);
|
||||
RecastVectors.Max(ref bmax, vertices, i * 3);
|
||||
}
|
||||
|
||||
_mesh = new TriMesh(vertices, faces);
|
||||
}
|
||||
|
||||
public Vector3f getMeshBoundsMin()
|
||||
public Vector3f GetMeshBoundsMin()
|
||||
{
|
||||
return bmin;
|
||||
}
|
||||
|
||||
public Vector3f getMeshBoundsMax()
|
||||
public Vector3f GetMeshBoundsMax()
|
||||
{
|
||||
return bmax;
|
||||
}
|
||||
|
||||
public IList<ConvexVolume> convexVolumes()
|
||||
public IList<ConvexVolume> ConvexVolumes()
|
||||
{
|
||||
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();
|
||||
vol.hmin = minh;
|
||||
|
@ -106,12 +106,12 @@ namespace DotRecast.Recast.Geom
|
|||
volumes.Add(vol);
|
||||
}
|
||||
|
||||
public IEnumerable<TriMesh> meshes()
|
||||
public IEnumerable<TriMesh> Meshes()
|
||||
{
|
||||
return ImmutableArray.Create(_mesh);
|
||||
}
|
||||
|
||||
public void calculateNormals()
|
||||
public void CalculateNormals()
|
||||
{
|
||||
for (int i = 0; i < faces.Length; i += 3)
|
||||
{
|
||||
|
|
|
@ -33,33 +33,33 @@ namespace DotRecast.Recast.Geom
|
|||
{
|
||||
bmin = Vector3f.Zero;
|
||||
bmax = Vector3f.Zero;
|
||||
RecastVectors.copy(ref bmin, vertices, 0);
|
||||
RecastVectors.copy(ref bmax, vertices, 0);
|
||||
RecastVectors.Copy(ref bmin, vertices, 0);
|
||||
RecastVectors.Copy(ref bmax, vertices, 0);
|
||||
for (int i = 1; i < vertices.Length / 3; i++)
|
||||
{
|
||||
RecastVectors.min(ref bmin, vertices, i * 3);
|
||||
RecastVectors.max(ref bmax, vertices, i * 3);
|
||||
RecastVectors.Min(ref bmin, vertices, i * 3);
|
||||
RecastVectors.Max(ref bmax, vertices, i * 3);
|
||||
}
|
||||
|
||||
_mesh = new TriMesh(vertices, faces);
|
||||
}
|
||||
|
||||
public Vector3f getMeshBoundsMin()
|
||||
public Vector3f GetMeshBoundsMin()
|
||||
{
|
||||
return bmin;
|
||||
}
|
||||
|
||||
public Vector3f getMeshBoundsMax()
|
||||
public Vector3f GetMeshBoundsMax()
|
||||
{
|
||||
return bmax;
|
||||
}
|
||||
|
||||
public IEnumerable<TriMesh> meshes()
|
||||
public IEnumerable<TriMesh> Meshes()
|
||||
{
|
||||
return ImmutableArray.Create(_mesh);
|
||||
}
|
||||
|
||||
public IList<ConvexVolume> convexVolumes()
|
||||
public IList<ConvexVolume> ConvexVolumes()
|
||||
{
|
||||
return ImmutableArray<ConvexVolume>.Empty;
|
||||
}
|
||||
|
|
|
@ -35,19 +35,19 @@ namespace DotRecast.Recast.Geom
|
|||
chunkyTriMesh = new ChunkyTriMesh(vertices, faces, faces.Length / 3, 32);
|
||||
}
|
||||
|
||||
public int[] getTris()
|
||||
public int[] GetTris()
|
||||
{
|
||||
return faces;
|
||||
}
|
||||
|
||||
public float[] getVerts()
|
||||
public float[] GetVerts()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,13 +31,13 @@ namespace DotRecast.Recast
|
|||
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);
|
||||
}
|
||||
|
||||
public static ObjImporterContext loadContext(byte[] chunck)
|
||||
public static ObjImporterContext LoadContext(byte[] chunck)
|
||||
{
|
||||
ObjImporterContext context = new ObjImporterContext();
|
||||
try
|
||||
|
@ -47,7 +47,7 @@ namespace DotRecast.Recast
|
|||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
line = line.Trim();
|
||||
readLine(line, context);
|
||||
ReadLine(line, context);
|
||||
}
|
||||
}
|
||||
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"))
|
||||
{
|
||||
readVertex(line, context);
|
||||
ReadVertex(line, context);
|
||||
}
|
||||
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 "))
|
||||
{
|
||||
float[] vert = readVector3f(line);
|
||||
float[] vert = ReadVector3f(line);
|
||||
foreach (float vp in vert)
|
||||
{
|
||||
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);
|
||||
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]) };
|
||||
}
|
||||
|
||||
private static void readFace(string line, ObjImporterContext context)
|
||||
private static void ReadFace(string line, ObjImporterContext context)
|
||||
{
|
||||
string[] v = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (v.Length < 4)
|
||||
|
@ -104,21 +104,21 @@ namespace DotRecast.Recast
|
|||
|
||||
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++)
|
||||
{
|
||||
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("/");
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -24,13 +24,13 @@ namespace DotRecast.Recast
|
|||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return intersection;
|
||||
|
@ -41,7 +41,7 @@ namespace DotRecast.Recast
|
|||
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)
|
||||
{
|
||||
|
@ -63,7 +63,7 @@ namespace DotRecast.Recast
|
|||
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)
|
||||
{
|
||||
return intersection;
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
public static class PolyUtils
|
||||
{
|
||||
public static bool pointInPoly(float[] verts, Vector3f p)
|
||||
public static bool PointInPoly(float[] verts, Vector3f p)
|
||||
{
|
||||
int i, j;
|
||||
bool c = false;
|
||||
|
@ -42,7 +42,7 @@ namespace DotRecast.Recast
|
|||
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;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace DotRecast.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++)
|
||||
{
|
||||
|
@ -46,25 +46,25 @@ namespace DotRecast.Recast
|
|||
// 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) };
|
||||
}
|
||||
|
||||
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) };
|
||||
}
|
||||
|
||||
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) };
|
||||
}
|
||||
|
||||
|
||||
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 gd = gwd[1];
|
||||
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 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)
|
||||
{
|
||||
int[] areas = new int[nt];
|
||||
|
@ -88,33 +88,33 @@ namespace DotRecast.Recast
|
|||
for (int i = 0; i < nt; ++i)
|
||||
{
|
||||
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.
|
||||
if (norm.y > walkableThr)
|
||||
areas[i] = areaMod.apply(areas[i]);
|
||||
areas[i] = areaMod.Apply(areas[i]);
|
||||
}
|
||||
|
||||
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 e1 = new Vector3f();
|
||||
RecastVectors.sub(ref e0, verts, v1 * 3, v0 * 3);
|
||||
RecastVectors.sub(ref e1, verts, v2 * 3, v0 * 3);
|
||||
RecastVectors.cross(norm, e0, e1);
|
||||
RecastVectors.normalize(norm);
|
||||
RecastVectors.Sub(ref e0, verts, v1 * 3, v0 * 3);
|
||||
RecastVectors.Sub(ref e1, verts, v2 * 3, v0 * 3);
|
||||
RecastVectors.Cross(norm, e0, e1);
|
||||
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 e1 = new Vector3f();
|
||||
RecastVectors.sub(ref e0, verts, v1 * 3, v0 * 3);
|
||||
RecastVectors.sub(ref e1, verts, v2 * 3, v0 * 3);
|
||||
RecastVectors.cross(ref norm, e0, e1);
|
||||
RecastVectors.normalize(ref norm);
|
||||
RecastVectors.Sub(ref e0, verts, v1 * 3, v0 * 3);
|
||||
RecastVectors.Sub(ref e1, verts, v2 * 3, v0 * 3);
|
||||
RecastVectors.Cross(ref norm, e0, e1);
|
||||
RecastVectors.Normalize(ref norm);
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,7 +126,7 @@ namespace DotRecast.Recast
|
|||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||
///
|
||||
/// @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)
|
||||
{
|
||||
float walkableThr = (float)Math.Cos(walkableSlopeAngle / 180.0f * Math.PI);
|
||||
|
@ -136,7 +136,7 @@ namespace DotRecast.Recast
|
|||
for (int i = 0; i < nt; ++i)
|
||||
{
|
||||
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.
|
||||
if (norm.y <= walkableThr)
|
||||
areas[i] = RC_NULL_AREA;
|
||||
|
|
|
@ -35,11 +35,11 @@ namespace DotRecast.Recast
|
|||
/// This method is usually called immediately after the heightfield has been built.
|
||||
///
|
||||
/// @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 h = chf.height;
|
||||
ctx.startTimer("ERODE_AREA");
|
||||
ctx.StartTimer("ERODE_AREA");
|
||||
|
||||
int[] dist = new int[chf.spanCount];
|
||||
Array.Fill(dist, 255);
|
||||
|
@ -206,7 +206,7 @@ namespace DotRecast.Recast
|
|||
if (dist[i] < thr)
|
||||
chf.areas[i] = RC_NULL_AREA;
|
||||
|
||||
ctx.stopTimer("ERODE_AREA");
|
||||
ctx.StopTimer("ERODE_AREA");
|
||||
}
|
||||
|
||||
/// @par
|
||||
|
@ -215,12 +215,12 @@ namespace DotRecast.Recast
|
|||
/// such as #rcMarkBoxArea, #rcMarkConvexPolyArea, and #rcMarkCylinderArea.
|
||||
///
|
||||
/// @see rcCompactHeightfield
|
||||
public bool medianFilterWalkableArea(Telemetry ctx, CompactHeightfield chf)
|
||||
public bool MedianFilterWalkableArea(Telemetry ctx, CompactHeightfield chf)
|
||||
{
|
||||
int w = chf.width;
|
||||
int h = chf.height;
|
||||
|
||||
ctx.startTimer("MEDIAN_AREA");
|
||||
ctx.StartTimer("MEDIAN_AREA");
|
||||
|
||||
int[] areas = new int[chf.spanCount];
|
||||
|
||||
|
@ -273,7 +273,7 @@ namespace DotRecast.Recast
|
|||
|
||||
chf.areas = areas;
|
||||
|
||||
ctx.stopTimer("MEDIAN_AREA");
|
||||
ctx.StopTimer("MEDIAN_AREA");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -283,9 +283,9 @@ namespace DotRecast.Recast
|
|||
/// The value of spacial parameters are in world units.
|
||||
///
|
||||
/// @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 miny = (int)((bmin[1] - chf.bmin.y) / chf.ch);
|
||||
|
@ -323,16 +323,16 @@ namespace DotRecast.Recast
|
|||
if (s.y >= miny && s.y <= maxy)
|
||||
{
|
||||
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;
|
||||
int i, j;
|
||||
|
@ -357,19 +357,19 @@ namespace DotRecast.Recast
|
|||
/// projected onto the xz-plane at @p hmin, then extruded to @p hmax.
|
||||
///
|
||||
/// @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)
|
||||
{
|
||||
ctx.startTimer("MARK_CONVEXPOLY_AREA");
|
||||
ctx.StartTimer("MARK_CONVEXPOLY_AREA");
|
||||
|
||||
Vector3f bmin = new Vector3f();
|
||||
Vector3f bmax = new Vector3f();
|
||||
RecastVectors.copy(ref bmin, verts, 0);
|
||||
RecastVectors.copy(ref bmax, verts, 0);
|
||||
RecastVectors.Copy(ref bmin, verts, 0);
|
||||
RecastVectors.Copy(ref bmax, verts, 0);
|
||||
for (int i = 3; i < verts.Length; i += 3)
|
||||
{
|
||||
RecastVectors.min(ref bmin, verts, i);
|
||||
RecastVectors.max(ref bmax, verts, i);
|
||||
RecastVectors.Min(ref bmin, verts, i);
|
||||
RecastVectors.Max(ref bmax, verts, i);
|
||||
}
|
||||
|
||||
bmin.y = hmin;
|
||||
|
@ -418,19 +418,19 @@ namespace DotRecast.Recast
|
|||
p.y = 0;
|
||||
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;
|
||||
|
||||
|
@ -513,10 +513,10 @@ namespace DotRecast.Recast
|
|||
/// The value of spacial parameters are in world units.
|
||||
///
|
||||
/// @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)
|
||||
{
|
||||
ctx.startTimer("MARK_CYLINDER_AREA");
|
||||
ctx.StartTimer("MARK_CYLINDER_AREA");
|
||||
|
||||
Vector3f bmin = new Vector3f();
|
||||
Vector3f bmax = new Vector3f();
|
||||
|
@ -574,14 +574,14 @@ namespace DotRecast.Recast
|
|||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
public interface RecastBuilderProgressListener
|
||||
{
|
||||
void onProgress(int completed, int total);
|
||||
void OnProgress(int completed, int total);
|
||||
}
|
||||
|
||||
private readonly RecastBuilderProgressListener progressListener;
|
||||
|
@ -46,48 +46,48 @@ namespace DotRecast.Recast
|
|||
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 bmax = geom.getMeshBoundsMax();
|
||||
int[] twh = Recast.calcTileCount(bmin, bmax, cfg.cs, cfg.tileSizeX, cfg.tileSizeZ);
|
||||
Vector3f bmin = geom.GetMeshBoundsMin();
|
||||
Vector3f bmax = geom.GetMeshBoundsMax();
|
||||
int[] twh = Recast.CalcTileCount(bmin, bmax, cfg.cs, cfg.tileSizeX, cfg.tileSizeZ);
|
||||
int tw = twh[0];
|
||||
int th = twh[1];
|
||||
List<RecastBuilderResult> results = new List<RecastBuilderResult>();
|
||||
if (null != taskFactory)
|
||||
{
|
||||
buildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, default);
|
||||
BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, default);
|
||||
}
|
||||
else
|
||||
{
|
||||
buildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results);
|
||||
BuildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, 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 bmax = geom.getMeshBoundsMax();
|
||||
int[] twh = Recast.calcTileCount(bmin, bmax, cfg.cs, cfg.tileSizeX, cfg.tileSizeZ);
|
||||
Vector3f bmin = geom.GetMeshBoundsMin();
|
||||
Vector3f bmax = geom.GetMeshBoundsMax();
|
||||
int[] twh = Recast.CalcTileCount(bmin, bmax, cfg.cs, cfg.tileSizeX, cfg.tileSizeZ);
|
||||
int tw = twh[0];
|
||||
int th = twh[1];
|
||||
Task task;
|
||||
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
|
||||
{
|
||||
task = buildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results);
|
||||
task = BuildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
AtomicInteger counter = new AtomicInteger(0);
|
||||
|
@ -95,14 +95,14 @@ namespace DotRecast.Recast
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
AtomicInteger counter = new AtomicInteger(0);
|
||||
|
@ -122,7 +122,7 @@ namespace DotRecast.Recast
|
|||
|
||||
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)
|
||||
{
|
||||
results.Add(tile);
|
||||
|
@ -152,34 +152,34 @@ namespace DotRecast.Recast
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
progressListener.onProgress(counter.IncrementAndGet(), total);
|
||||
progressListener.OnProgress(counter.IncrementAndGet(), total);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public RecastBuilderResult build(InputGeomProvider geom, RecastBuilderConfig builderCfg)
|
||||
public RecastBuilderResult Build(InputGeomProvider geom, RecastBuilderConfig builderCfg)
|
||||
{
|
||||
RecastConfig cfg = builderCfg.cfg;
|
||||
Telemetry ctx = new Telemetry();
|
||||
//
|
||||
// Step 1. Rasterize input polygon soup.
|
||||
//
|
||||
Heightfield solid = RecastVoxelization.buildSolidHeightfield(geom, builderCfg, ctx);
|
||||
return build(builderCfg.tileX, builderCfg.tileZ, geom, cfg, solid, ctx);
|
||||
Heightfield solid = RecastVoxelization.BuildSolidHeightfield(geom, builderCfg, 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)
|
||||
{
|
||||
filterHeightfield(solid, cfg, ctx);
|
||||
CompactHeightfield chf = buildCompactHeightfield(geom, cfg, ctx, solid);
|
||||
FilterHeightfield(solid, cfg, ctx);
|
||||
CompactHeightfield chf = BuildCompactHeightfield(geom, cfg, ctx, solid);
|
||||
|
||||
// Partition the heightfield so that we can use simple algorithm later
|
||||
// to triangulate the walkable areas.
|
||||
|
@ -223,20 +223,20 @@ namespace DotRecast.Recast
|
|||
{
|
||||
// Prepare for region partitioning, by calculating distance field
|
||||
// along the walkable surface.
|
||||
RecastRegion.buildDistanceField(ctx, chf);
|
||||
RecastRegion.BuildDistanceField(ctx, chf);
|
||||
// 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)
|
||||
{
|
||||
// Partition the walkable surface into simple regions without holes.
|
||||
// Monotone partitioning does not need distancefield.
|
||||
RecastRegion.buildRegionsMonotone(ctx, chf, cfg.minRegionArea, cfg.mergeRegionArea);
|
||||
RecastRegion.BuildRegionsMonotone(ctx, chf, cfg.minRegionArea, cfg.mergeRegionArea);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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.
|
||||
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);
|
||||
|
||||
//
|
||||
// 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
|
||||
// on each polygon.
|
||||
//
|
||||
PolyMeshDetail dmesh = cfg.buildMeshDetail
|
||||
? RecastMeshDetail.buildPolyMeshDetail(ctx, pmesh, chf, cfg.detailSampleDist, cfg.detailSampleMaxError)
|
||||
? RecastMeshDetail.BuildPolyMeshDetail(ctx, pmesh, chf, cfg.detailSampleDist, cfg.detailSampleMaxError)
|
||||
: null;
|
||||
return new RecastBuilderResult(tileX, tileZ, solid, chf, cset, pmesh, dmesh, ctx);
|
||||
}
|
||||
|
@ -266,59 +266,59 @@ namespace DotRecast.Recast
|
|||
/*
|
||||
* 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
|
||||
// remove unwanted overhangs caused by the conservative rasterization
|
||||
// as well as filter spans where the character cannot possibly stand.
|
||||
if (cfg.filterLowHangingObstacles)
|
||||
{
|
||||
RecastFilter.filterLowHangingWalkableObstacles(ctx, cfg.walkableClimb, solid);
|
||||
RecastFilter.FilterLowHangingWalkableObstacles(ctx, cfg.walkableClimb, solid);
|
||||
}
|
||||
|
||||
if (cfg.filterLedgeSpans)
|
||||
{
|
||||
RecastFilter.filterLedgeSpans(ctx, cfg.walkableHeight, cfg.walkableClimb, solid);
|
||||
RecastFilter.FilterLedgeSpans(ctx, cfg.walkableHeight, cfg.walkableClimb, solid);
|
||||
}
|
||||
|
||||
if (cfg.filterWalkableLowHeightSpans)
|
||||
{
|
||||
RecastFilter.filterWalkableLowHeightSpans(ctx, cfg.walkableHeight, solid);
|
||||
RecastFilter.FilterWalkableLowHeightSpans(ctx, cfg.walkableHeight, solid);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
// 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
|
||||
// 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.
|
||||
RecastArea.erodeWalkableArea(ctx, cfg.walkableRadius, chf);
|
||||
RecastArea.ErodeWalkableArea(ctx, cfg.walkableRadius, chf);
|
||||
// (Optional) Mark areas.
|
||||
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;
|
||||
}
|
||||
|
||||
public HeightfieldLayerSet buildLayers(InputGeomProvider geom, RecastBuilderConfig builderCfg)
|
||||
public HeightfieldLayerSet BuildLayers(InputGeomProvider geom, RecastBuilderConfig builderCfg)
|
||||
{
|
||||
Telemetry ctx = new Telemetry();
|
||||
Heightfield solid = RecastVoxelization.buildSolidHeightfield(geom, builderCfg, ctx);
|
||||
filterHeightfield(solid, builderCfg.cfg, ctx);
|
||||
CompactHeightfield chf = buildCompactHeightfield(geom, builderCfg.cfg, ctx, solid);
|
||||
return RecastLayers.buildHeightfieldLayers(ctx, chf, builderCfg.cfg.walkableHeight);
|
||||
Heightfield solid = RecastVoxelization.BuildSolidHeightfield(geom, builderCfg, ctx);
|
||||
FilterHeightfield(solid, builderCfg.cfg, ctx);
|
||||
CompactHeightfield chf = BuildCompactHeightfield(geom, builderCfg.cfg, ctx, solid);
|
||||
return RecastLayers.BuildHeightfieldLayers(ctx, chf, builderCfg.cfg.walkableHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
else
|
||||
{
|
||||
int[] wh = Recast.calcGridSize(this.bmin, this.bmax, cfg.cs);
|
||||
int[] wh = Recast.CalcGridSize(this.bmin, this.bmax, cfg.cs);
|
||||
width = wh[0];
|
||||
height = wh[1];
|
||||
}
|
||||
|
|
|
@ -23,32 +23,32 @@
|
|||
telemetry = ctx;
|
||||
}
|
||||
|
||||
public PolyMesh getMesh()
|
||||
public PolyMesh GetMesh()
|
||||
{
|
||||
return pmesh;
|
||||
}
|
||||
|
||||
public PolyMeshDetail getMeshDetail()
|
||||
public PolyMeshDetail GetMeshDetail()
|
||||
{
|
||||
return dmesh;
|
||||
}
|
||||
|
||||
public CompactHeightfield getCompactHeightfield()
|
||||
public CompactHeightfield GetCompactHeightfield()
|
||||
{
|
||||
return chf;
|
||||
}
|
||||
|
||||
public ContourSet getContourSet()
|
||||
public ContourSet GetContourSet()
|
||||
{
|
||||
return cs;
|
||||
}
|
||||
|
||||
public Heightfield getSolidHeightfield()
|
||||
public Heightfield GetSolidHeightfield()
|
||||
{
|
||||
return solid;
|
||||
}
|
||||
|
||||
public Telemetry getTelemetry()
|
||||
public Telemetry GetTelemetry()
|
||||
{
|
||||
return telemetry;
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace DotRecast.Recast
|
|||
/// @param[in] x The x offset. [Limits: -1 <= value <= 1]
|
||||
/// @param[in] y The y offset. [Limits: -1 <= value <= 1]
|
||||
/// @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 };
|
||||
return dirs[((y + 1) << 1) + x];
|
||||
|
|
|
@ -38,15 +38,15 @@ namespace DotRecast.Recast
|
|||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||
///
|
||||
/// @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)
|
||||
{
|
||||
ctx.startTimer("BUILD_COMPACTHEIGHTFIELD");
|
||||
ctx.StartTimer("BUILD_COMPACTHEIGHTFIELD");
|
||||
|
||||
CompactHeightfield chf = new CompactHeightfield();
|
||||
int w = hf.width;
|
||||
int h = hf.height;
|
||||
int spanCount = getHeightFieldSpanCount(hf);
|
||||
int spanCount = GetHeightFieldSpanCount(hf);
|
||||
|
||||
// Fill in header.
|
||||
chf.width = w;
|
||||
|
@ -93,8 +93,8 @@ namespace DotRecast.Recast
|
|||
{
|
||||
int bot = s.smax;
|
||||
int top = s.next != null ? (int)s.next.smin : MAX_HEIGHT;
|
||||
chf.spans[idx].y = clamp(bot, 0, MAX_HEIGHT);
|
||||
chf.spans[idx].h = clamp(top - bot, 0, MAX_HEIGHT);
|
||||
chf.spans[idx].y = Clamp(bot, 0, MAX_HEIGHT);
|
||||
chf.spans[idx].h = Clamp(top - bot, 0, MAX_HEIGHT);
|
||||
chf.areas[idx] = s.area;
|
||||
idx++;
|
||||
c.count++;
|
||||
|
@ -161,11 +161,11 @@ namespace DotRecast.Recast
|
|||
+ " (max: " + MAX_LAYERS + ")");
|
||||
}
|
||||
|
||||
ctx.stopTimer("BUILD_COMPACTHEIGHTFIELD");
|
||||
ctx.StopTimer("BUILD_COMPACTHEIGHTFIELD");
|
||||
return chf;
|
||||
}
|
||||
|
||||
private static int getHeightFieldSpanCount(Heightfield hf)
|
||||
private static int GetHeightFieldSpanCount(Heightfield hf)
|
||||
{
|
||||
int w = hf.width;
|
||||
int h = hf.height;
|
||||
|
|
|
@ -179,7 +179,7 @@ namespace DotRecast.Recast
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
CompactSpan s = chf.spans[i];
|
||||
|
@ -138,7 +138,7 @@ namespace DotRecast.Recast
|
|||
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
|
||||
int dir = 0;
|
||||
|
@ -157,7 +157,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
// Choose the edge corner
|
||||
bool isAreaBorder = false;
|
||||
CornerHeight cornerHeight = getCornerHeight(x, y, i, dir, chf);
|
||||
CornerHeight cornerHeight = GetCornerHeight(x, y, i, dir, chf);
|
||||
bool isBorderVertex = cornerHeight.borderVertex;
|
||||
int px = x;
|
||||
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 pqz = qz - pz;
|
||||
|
@ -252,7 +252,7 @@ namespace DotRecast.Recast
|
|||
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.
|
||||
bool hasConnections = false;
|
||||
|
@ -377,7 +377,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
for (int i = 0, j = nverts - 1; i < nverts; j = i++)
|
||||
|
@ -493,7 +493,7 @@ namespace DotRecast.Recast
|
|||
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
|
||||
int[] pverts = new int[4 * 4];
|
||||
|
@ -507,7 +507,7 @@ namespace DotRecast.Recast
|
|||
d1 = 4;
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
int k1 = RecastMesh.next(k, n);
|
||||
int k1 = RecastMesh.Next(k, n);
|
||||
// Skip edges incident to i.
|
||||
if (i == k || i == k1)
|
||||
continue;
|
||||
|
@ -521,22 +521,22 @@ namespace DotRecast.Recast
|
|||
|
||||
p0 = 8;
|
||||
p1 = 12;
|
||||
if (RecastMesh.vequal(pverts, d0, p0) || RecastMesh.vequal(pverts, d1, p0)
|
||||
|| RecastMesh.vequal(pverts, d0, p1) || RecastMesh.vequal(pverts, d1, p1))
|
||||
if (RecastMesh.Vequal(pverts, d0, p0) || RecastMesh.Vequal(pverts, d1, p0)
|
||||
|| RecastMesh.Vequal(pverts, d0, p1) || RecastMesh.Vequal(pverts, d1, p1))
|
||||
continue;
|
||||
|
||||
if (RecastMesh.intersect(pverts, d0, d1, p0, p1))
|
||||
if (RecastMesh.Intersect(pverts, d0, d1, p0, p1))
|
||||
return true;
|
||||
}
|
||||
|
||||
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 pi1 = RecastMesh.next(i, n) * 4;
|
||||
int pin1 = RecastMesh.prev(i, n) * 4;
|
||||
int pi1 = RecastMesh.Next(i, n) * 4;
|
||||
int pin1 = RecastMesh.Prev(i, n) * 4;
|
||||
int[] pverts = new int[4 * 4];
|
||||
for (int g = 0; g < 4; g++)
|
||||
{
|
||||
|
@ -551,23 +551,23 @@ namespace DotRecast.Recast
|
|||
pin1 = 8;
|
||||
pj = 12;
|
||||
// If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
|
||||
if (RecastMesh.leftOn(pverts, pin1, pi, pi1))
|
||||
return RecastMesh.left(pverts, pi, pj, pin1) && RecastMesh.left(pverts, pj, pi, pi1);
|
||||
if (RecastMesh.LeftOn(pverts, pin1, pi, pi1))
|
||||
return RecastMesh.Left(pverts, pi, pj, pin1) && RecastMesh.Left(pverts, pj, pi, pi1);
|
||||
// Assume (i-1,i,i+1) not collinear.
|
||||
// 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,
|
||||
// or else the triangulator will get confused.
|
||||
int npts = simplified.Count / 4;
|
||||
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]
|
||||
&& 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[] verts = new int[maxVerts * 4];
|
||||
|
@ -620,7 +620,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
// 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 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.
|
||||
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].minz = minleft[1];
|
||||
region.holes[i].leftmost = minleft[2];
|
||||
|
@ -711,7 +711,7 @@ namespace DotRecast.Recast
|
|||
int corner = bestVertex * 4;
|
||||
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 dz = outline.verts[j * 4 + 2] - hole.verts[corner + 2];
|
||||
|
@ -729,10 +729,10 @@ namespace DotRecast.Recast
|
|||
for (int j = 0; j < ndiags; j++)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
if (!intersect)
|
||||
{
|
||||
|
@ -750,11 +750,11 @@ namespace DotRecast.Recast
|
|||
|
||||
if (index == -1)
|
||||
{
|
||||
ctx.warn("mergeHoles: Failed to find merge points for");
|
||||
ctx.Warn("mergeHoles: Failed to find merge points for");
|
||||
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 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 w = chf.width;
|
||||
|
@ -779,7 +779,7 @@ namespace DotRecast.Recast
|
|||
int borderSize = chf.borderSize;
|
||||
ContourSet cset = new ContourSet();
|
||||
|
||||
ctx.startTimer("CONTOURS");
|
||||
ctx.StartTimer("CONTOURS");
|
||||
cset.bmin = chf.bmin;
|
||||
cset.bmax = chf.bmax;
|
||||
if (borderSize > 0)
|
||||
|
@ -801,7 +801,7 @@ namespace DotRecast.Recast
|
|||
|
||||
int[] flags = new int[chf.spanCount];
|
||||
|
||||
ctx.startTimer("CONTOURS_TRACE");
|
||||
ctx.StartTimer("CONTOURS_TRACE");
|
||||
|
||||
// Mark boundaries.
|
||||
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> simplified = new List<int>(64);
|
||||
|
@ -865,14 +865,14 @@ namespace DotRecast.Recast
|
|||
verts.Clear();
|
||||
simplified.Clear();
|
||||
|
||||
ctx.startTimer("CONTOURS_WALK");
|
||||
walkContour(x, y, i, chf, flags, verts);
|
||||
ctx.stopTimer("CONTOURS_WALK");
|
||||
ctx.StartTimer("CONTOURS_WALK");
|
||||
WalkContour(x, y, i, chf, flags, verts);
|
||||
ctx.StopTimer("CONTOURS_WALK");
|
||||
|
||||
ctx.startTimer("CONTOURS_SIMPLIFY");
|
||||
simplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags);
|
||||
removeDegenerateSegments(simplified);
|
||||
ctx.stopTimer("CONTOURS_SIMPLIFY");
|
||||
ctx.StartTimer("CONTOURS_SIMPLIFY");
|
||||
SimplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags);
|
||||
RemoveDegenerateSegments(simplified);
|
||||
ctx.StopTimer("CONTOURS_SIMPLIFY");
|
||||
|
||||
// Store region->contour remap info.
|
||||
// Create contour.
|
||||
|
@ -932,7 +932,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
Contour cont = cset.conts[i];
|
||||
// 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)
|
||||
nholes++;
|
||||
}
|
||||
|
@ -999,7 +999,7 @@ namespace DotRecast.Recast
|
|||
|
||||
if (reg.outline != null)
|
||||
{
|
||||
mergeRegionHoles(ctx, reg);
|
||||
MergeRegionHoles(ctx, reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1013,7 +1013,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
}
|
||||
|
||||
ctx.stopTimer("CONTOURS");
|
||||
ctx.StopTimer("CONTOURS");
|
||||
return cset;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,28 +24,28 @@ using static DotRecast.Recast.RecastVectors;
|
|||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public class RecastFilledVolumeRasterization
|
||||
public static class RecastFilledVolumeRasterization
|
||||
{
|
||||
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 };
|
||||
|
||||
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 =
|
||||
{
|
||||
center.x - radius, center.y - radius, center.z - radius, center.x + radius, center.y + radius,
|
||||
center.z + radius
|
||||
};
|
||||
rasterizationFilledShape(hf, bounds, area, flagMergeThr,
|
||||
rectangle => intersectSphere(rectangle, center, radius * radius));
|
||||
ctx.stopTimer("RASTERIZE_SPHERE");
|
||||
RasterizationFilledShape(hf, bounds, area, flagMergeThr,
|
||||
rectangle => IntersectSphere(rectangle, center, radius * radius));
|
||||
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)
|
||||
{
|
||||
ctx.startTimer("RASTERIZE_CAPSULE");
|
||||
ctx.StartTimer("RASTERIZE_CAPSULE");
|
||||
float[] bounds =
|
||||
{
|
||||
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
|
||||
};
|
||||
Vector3f axis = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
|
||||
rasterizationFilledShape(hf, bounds, area, flagMergeThr,
|
||||
rectangle => intersectCapsule(rectangle, start, end, axis, radius * radius));
|
||||
ctx.stopTimer("RASTERIZE_CAPSULE");
|
||||
RasterizationFilledShape(hf, bounds, area, flagMergeThr,
|
||||
rectangle => IntersectCapsule(rectangle, start, end, axis, radius * radius));
|
||||
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)
|
||||
{
|
||||
ctx.startTimer("RASTERIZE_CYLINDER");
|
||||
ctx.StartTimer("RASTERIZE_CYLINDER");
|
||||
float[] bounds =
|
||||
{
|
||||
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
|
||||
};
|
||||
Vector3f axis = Vector3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
|
||||
rasterizationFilledShape(hf, bounds, area, flagMergeThr,
|
||||
rectangle => intersectCylinder(rectangle, start, end, axis, radius * radius));
|
||||
ctx.stopTimer("RASTERIZE_CYLINDER");
|
||||
RasterizationFilledShape(hf, bounds, area, flagMergeThr,
|
||||
rectangle => IntersectCylinder(rectangle, start, end, axis, radius * radius));
|
||||
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)
|
||||
{
|
||||
ctx.startTimer("RASTERIZE_BOX");
|
||||
ctx.StartTimer("RASTERIZE_BOX");
|
||||
Vector3f[] normals =
|
||||
{
|
||||
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[2].x, halfEdges[2].y, halfEdges[2].z),
|
||||
};
|
||||
normalize(ref normals[0]);
|
||||
normalize(ref normals[1]);
|
||||
normalize(ref normals[2]);
|
||||
Normalize(ref normals[0]);
|
||||
Normalize(ref normals[1]);
|
||||
Normalize(ref normals[2]);
|
||||
|
||||
float[] vertices = new float[8 * 3];
|
||||
float[] bounds = new float[]
|
||||
|
@ -122,14 +122,14 @@ namespace DotRecast.Recast
|
|||
+ vertices[vi * 3 + 2] * planes[i][2];
|
||||
}
|
||||
|
||||
rasterizationFilledShape(hf, bounds, area, flagMergeThr, rectangle => intersectBox(rectangle, vertices, planes));
|
||||
ctx.stopTimer("RASTERIZE_BOX");
|
||||
RasterizationFilledShape(hf, bounds, area, flagMergeThr, rectangle => IntersectBox(rectangle, vertices, planes));
|
||||
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)
|
||||
{
|
||||
ctx.startTimer("RASTERIZE_CONVEX");
|
||||
ctx.StartTimer("RASTERIZE_CONVEX");
|
||||
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)
|
||||
{
|
||||
|
@ -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[] 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] };
|
||||
plane(planes, i, ab, ac, vertices, a);
|
||||
plane(planes, i + 1, planes[i], bc, vertices, b);
|
||||
plane(planes, i + 2, planes[i], ca, vertices, c);
|
||||
Plane(planes, i, ab, ac, vertices, a);
|
||||
Plane(planes, i + 1, planes[i], bc, vertices, b);
|
||||
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]
|
||||
+ 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]);
|
||||
}
|
||||
|
||||
rasterizationFilledShape(hf, bounds, area, flagMergeThr,
|
||||
rectangle => intersectConvex(rectangle, triangles, vertices, planes, triBounds));
|
||||
ctx.stopTimer("RASTERIZE_CONVEX");
|
||||
RasterizationFilledShape(hf, bounds, area, flagMergeThr,
|
||||
rectangle => IntersectConvex(rectangle, triangles, vertices, planes, triBounds));
|
||||
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];
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!overlapBounds(hf.bmin, hf.bmax, bounds))
|
||||
if (!OverlapBounds(hf.bmin, hf.bmax, bounds))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -229,16 +229,16 @@ namespace DotRecast.Recast
|
|||
int smax = (int)Math.Ceiling((h[1] - hf.bmin.y) * ich);
|
||||
if (smin != smax)
|
||||
{
|
||||
int ismin = clamp(smin, 0, SPAN_MAX_HEIGHT);
|
||||
int ismax = clamp(smax, ismin + 1, SPAN_MAX_HEIGHT);
|
||||
RecastRasterization.addSpan(hf, x, z, ismin, ismax, area, flagMergeThr);
|
||||
int ismin = Clamp(smin, 0, SPAN_MAX_HEIGHT);
|
||||
int ismax = Clamp(smax, ismin + 1, SPAN_MAX_HEIGHT);
|
||||
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 y = rectangle[4];
|
||||
|
@ -248,8 +248,8 @@ namespace DotRecast.Recast
|
|||
float my = y - center.y;
|
||||
float mz = z - center.z;
|
||||
|
||||
float b = my; // dot(m, d) d = (0, 1, 0)
|
||||
float c = lenSqr(mx, my, mz) - radiusSqr;
|
||||
float b = my; // Dot(m, d) d = (0, 1, 0)
|
||||
float c = LenSqr(mx, my, mz) - radiusSqr;
|
||||
if (c > 0.0f && b > 0.0f)
|
||||
{
|
||||
return null;
|
||||
|
@ -273,47 +273,47 @@ namespace DotRecast.Recast
|
|||
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;
|
||||
if (axisLen2dSqr > EPSILON)
|
||||
{
|
||||
s = slabsCylinderIntersection(rectangle, start, end, axis, radiusSqr, s);
|
||||
s = SlabsCylinderIntersection(rectangle, start, end, axis, radiusSqr, 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(
|
||||
rayCylinderIntersection(Vector3f.Of(
|
||||
clamp(start.x, rectangle[0], rectangle[2]), rectangle[4],
|
||||
clamp(start.z, rectangle[1], rectangle[3])
|
||||
float[] s = MergeIntersections(
|
||||
RayCylinderIntersection(Vector3f.Of(
|
||||
Clamp(start.x, rectangle[0], rectangle[2]), rectangle[4],
|
||||
Clamp(start.z, rectangle[1], rectangle[3])
|
||||
), start, axis, radiusSqr),
|
||||
rayCylinderIntersection(Vector3f.Of(
|
||||
clamp(end.x, rectangle[0], rectangle[2]), rectangle[4],
|
||||
clamp(end.z, rectangle[1], rectangle[3])
|
||||
RayCylinderIntersection(Vector3f.Of(
|
||||
Clamp(end.x, rectangle[0], rectangle[2]), rectangle[4],
|
||||
Clamp(end.z, rectangle[1], rectangle[3])
|
||||
), start, axis, radiusSqr));
|
||||
float axisLen2dSqr = axis.x * axis.x + axis.z * axis.z;
|
||||
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)
|
||||
{
|
||||
float[][] rectangleOnStartPlane = ArrayUtils.Of<float>(4, 3);
|
||||
float[][] rectangleOnEndPlane = ArrayUtils.Of<float>(4, 3);
|
||||
float ds = dot(axis, start);
|
||||
float de = dot(axis, end);
|
||||
float ds = Dot(axis, start);
|
||||
float de = Dot(axis, end);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
float x = rectangle[(i + 1) & 2];
|
||||
float z = rectangle[(i & 2) + 1];
|
||||
Vector3f a = Vector3f.Of(x, rectangle[4], z);
|
||||
float dotAxisA = dot(axis, a);
|
||||
float dotAxisA = Dot(axis, a);
|
||||
float t = (ds - dotAxisA) / axis.y;
|
||||
rectangleOnStartPlane[i][0] = x;
|
||||
rectangleOnStartPlane[i][1] = rectangle[4] + t;
|
||||
|
@ -326,15 +326,15 @@ namespace DotRecast.Recast
|
|||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
s = cylinderCapIntersection(start, radiusSqr, s, i, rectangleOnStartPlane);
|
||||
s = cylinderCapIntersection(end, radiusSqr, s, i, rectangleOnEndPlane);
|
||||
s = CylinderCapIntersection(start, radiusSqr, s, i, rectangleOnStartPlane);
|
||||
s = CylinderCapIntersection(end, radiusSqr, s, i, rectangleOnEndPlane);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
// Ray against sphere intersection
|
||||
|
@ -348,9 +348,9 @@ namespace DotRecast.Recast
|
|||
rectangleOnPlane[j][1] - rectangleOnPlane[i][1],
|
||||
rectangleOnPlane[j][2] - rectangleOnPlane[i][2]
|
||||
);
|
||||
float dl = dot(d, d);
|
||||
float b = dot(m, d) / dl;
|
||||
float c = (dot(m, m) - radiusSqr) / dl;
|
||||
float dl = Dot(d, d);
|
||||
float b = Dot(m, d) / dl;
|
||||
float c = (Dot(m, m) - radiusSqr) / dl;
|
||||
float discr = b * b - c;
|
||||
if (discr > EPSILON)
|
||||
{
|
||||
|
@ -364,83 +364,83 @@ namespace DotRecast.Recast
|
|||
float y1 = rectangleOnPlane[i][1] + t1 * d.y;
|
||||
float y2 = rectangleOnPlane[i][1] + t2 * d.y;
|
||||
float[] y = { Math.Min(y1, y2), Math.Max(y1, y2) };
|
||||
s = mergeIntersections(s, y);
|
||||
s = MergeIntersections(s, y);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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])
|
||||
{
|
||||
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])
|
||||
{
|
||||
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])
|
||||
{
|
||||
s = mergeIntersections(s, zSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[3]));
|
||||
s = MergeIntersections(s, ZSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[3]));
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
// 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 m = Vector3f.Of(point.x - start.x, point.y - start.y, point.z - start.z);
|
||||
// float[] n = { 0, 1, 0 };
|
||||
float md = dot(m, d);
|
||||
// float nd = dot(n, d);
|
||||
float md = Dot(m, d);
|
||||
// float nd = Dot(n, d);
|
||||
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 mn = dot(m, n);
|
||||
// float mn = Dot(m, n);
|
||||
float mn = m.y;
|
||||
// float a = dd * nn - 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;
|
||||
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) };
|
||||
}
|
||||
|
||||
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 yMax = float.NegativeInfinity;
|
||||
|
@ -534,7 +534,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
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 y = point.y + t;
|
||||
bool valid = true;
|
||||
|
@ -573,14 +573,14 @@ namespace DotRecast.Recast
|
|||
float dz = vertices[vj + 2] - z;
|
||||
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)
|
||||
{
|
||||
yMin = Math.Min(yMin, 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)
|
||||
{
|
||||
yMin = Math.Min(yMin, iy.Value);
|
||||
|
@ -590,14 +590,14 @@ namespace DotRecast.Recast
|
|||
|
||||
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)
|
||||
{
|
||||
yMin = Math.Min(yMin, 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)
|
||||
{
|
||||
yMin = Math.Min(yMin, iy.Value);
|
||||
|
@ -614,7 +614,7 @@ namespace DotRecast.Recast
|
|||
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 imin = float.PositiveInfinity;
|
||||
|
@ -652,14 +652,14 @@ namespace DotRecast.Recast
|
|||
float dz = verts[vj + 2] - z;
|
||||
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)
|
||||
{
|
||||
imin = Math.Min(imin, 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)
|
||||
{
|
||||
imin = Math.Min(imin, iy.Value);
|
||||
|
@ -669,14 +669,14 @@ namespace DotRecast.Recast
|
|||
|
||||
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)
|
||||
{
|
||||
imin = Math.Min(imin, 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)
|
||||
{
|
||||
imin = Math.Min(imin, iy.Value);
|
||||
|
@ -691,7 +691,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
point.x = ((i & 1) == 0) ? rectangle[0] : rectangle[2];
|
||||
point.z = ((i & 2) == 0) ? rectangle[1] : rectangle[3];
|
||||
float? y = rayTriangleIntersection(point, tri, planes);
|
||||
float? y = RayTriangleIntersection(point, tri, planes);
|
||||
if (y != null)
|
||||
{
|
||||
imin = Math.Min(imin, y.Value);
|
||||
|
@ -708,7 +708,7 @@ namespace DotRecast.Recast
|
|||
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 x2 = x + dx;
|
||||
|
@ -725,7 +725,7 @@ namespace DotRecast.Recast
|
|||
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 z2 = z + dz;
|
||||
|
@ -742,17 +742,17 @@ namespace DotRecast.Recast
|
|||
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 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return null;
|
||||
|
@ -767,7 +767,7 @@ namespace DotRecast.Recast
|
|||
return s[1];
|
||||
}
|
||||
|
||||
private static float[] mergeIntersections(float[] s1, float[] s2)
|
||||
private static float[] MergeIntersections(float[] s1, float[] s2)
|
||||
{
|
||||
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]) };
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static bool overlapBounds(Vector3f amin, Vector3f amax, float[] bounds)
|
||||
private static bool OverlapBounds(Vector3f amin, Vector3f amax, float[] bounds)
|
||||
{
|
||||
bool overlap = true;
|
||||
overlap = (amin.x > bounds[3] || amax.x < bounds[0]) ? false : overlap;
|
||||
|
|
|
@ -31,15 +31,15 @@ namespace DotRecast.Recast
|
|||
/// Allows the formation of walkable regions that will flow over low lying
|
||||
/// 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
|
||||
/// #rcFilterLedgeSpans after calling this filter.
|
||||
///
|
||||
/// @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 h = solid.height;
|
||||
|
@ -71,7 +71,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
}
|
||||
|
||||
ctx.stopTimer("FILTER_LOW_OBSTACLES");
|
||||
ctx.StopTimer("FILTER_LOW_OBSTACLES");
|
||||
}
|
||||
|
||||
/// @par
|
||||
|
@ -81,12 +81,12 @@ namespace DotRecast.Recast
|
|||
/// 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.
|
||||
///
|
||||
/// 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
|
||||
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 h = solid.height;
|
||||
|
@ -168,7 +168,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
}
|
||||
|
||||
ctx.stopTimer("FILTER_LEDGE");
|
||||
ctx.StopTimer("FILTER_LEDGE");
|
||||
}
|
||||
|
||||
/// @par
|
||||
|
@ -177,9 +177,9 @@ namespace DotRecast.Recast
|
|||
/// maximum to the next higher span's minimum. (Same grid column.)
|
||||
///
|
||||
/// @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 h = solid.height;
|
||||
|
@ -200,7 +200,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
}
|
||||
|
||||
ctx.stopTimer("FILTER_WALKABLE");
|
||||
ctx.StopTimer("FILTER_WALKABLE");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 h = chf.height;
|
||||
int borderSize = chf.borderSize;
|
||||
|
@ -234,7 +234,7 @@ namespace DotRecast.Recast
|
|||
int ai = chf.cells[ax + ay * w].index + GetCon(s, dir);
|
||||
int rai = srcReg[ai];
|
||||
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 rj = regs[lregs[j]];
|
||||
addUnique(ri.layers, lregs[j]);
|
||||
addUnique(rj.layers, lregs[i]);
|
||||
AddUnique(ri.layers, lregs[j]);
|
||||
AddUnique(rj.layers, lregs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ namespace DotRecast.Recast
|
|||
if (regn.layerId != 0xff)
|
||||
continue;
|
||||
// Skip if the neighbour is overlapping root region.
|
||||
if (contains(root.layers, nei))
|
||||
if (Contains(root.layers, nei))
|
||||
continue;
|
||||
// Skip if the height range would become too large.
|
||||
int ymin = Math.Min(root.ymin, regn.ymin);
|
||||
|
@ -303,7 +303,7 @@ namespace DotRecast.Recast
|
|||
regn.layerId = layerId;
|
||||
// Merge current layers to root.
|
||||
foreach (int layer in regn.layers)
|
||||
addUnique(root.layers, layer);
|
||||
AddUnique(root.layers, layer);
|
||||
root.ymin = Math.Min(root.ymin, regn.ymin);
|
||||
root.ymax = Math.Max(root.ymax, regn.ymax);
|
||||
}
|
||||
|
@ -336,7 +336,7 @@ namespace DotRecast.Recast
|
|||
continue;
|
||||
|
||||
// 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;
|
||||
// Skip if the height range would become too large.
|
||||
int ymin = Math.Min(ri.ymin, rj.ymin);
|
||||
|
@ -355,7 +355,7 @@ namespace DotRecast.Recast
|
|||
continue;
|
||||
// Check if region 'k' is overlapping region 'ri'
|
||||
// Index to 'regs' is the same as region id.
|
||||
if (contains(ri.layers, k))
|
||||
if (Contains(ri.layers, k))
|
||||
{
|
||||
overlap = true;
|
||||
break;
|
||||
|
@ -386,7 +386,7 @@ namespace DotRecast.Recast
|
|||
rj.layerId = newId;
|
||||
// Add overlaid layers from 'rj' to 'ri'.
|
||||
foreach (int layer in rj.layers)
|
||||
addUnique(ri.layers, layer);
|
||||
AddUnique(ri.layers, layer);
|
||||
// Update height bounds.
|
||||
ri.ymin = Math.Min(ri.ymin, rj.ymin);
|
||||
ri.ymax = Math.Max(ri.ymax, rj.ymax);
|
||||
|
@ -417,12 +417,12 @@ namespace DotRecast.Recast
|
|||
// No layers, return empty.
|
||||
if (layerId == 0)
|
||||
{
|
||||
// ctx.stopTimer(RC_TIMER_BUILD_LAYERS);
|
||||
// ctx.StopTimer(RC_TIMER_BUILD_LAYERS);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create layers.
|
||||
// rcAssert(lset.layers == 0);
|
||||
// RcAssert(lset.layers == 0);
|
||||
|
||||
int lw = w - borderSize * 2;
|
||||
int lh = h - borderSize * 2;
|
||||
|
@ -560,7 +560,7 @@ namespace DotRecast.Recast
|
|||
layer.miny = layer.maxy = 0;
|
||||
}
|
||||
|
||||
// ctx->stopTimer(RC_TIMER_BUILD_LAYERS);
|
||||
// ctx->StopTimer(RC_TIMER_BUILD_LAYERS);
|
||||
return lset;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace DotRecast.Recast
|
|||
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:
|
||||
// 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 h2 = 0xd8163841; // here arbitrarily chosen primes
|
||||
|
@ -131,9 +131,9 @@ namespace DotRecast.Recast
|
|||
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];
|
||||
|
||||
while (i != -1)
|
||||
|
@ -157,17 +157,17 @@ namespace DotRecast.Recast
|
|||
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;
|
||||
}
|
||||
|
||||
public static int next(int i, int n)
|
||||
public static int Next(int i, int n)
|
||||
{
|
||||
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])
|
||||
- (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
|
||||
// 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
|
||||
// a point interior to both segments. The properness of the
|
||||
// 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.
|
||||
if (collinear(verts, a, b, c) || collinear(verts, a, b, d) || collinear(verts, c, d, a)
|
||||
|| collinear(verts, c, d, b))
|
||||
if (Collinear(verts, a, b, c) || Collinear(verts, a, b, d) || Collinear(verts, c, d, a)
|
||||
|| Collinear(verts, c, d, b))
|
||||
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
|
||||
// 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;
|
||||
// If ab not vertical, check betweenness on x; else on y.
|
||||
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.
|
||||
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;
|
||||
else if (between(verts, a, b, c) || between(verts, a, b, d) || between(verts, c, d, a)
|
||||
|| between(verts, c, d, b))
|
||||
else if (Between(verts, a, b, c) || Between(verts, a, b, d) || Between(verts, c, d, a)
|
||||
|| Between(verts, c, d, b))
|
||||
return true;
|
||||
else
|
||||
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];
|
||||
}
|
||||
|
||||
// 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*.
|
||||
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 d1 = (indices[j] & 0x0fffffff) * 4;
|
||||
|
@ -245,17 +245,17 @@ namespace DotRecast.Recast
|
|||
// For each edge (k,k+1) of P
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
int k1 = next(k, n);
|
||||
int k1 = Next(k, n);
|
||||
// Skip edges incident to i or j
|
||||
if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
|
||||
{
|
||||
int p0 = (indices[k] & 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;
|
||||
|
||||
if (intersect(verts, d0, d1, p0, p1))
|
||||
if (Intersect(verts, d0, d1, p0, p1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -265,31 +265,31 @@ namespace DotRecast.Recast
|
|||
|
||||
// Returns true iff the diagonal (i,j) is strictly internal to the
|
||||
// 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 pj = (indices[j] & 0x0fffffff) * 4;
|
||||
int pi1 = (indices[next(i, n)] & 0x0fffffff) * 4;
|
||||
int pin1 = (indices[prev(i, n)] & 0x0fffffff) * 4;
|
||||
int pi1 = (indices[Next(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 (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.
|
||||
// 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
|
||||
// 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 d1 = (indices[j] & 0x0fffffff) * 4;
|
||||
|
@ -297,17 +297,17 @@ namespace DotRecast.Recast
|
|||
// For each edge (k,k+1) of P
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
int k1 = next(k, n);
|
||||
int k1 = Next(k, n);
|
||||
// Skip edges incident to i or j
|
||||
if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
|
||||
{
|
||||
int p0 = (indices[k] & 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;
|
||||
|
||||
if (intersectProp(verts, d0, d1, p0, p1))
|
||||
if (IntersectProp(verts, d0, d1, p0, p1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -315,36 +315,36 @@ namespace DotRecast.Recast
|
|||
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 pj = (indices[j] & 0x0fffffff) * 4;
|
||||
int pi1 = (indices[next(i, n)] & 0x0fffffff) * 4;
|
||||
int pin1 = (indices[prev(i, n)] & 0x0fffffff) * 4;
|
||||
int pi1 = (indices[Next(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 (leftOn(verts, pin1, pi, pi1))
|
||||
return leftOn(verts, pi, pj, pin1) && leftOn(verts, pj, pi, pi1);
|
||||
if (LeftOn(verts, pin1, pi, pi1))
|
||||
return LeftOn(verts, pi, pj, pin1) && LeftOn(verts, pj, pi, pi1);
|
||||
// Assume (i-1,i,i+1) not collinear.
|
||||
// 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;
|
||||
|
||||
// The last bit of the index is used to indicate if the vertex can be removed.
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
int i1 = next(i, n);
|
||||
int i2 = next(i1, n);
|
||||
if (diagonal(i, i2, n, verts, indices))
|
||||
int i1 = Next(i, n);
|
||||
int i2 = Next(i1, n);
|
||||
if (Diagonal(i, i2, n, verts, indices))
|
||||
{
|
||||
indices[i1] |= int.MinValue; // TODO : 체크 필요
|
||||
}
|
||||
|
@ -356,11 +356,11 @@ namespace DotRecast.Recast
|
|||
int mini = -1;
|
||||
for (int minIdx = 0; minIdx < n; minIdx++)
|
||||
{
|
||||
int nextIdx1 = next(minIdx, n);
|
||||
int nextIdx1 = Next(minIdx, n);
|
||||
if ((indices[nextIdx1] & 0x80000000) != 0)
|
||||
{
|
||||
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 dy = verts[p2 + 2] - verts[p0 + 2];
|
||||
|
@ -388,12 +388,12 @@ namespace DotRecast.Recast
|
|||
mini = -1;
|
||||
for (int minIdx = 0; minIdx < n; minIdx++)
|
||||
{
|
||||
int nextIdx1 = next(minIdx, n);
|
||||
int nextIdx2 = next(nextIdx1, n);
|
||||
if (diagonalLoose(minIdx, nextIdx2, n, verts, indices))
|
||||
int nextIdx1 = Next(minIdx, n);
|
||||
int nextIdx2 = Next(nextIdx1, n);
|
||||
if (DiagonalLoose(minIdx, nextIdx2, n, verts, indices))
|
||||
{
|
||||
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 dy = verts[p2 + 2] - verts[p0 + 2];
|
||||
int len = dx * dx + dy * dy;
|
||||
|
@ -415,8 +415,8 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
int i = mini;
|
||||
int i1 = next(i, n);
|
||||
int i2 = next(i1, n);
|
||||
int i1 = Next(i, n);
|
||||
int i2 = Next(i1, n);
|
||||
|
||||
tris[ntris * 3] = indices[i] & 0x0fffffff;
|
||||
tris[ntris * 3 + 1] = indices[i1] & 0x0fffffff;
|
||||
|
@ -430,14 +430,14 @@ namespace DotRecast.Recast
|
|||
|
||||
if (i1 >= n)
|
||||
i1 = 0;
|
||||
i = prev(i1, n);
|
||||
i = Prev(i1, n);
|
||||
// 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;
|
||||
else
|
||||
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;
|
||||
else
|
||||
indices[i1] &= 0x0fffffff;
|
||||
|
@ -452,7 +452,7 @@ namespace DotRecast.Recast
|
|||
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)
|
||||
if (p[i + j] == RC_MESH_NULL_IDX)
|
||||
|
@ -460,18 +460,18 @@ namespace DotRecast.Recast
|
|||
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])
|
||||
- (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 eb = -1;
|
||||
int na = countPolyVerts(polys, pa, nvp);
|
||||
int nb = countPolyVerts(polys, pb, nvp);
|
||||
int na = CountPolyVerts(polys, pa, nvp);
|
||||
int nb = CountPolyVerts(polys, pb, nvp);
|
||||
|
||||
// If the merged polygon would be too big, do not merge.
|
||||
if (na + nb - 2 > nvp)
|
||||
|
@ -520,13 +520,13 @@ namespace DotRecast.Recast
|
|||
va = polys[pa + (ea + na - 1) % na];
|
||||
vb = polys[pa + ea];
|
||||
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 };
|
||||
|
||||
va = polys[pb + (eb + nb - 1) % nb];
|
||||
vb = polys[pb + eb];
|
||||
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 };
|
||||
|
||||
va = polys[pa + ea];
|
||||
|
@ -538,10 +538,10 @@ namespace DotRecast.Recast
|
|||
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 nb = countPolyVerts(polys, pb, nvp);
|
||||
int na = CountPolyVerts(polys, pa, nvp);
|
||||
int nb = CountPolyVerts(polys, pb, nvp);
|
||||
|
||||
// Merge polygons.
|
||||
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);
|
||||
}
|
||||
|
||||
private static int pushFront(int v, int[] arr, int an)
|
||||
private static int PushFront(int v, int[] arr, int an)
|
||||
{
|
||||
an++;
|
||||
for (int i = an - 1; i > 0; --i)
|
||||
|
@ -572,14 +572,14 @@ namespace DotRecast.Recast
|
|||
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;
|
||||
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;
|
||||
|
||||
|
@ -589,7 +589,7 @@ namespace DotRecast.Recast
|
|||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
int p = i * nvp * 2;
|
||||
int nv = countPolyVerts(mesh.polys, p, nvp);
|
||||
int nv = CountPolyVerts(mesh.polys, p, nvp);
|
||||
int numRemoved = 0;
|
||||
int numVerts = 0;
|
||||
for (int j = 0; j < nv; ++j)
|
||||
|
@ -624,7 +624,7 @@ namespace DotRecast.Recast
|
|||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
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.
|
||||
for (int j = 0, k = nv - 1; j < nv; k = j++)
|
||||
|
@ -682,7 +682,7 @@ namespace DotRecast.Recast
|
|||
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;
|
||||
|
||||
|
@ -691,7 +691,7 @@ namespace DotRecast.Recast
|
|||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (mesh.polys[p + j] == rem)
|
||||
|
@ -714,7 +714,7 @@ namespace DotRecast.Recast
|
|||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
int p = i * nvp * 2;
|
||||
int nv = countPolyVerts(mesh.polys, p, nvp);
|
||||
int nv = CountPolyVerts(mesh.polys, p, nvp);
|
||||
bool hasRem = false;
|
||||
for (int j = 0; j < nv; ++j)
|
||||
if (mesh.polys[p + j] == rem)
|
||||
|
@ -764,7 +764,7 @@ namespace DotRecast.Recast
|
|||
for (int i = 0; i < mesh.npolys; ++i)
|
||||
{
|
||||
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)
|
||||
if (mesh.polys[p + j] > rem)
|
||||
mesh.polys[p + j]--;
|
||||
|
@ -783,9 +783,9 @@ namespace DotRecast.Recast
|
|||
|
||||
// Start with one vertex, keep appending connected
|
||||
// segments to the start and end of the hole.
|
||||
nhole = pushBack(edges[0], hole, nhole);
|
||||
nhreg = pushBack(edges[2], hreg, nhreg);
|
||||
nharea = pushBack(edges[3], harea, nharea);
|
||||
nhole = PushBack(edges[0], hole, nhole);
|
||||
nhreg = PushBack(edges[2], hreg, nhreg);
|
||||
nharea = PushBack(edges[3], harea, nharea);
|
||||
|
||||
while (nedges != 0)
|
||||
{
|
||||
|
@ -801,17 +801,17 @@ namespace DotRecast.Recast
|
|||
if (hole[0] == eb)
|
||||
{
|
||||
// The segment matches the beginning of the hole boundary.
|
||||
nhole = pushFront(ea, hole, nhole);
|
||||
nhreg = pushFront(r, hreg, nhreg);
|
||||
nharea = pushFront(a, harea, nharea);
|
||||
nhole = PushFront(ea, hole, nhole);
|
||||
nhreg = PushFront(r, hreg, nhreg);
|
||||
nharea = PushFront(a, harea, nharea);
|
||||
add = true;
|
||||
}
|
||||
else if (hole[nhole - 1] == ea)
|
||||
{
|
||||
// The segment matches the end of the hole boundary.
|
||||
nhole = pushBack(eb, hole, nhole);
|
||||
nhreg = pushBack(r, hreg, nhreg);
|
||||
nharea = pushBack(a, harea, nharea);
|
||||
nhole = PushBack(eb, hole, nhole);
|
||||
nhreg = PushBack(r, hreg, nhreg);
|
||||
nharea = PushBack(a, harea, nharea);
|
||||
add = true;
|
||||
}
|
||||
|
||||
|
@ -850,11 +850,11 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
// Triangulate the hole.
|
||||
int ntris = triangulate(nhole, tverts, thole, tris);
|
||||
int ntris = Triangulate(nhole, tverts, thole, tris);
|
||||
if (ntris < 0)
|
||||
{
|
||||
ntris = -ntris;
|
||||
ctx.warn("removeVertex: triangulate() returned bad results.");
|
||||
ctx.Warn("removeVertex: Triangulate() returned bad results.");
|
||||
}
|
||||
|
||||
// Merge the hole triangles back to polygons.
|
||||
|
@ -906,7 +906,7 @@ namespace DotRecast.Recast
|
|||
for (int k = j + 1; k < npolys; ++k)
|
||||
{
|
||||
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 ea = veaeb[1];
|
||||
int eb = veaeb[2];
|
||||
|
@ -926,7 +926,7 @@ namespace DotRecast.Recast
|
|||
// Found best, merge.
|
||||
int pa = bestPa * 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])
|
||||
pregs[bestPa] = RC_MULTIPLE_REGS;
|
||||
int last = (npolys - 1) * nvp;
|
||||
|
@ -972,9 +972,9 @@ namespace DotRecast.Recast
|
|||
/// limit must be retricted to <= #DT_VERTS_PER_POLYGON.
|
||||
///
|
||||
/// @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();
|
||||
mesh.bmin = cset.bmin;
|
||||
mesh.bmax = cset.bmax;
|
||||
|
@ -1037,11 +1037,11 @@ namespace DotRecast.Recast
|
|||
// Triangulate contour
|
||||
for (int j = 0; j < cont.nverts; ++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)
|
||||
{
|
||||
// Bad triangulation, should not happen.
|
||||
ctx.warn("buildPolyMesh: Bad triangulation Contour " + i + ".");
|
||||
ctx.Warn("buildPolyMesh: Bad triangulation Contour " + i + ".");
|
||||
ntris = -ntris;
|
||||
}
|
||||
|
||||
|
@ -1049,7 +1049,7 @@ namespace DotRecast.Recast
|
|||
for (int j = 0; j < cont.nverts; ++j)
|
||||
{
|
||||
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);
|
||||
indices[j] = inv[0];
|
||||
mesh.nverts = inv[1];
|
||||
|
@ -1093,7 +1093,7 @@ namespace DotRecast.Recast
|
|||
for (int k = j + 1; k < npolys; ++k)
|
||||
{
|
||||
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 ea = veaeb[1];
|
||||
int eb = veaeb[2];
|
||||
|
@ -1113,7 +1113,7 @@ namespace DotRecast.Recast
|
|||
// Found best, merge.
|
||||
int pa = bestPa * 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;
|
||||
if (pb != lastPoly)
|
||||
{
|
||||
|
@ -1153,11 +1153,11 @@ namespace DotRecast.Recast
|
|||
{
|
||||
if (vflags[i] != 0)
|
||||
{
|
||||
if (!canRemoveVertex(ctx, mesh, i))
|
||||
if (!CanRemoveVertex(ctx, mesh, i))
|
||||
continue;
|
||||
removeVertex(ctx, mesh, i, maxTris);
|
||||
RemoveVertex(ctx, mesh, i, maxTris);
|
||||
// Remove vertex
|
||||
// Note: mesh.nverts is already decremented inside removeVertex()!
|
||||
// Note: mesh.nverts is already decremented inside RemoveVertex()!
|
||||
// Fixup vertex flags
|
||||
for (int j = i; j < mesh.nverts; ++j)
|
||||
vflags[j] = vflags[j + 1];
|
||||
|
@ -1166,7 +1166,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
// Calculate adjacency.
|
||||
buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, nvp);
|
||||
BuildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, nvp);
|
||||
|
||||
// Find portal edges
|
||||
if (mesh.borderSize > 0)
|
||||
|
@ -1216,17 +1216,17 @@ namespace DotRecast.Recast
|
|||
+ " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted.");
|
||||
}
|
||||
|
||||
ctx.stopTimer("POLYMESH");
|
||||
ctx.StopTimer("POLYMESH");
|
||||
return mesh;
|
||||
}
|
||||
|
||||
/// @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)
|
||||
return null;
|
||||
|
||||
ctx.startTimer("MERGE_POLYMESH");
|
||||
ctx.StartTimer("MERGE_POLYMESH");
|
||||
PolyMesh mesh = new PolyMesh();
|
||||
mesh.nvp = meshes[0].nvp;
|
||||
mesh.cs = meshes[0].cs;
|
||||
|
@ -1239,8 +1239,8 @@ namespace DotRecast.Recast
|
|||
int maxVertsPerMesh = 0;
|
||||
for (int i = 0; i < nmeshes; ++i)
|
||||
{
|
||||
RecastVectors.min(ref mesh.bmin, meshes[i].bmin);
|
||||
RecastVectors.max(ref mesh.bmax, meshes[i].bmax);
|
||||
RecastVectors.Min(ref mesh.bmin, meshes[i].bmin);
|
||||
RecastVectors.Max(ref mesh.bmax, meshes[i].bmax);
|
||||
maxVertsPerMesh = Math.Max(maxVertsPerMesh, meshes[i].nverts);
|
||||
maxVerts += meshes[i].nverts;
|
||||
maxPolys += meshes[i].npolys;
|
||||
|
@ -1280,7 +1280,7 @@ namespace DotRecast.Recast
|
|||
for (int j = 0; j < pmesh.nverts; ++j)
|
||||
{
|
||||
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);
|
||||
|
||||
vremap[j] = inv[0];
|
||||
|
@ -1335,7 +1335,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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.");
|
||||
}
|
||||
|
||||
ctx.stopTimer("MERGE_POLYMESH");
|
||||
ctx.StopTimer("MERGE_POLYMESH");
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
public static PolyMesh copyPolyMesh(Telemetry ctx, PolyMesh src)
|
||||
public static PolyMesh CopyPolyMesh(Telemetry ctx, PolyMesh src)
|
||||
{
|
||||
PolyMesh dst = new PolyMesh();
|
||||
|
||||
|
|
|
@ -46,37 +46,37 @@ namespace DotRecast.Recast
|
|||
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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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 dy = verts[q + 2] - verts[p + 2];
|
||||
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 dy = q[2] - p[2];
|
||||
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 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 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 dy = verts[q + 2] - p[2];
|
||||
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 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 v1 = verts[p2 + 2] - verts[p1 + 2];
|
||||
|
@ -143,7 +143,7 @@ namespace DotRecast.Recast
|
|||
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 v1 = p2[2] - p1[2];
|
||||
|
@ -152,7 +152,7 @@ namespace DotRecast.Recast
|
|||
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 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;
|
||||
// Calculate the circle relative to p1, to avoid some precision issues.
|
||||
Vector3f v1 = new Vector3f();
|
||||
Vector3f v2 = new Vector3f();
|
||||
Vector3f v3 = new Vector3f();
|
||||
RecastVectors.sub(ref v2, verts, p2, p1);
|
||||
RecastVectors.sub(ref v3, verts, p3, p1);
|
||||
RecastVectors.Sub(ref v2, verts, p2, 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)
|
||||
{
|
||||
float v1Sq = vdot2(v1, v1);
|
||||
float v2Sq = vdot2(v2, v2);
|
||||
float v3Sq = vdot2(v3, v3);
|
||||
float v1Sq = Vdot2(v1, v1);
|
||||
float v2Sq = Vdot2(v2, v2);
|
||||
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.y = 0;
|
||||
c.z = (v1Sq * (v3.x - v2.x) + v2Sq * (v1.x - v3.x) + v3Sq * (v2.x - v1.x)) / (2 * cp);
|
||||
r.Exchange(vdist2(c, v1));
|
||||
RecastVectors.add(ref c, c, verts, p1);
|
||||
r.Exchange(Vdist2(c, v1));
|
||||
RecastVectors.Add(ref c, c, verts, p1);
|
||||
return true;
|
||||
}
|
||||
|
||||
RecastVectors.copy(ref c, verts, p1);
|
||||
RecastVectors.Copy(ref c, verts, p1);
|
||||
r.Exchange(0f);
|
||||
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 v1 = new Vector3f();
|
||||
Vector3f v2 = new Vector3f();
|
||||
RecastVectors.sub(ref v0, verts, c, a);
|
||||
RecastVectors.sub(ref v1, verts, b, a);
|
||||
RecastVectors.sub(ref v2, p, verts, a);
|
||||
RecastVectors.Sub(ref v0, verts, c, a);
|
||||
RecastVectors.Sub(ref v1, verts, b, a);
|
||||
RecastVectors.Sub(ref v2, p, verts, a);
|
||||
|
||||
float dot00 = vdot2(v0, v0);
|
||||
float dot01 = vdot2(v0, v1);
|
||||
float dot02 = vdot2(v0, v2);
|
||||
float dot11 = vdot2(v1, v1);
|
||||
float dot12 = vdot2(v1, v2);
|
||||
float dot00 = Vdot2(v0, v0);
|
||||
float dot01 = Vdot2(v0, v1);
|
||||
float dot02 = Vdot2(v0, v2);
|
||||
float dot11 = Vdot2(v1, v1);
|
||||
float dot12 = Vdot2(v1, v2);
|
||||
|
||||
// Compute barycentric coordinates
|
||||
float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
|
||||
|
@ -222,7 +222,7 @@ namespace DotRecast.Recast
|
|||
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 pqy = verts[q + 1] - verts[p + 1];
|
||||
|
@ -253,7 +253,7 @@ namespace DotRecast.Recast
|
|||
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 pqz = poly[q + 2] - poly[p + 2];
|
||||
|
@ -281,7 +281,7 @@ namespace DotRecast.Recast
|
|||
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 pqz = poly[q + 2] - poly[p + 2];
|
||||
|
@ -309,7 +309,7 @@ namespace DotRecast.Recast
|
|||
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;
|
||||
for (int i = 0; i < ntris; ++i)
|
||||
|
@ -317,7 +317,7 @@ namespace DotRecast.Recast
|
|||
int va = tris[i * 4 + 0] * 3;
|
||||
int vb = tris[i * 4 + 1] * 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)
|
||||
{
|
||||
dmin = d;
|
||||
|
@ -332,7 +332,7 @@ namespace DotRecast.Recast
|
|||
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;
|
||||
int i, j;
|
||||
|
@ -347,19 +347,19 @@ namespace DotRecast.Recast
|
|||
c = !c;
|
||||
}
|
||||
|
||||
dmin = Math.Min(dmin, distancePtSeg2d(p, verts, vj, vi));
|
||||
dmin = Math.Min(dmin, DistancePtSeg2d(p, verts, vj, vi));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int ix = (int)Math.Floor(fx * ics + 0.01f);
|
||||
int iz = (int)Math.Floor(fz * ics + 0.01f);
|
||||
ix = clamp(ix - hp.xmin, 0, hp.width - 1);
|
||||
iz = clamp(iz - hp.ymin, 0, hp.height - 1);
|
||||
ix = Clamp(ix - hp.xmin, 0, hp.width - 1);
|
||||
iz = Clamp(iz - hp.ymin, 0, hp.height - 1);
|
||||
int h = hp.data[ix + iz * hp.width];
|
||||
if (h == RC_UNSET_HEIGHT)
|
||||
{
|
||||
|
@ -436,7 +436,7 @@ namespace DotRecast.Recast
|
|||
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++)
|
||||
{
|
||||
|
@ -450,7 +450,7 @@ namespace DotRecast.Recast
|
|||
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)
|
||||
{
|
||||
|
@ -458,7 +458,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
// Add edge if not already in the triangulation.
|
||||
int e = findEdge(edges, s, t);
|
||||
int e = FindEdge(edges, s, t);
|
||||
if (e == EV_UNDEF)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -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 a2 = vcross2(verts, a, b, c);
|
||||
float a1 = Vcross2(verts, a, b, d);
|
||||
float a2 = Vcross2(verts, a, b, c);
|
||||
if (a1 * a2 < 0.0f)
|
||||
{
|
||||
float a3 = vcross2(verts, c, d, a);
|
||||
float a3 = Vcross2(verts, c, d, a);
|
||||
float a4 = a3 + a2 - a1;
|
||||
if (a3 * a4 < 0.0f)
|
||||
{
|
||||
|
@ -497,7 +497,7 @@ namespace DotRecast.Recast
|
|||
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)
|
||||
{
|
||||
|
@ -509,7 +509,7 @@ namespace DotRecast.Recast
|
|||
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;
|
||||
}
|
||||
|
@ -518,7 +518,7 @@ namespace DotRecast.Recast
|
|||
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;
|
||||
|
||||
|
@ -553,17 +553,17 @@ namespace DotRecast.Recast
|
|||
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)
|
||||
{
|
||||
// The circle is not updated yet, do it now.
|
||||
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;
|
||||
}
|
||||
|
||||
float d = vdist2(c, pts, u * 3);
|
||||
float d = Vdist2(c, pts, u * 3);
|
||||
float tol = 0.001f;
|
||||
if (d > r.Get() * (1 + tol))
|
||||
{
|
||||
|
@ -574,25 +574,25 @@ namespace DotRecast.Recast
|
|||
{
|
||||
// Inside safe circumcircle, update circle.
|
||||
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
|
||||
{
|
||||
// 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.
|
||||
if (overlapEdges(pts, edges, s, u))
|
||||
if (OverlapEdges(pts, edges, s, u))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (overlapEdges(pts, edges, t, u))
|
||||
if (OverlapEdges(pts, edges, t, u))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Edge is valid.
|
||||
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)
|
||||
{
|
||||
// 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.
|
||||
e = findEdge(edges, pt, s);
|
||||
e = FindEdge(edges, pt, s);
|
||||
if (e == EV_UNDEF)
|
||||
{
|
||||
addEdge(ctx, edges, maxEdges, pt, s, nfaces, EV_UNDEF);
|
||||
AddEdge(ctx, edges, maxEdges, pt, s, nfaces, EV_UNDEF);
|
||||
}
|
||||
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.
|
||||
e = findEdge(edges, t, pt);
|
||||
e = FindEdge(edges, t, pt);
|
||||
if (e == EV_UNDEF)
|
||||
{
|
||||
addEdge(ctx, edges, maxEdges, t, pt, nfaces, EV_UNDEF);
|
||||
AddEdge(ctx, edges, maxEdges, t, pt, nfaces, EV_UNDEF);
|
||||
}
|
||||
else
|
||||
{
|
||||
updateLeftFace(edges, e * 4, t, pt, nfaces);
|
||||
UpdateLeftFace(edges, e * 4, t, pt, nfaces);
|
||||
}
|
||||
|
||||
nfaces++;
|
||||
}
|
||||
else
|
||||
{
|
||||
updateLeftFace(edges, e * 4, s, t, EV_HULL);
|
||||
UpdateLeftFace(edges, e * 4, s, t, EV_HULL);
|
||||
}
|
||||
|
||||
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 maxEdges = npts * 10;
|
||||
List<int> edges = new List<int>(64);
|
||||
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;
|
||||
|
@ -650,12 +650,12 @@ namespace DotRecast.Recast
|
|||
{
|
||||
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)
|
||||
{
|
||||
nfaces = completeFacet(ctx, pts, npts, edges, maxEdges, nfaces, currentEdge);
|
||||
nfaces = CompleteFacet(ctx, pts, npts, edges, maxEdges, nfaces, currentEdge);
|
||||
}
|
||||
|
||||
currentEdge++;
|
||||
|
@ -716,7 +716,7 @@ namespace DotRecast.Recast
|
|||
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]);
|
||||
// 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 + 1] = tris[tris.Count - 3];
|
||||
tris[t + 2] = tris[tris.Count - 2];
|
||||
|
@ -731,7 +731,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
// 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;
|
||||
for (int i = 0; i < nverts; i++)
|
||||
|
@ -747,7 +747,7 @@ namespace DotRecast.Recast
|
|||
continue;
|
||||
}
|
||||
|
||||
float d = distancePtSeg2d(verts, j * 3, verts, p1, p2);
|
||||
float d = DistancePtSeg2d(verts, j * 3, verts, p1, p2);
|
||||
maxEdgeDist = Math.Max(maxEdgeDist, d);
|
||||
}
|
||||
|
||||
|
@ -757,7 +757,7 @@ namespace DotRecast.Recast
|
|||
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;
|
||||
|
||||
|
@ -772,12 +772,12 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
// segments on edges
|
||||
int pi = RecastMesh.prev(i, nhull);
|
||||
int ni = RecastMesh.next(i, nhull);
|
||||
int pi = RecastMesh.Prev(i, nhull);
|
||||
int ni = RecastMesh.Next(i, nhull);
|
||||
int pv = hull[pi] * 3;
|
||||
int cv = hull[i] * 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)
|
||||
{
|
||||
start = i;
|
||||
|
@ -797,18 +797,18 @@ namespace DotRecast.Recast
|
|||
// depending on which triangle has shorter perimeter.
|
||||
// This heuristic was chose emprically, since it seems
|
||||
// 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.
|
||||
int nleft = RecastMesh.next(left, nhull);
|
||||
int nright = RecastMesh.prev(right, nhull);
|
||||
int nleft = RecastMesh.Next(left, nhull);
|
||||
int nright = RecastMesh.Prev(right, nhull);
|
||||
|
||||
int cvleft = hull[left] * 3;
|
||||
int nvleft = hull[nleft] * 3;
|
||||
int cvright = hull[right] * 3;
|
||||
int nvright = hull[nright] * 3;
|
||||
float dleft = vdist2(verts, cvleft, nvleft) + vdist2(verts, nvleft, cvright);
|
||||
float dright = vdist2(verts, cvright, nvright) + vdist2(verts, cvleft, nvright);
|
||||
float dleft = Vdist2(verts, cvleft, nvleft) + Vdist2(verts, nvleft, cvright);
|
||||
float dright = Vdist2(verts, cvright, nvright) + Vdist2(verts, cvleft, nvright);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static float getJitterY(int i)
|
||||
private static float GetJitterY(int i)
|
||||
{
|
||||
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)
|
||||
{
|
||||
List<int> samples = new List<int>(512);
|
||||
|
@ -853,7 +853,7 @@ namespace DotRecast.Recast
|
|||
|
||||
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();
|
||||
|
@ -862,7 +862,7 @@ namespace DotRecast.Recast
|
|||
float ics = 1.0f / cs;
|
||||
|
||||
// Calculate minimum extents of the polygon based on input data.
|
||||
float minExtent = polyMinExtent(verts, nverts);
|
||||
float minExtent = PolyMinExtent(verts, nverts);
|
||||
|
||||
// Tessellate outlines.
|
||||
// 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 + 1] = @in[vj + 1] + dy * 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;
|
||||
}
|
||||
|
||||
|
@ -940,7 +940,7 @@ namespace DotRecast.Recast
|
|||
int maxi = -1;
|
||||
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)
|
||||
{
|
||||
maxd = dev;
|
||||
|
@ -972,7 +972,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
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;
|
||||
nverts++;
|
||||
}
|
||||
|
@ -981,7 +981,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
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;
|
||||
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 (minExtent < sampleDist * 2)
|
||||
{
|
||||
triangulateHull(nverts, verts, nhull, hull, nin, tris);
|
||||
TriangulateHull(nverts, verts, nhull, hull, nin, tris);
|
||||
return nverts;
|
||||
}
|
||||
|
||||
|
@ -1000,7 +1000,7 @@ namespace DotRecast.Recast
|
|||
// We're using the triangulateHull instead of delaunayHull as it tends to
|
||||
// create a bit better triangulation for long thin triangles when there
|
||||
// are no internal points.
|
||||
triangulateHull(nverts, verts, nhull, hull, nin, tris);
|
||||
TriangulateHull(nverts, verts, nhull, hull, nin, tris);
|
||||
|
||||
if (tris.Count == 0)
|
||||
{
|
||||
|
@ -1013,12 +1013,12 @@ namespace DotRecast.Recast
|
|||
// Create sample locations in a grid.
|
||||
Vector3f bmin = new Vector3f();
|
||||
Vector3f bmax = new Vector3f();
|
||||
RecastVectors.copy(ref bmin, @in, 0);
|
||||
RecastVectors.copy(ref bmax, @in, 0);
|
||||
RecastVectors.Copy(ref bmin, @in, 0);
|
||||
RecastVectors.Copy(ref bmax, @in, 0);
|
||||
for (int i = 1; i < nin; ++i)
|
||||
{
|
||||
RecastVectors.min(ref bmin, @in, i * 3);
|
||||
RecastVectors.max(ref bmax, @in, i * 3);
|
||||
RecastVectors.Min(ref bmin, @in, i * 3);
|
||||
RecastVectors.Max(ref bmax, @in, i * 3);
|
||||
}
|
||||
|
||||
int x0 = (int)Math.Floor(bmin.x / sampleDist);
|
||||
|
@ -1035,13 +1035,13 @@ namespace DotRecast.Recast
|
|||
pt.y = (bmax.y + bmin.y) * 0.5f;
|
||||
pt.z = z * sampleDist;
|
||||
// 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;
|
||||
}
|
||||
|
||||
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(0); // Not added
|
||||
}
|
||||
|
@ -1073,10 +1073,10 @@ namespace DotRecast.Recast
|
|||
Vector3f pt = new Vector3f();
|
||||
// The sample location is jittered to get rid of some bad triangulations
|
||||
// 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.z = samples[s + 2] * sampleDist + getJitterY(i) * cs * 0.1f;
|
||||
float d = distToTriMesh(pt, verts, nverts, tris, tris.Count / 4);
|
||||
pt.z = samples[s + 2] * sampleDist + GetJitterY(i) * cs * 0.1f;
|
||||
float d = DistToTriMesh(pt, verts, nverts, tris, tris.Count / 4);
|
||||
if (d < 0)
|
||||
{
|
||||
continue; // did not hit the mesh.
|
||||
|
@ -1099,12 +1099,12 @@ namespace DotRecast.Recast
|
|||
// Mark sample as added.
|
||||
samples[besti * 4 + 3] = 1;
|
||||
// Add the new sample point.
|
||||
RecastVectors.copy(verts, nverts * 3, bestpt, 0);
|
||||
RecastVectors.Copy(verts, nverts * 3, bestpt, 0);
|
||||
nverts++;
|
||||
|
||||
// Create new triangulation.
|
||||
// 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Note: Reads to the compact heightfield are offset by border size (bs)
|
||||
|
@ -1186,7 +1186,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1211,11 +1211,11 @@ namespace DotRecast.Recast
|
|||
int directDir;
|
||||
if (cx == pcx)
|
||||
{
|
||||
directDir = rcGetDirForOffset(0, pcy > cy ? 1 : -1);
|
||||
directDir = RcGetDirForOffset(0, pcy > cy ? 1 : -1);
|
||||
}
|
||||
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
|
||||
|
@ -1272,14 +1272,14 @@ namespace DotRecast.Recast
|
|||
|
||||
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(v2);
|
||||
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)
|
||||
{
|
||||
// Note: Reads to the compact heightfield are offset by border size (bs)
|
||||
|
@ -1333,7 +1333,7 @@ namespace DotRecast.Recast
|
|||
|
||||
if (border)
|
||||
{
|
||||
push3(queue, x, y, i);
|
||||
Push3(queue, x, y, i);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -1348,7 +1348,7 @@ namespace DotRecast.Recast
|
|||
// then use the center as the seed point.
|
||||
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;
|
||||
|
@ -1395,20 +1395,20 @@ namespace DotRecast.Recast
|
|||
CompactSpan @as = chf.spans[ai];
|
||||
|
||||
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.
|
||||
// Figure out if edge (va,vb) is part of the polygon boundary.
|
||||
float thrSqr = 0.001f * 0.001f;
|
||||
for (int i = 0, j = npoly - 1; i < npoly; j = i++)
|
||||
{
|
||||
if (distancePtSeg2d(verts, va, vpoly, j * 3, i * 3) < thrSqr
|
||||
&& distancePtSeg2d(verts, vb, 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)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@ -1417,12 +1417,12 @@ namespace DotRecast.Recast
|
|||
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;
|
||||
flags |= getEdgeFlags(verts, va, vb, vpoly, npoly) << 0;
|
||||
flags |= getEdgeFlags(verts, vb, vc, vpoly, npoly) << 2;
|
||||
flags |= getEdgeFlags(verts, vc, va, vpoly, npoly) << 4;
|
||||
flags |= GetEdgeFlags(verts, va, vb, vpoly, npoly) << 0;
|
||||
flags |= GetEdgeFlags(verts, vb, vc, vpoly, npoly) << 2;
|
||||
flags |= GetEdgeFlags(verts, vc, va, vpoly, npoly) << 4;
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
@ -1431,10 +1431,10 @@ namespace DotRecast.Recast
|
|||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||
///
|
||||
/// @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)
|
||||
{
|
||||
ctx.startTimer("POLYMESHDETAIL");
|
||||
ctx.StartTimer("POLYMESHDETAIL");
|
||||
if (mesh.nverts == 0 || mesh.npolys == 0)
|
||||
{
|
||||
return null;
|
||||
|
@ -1533,10 +1533,10 @@ namespace DotRecast.Recast
|
|||
hp.ymin = bounds[i * 4 + 2];
|
||||
hp.width = bounds[i * 4 + 1] - bounds[i * 4 + 0];
|
||||
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.
|
||||
int nverts = buildPolyDetail(ctx, poly, npoly, sampleDist, sampleMaxError, heightSearchRadius, chf, hp,
|
||||
int nverts = BuildPolyDetail(ctx, poly, npoly, sampleDist, sampleMaxError, heightSearchRadius, chf, hp,
|
||||
verts, tris);
|
||||
|
||||
// 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 + 1] = tris[t + 1];
|
||||
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);
|
||||
dmesh.ntris++;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.stopTimer("POLYMESHDETAIL");
|
||||
ctx.StopTimer("POLYMESHDETAIL");
|
||||
return dmesh;
|
||||
}
|
||||
|
||||
/// @see rcAllocPolyMeshDetail, rcPolyMeshDetail
|
||||
PolyMeshDetail mergePolyMeshDetails(Telemetry ctx, PolyMeshDetail[] meshes, int nmeshes)
|
||||
PolyMeshDetail MergePolyMeshDetails(Telemetry ctx, PolyMeshDetail[] meshes, int nmeshes)
|
||||
{
|
||||
PolyMeshDetail mesh = new PolyMeshDetail();
|
||||
|
||||
ctx.startTimer("MERGE_POLYMESHDETAIL");
|
||||
ctx.StartTimer("MERGE_POLYMESHDETAIL");
|
||||
|
||||
int maxVerts = 0;
|
||||
int maxTris = 0;
|
||||
|
@ -1674,7 +1674,7 @@ namespace DotRecast.Recast
|
|||
|
||||
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++;
|
||||
}
|
||||
|
||||
|
@ -1688,7 +1688,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
}
|
||||
|
||||
ctx.stopTimer("MERGE_POLYMESHDETAIL");
|
||||
ctx.StopTimer("MERGE_POLYMESHDETAIL");
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace DotRecast.Recast
|
|||
* Max axis extents of bounding box B
|
||||
* @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;
|
||||
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||
|
@ -50,7 +50,7 @@ namespace DotRecast.Recast
|
|||
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;
|
||||
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]
|
||||
* @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 idx = x + y * heightfield.width;
|
||||
|
@ -170,7 +170,7 @@ namespace DotRecast.Recast
|
|||
* The separating axis
|
||||
* @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)
|
||||
{
|
||||
float[] d = new float[12];
|
||||
|
@ -191,19 +191,19 @@ namespace DotRecast.Recast
|
|||
+ (inVerts[inVertsOffset + i * 3 + 1] - inVerts[inVertsOffset + j * 3 + 1]) * s;
|
||||
inVerts[outVerts1 + m * 3 + 2] = inVerts[inVertsOffset + j * 3 + 2]
|
||||
+ (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++;
|
||||
n++;
|
||||
// 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
|
||||
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++;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
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++;
|
||||
if (d[i] != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
RecastVectors.copy(inVerts, outVerts2 + n * 3, inVerts, inVertsOffset + i * 3);
|
||||
RecastVectors.Copy(inVerts, outVerts2 + n * 3, inVerts, inVertsOffset + i * 3);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ namespace DotRecast.Recast
|
|||
* @param flagMergeThreshold
|
||||
* 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 tmin = new Vector3f();
|
||||
|
@ -263,15 +263,15 @@ namespace DotRecast.Recast
|
|||
float by = hfBBMax.y - hfBBMin.y;
|
||||
|
||||
// Calculate the bounding box of the triangle.
|
||||
RecastVectors.copy(ref tmin, verts, v0 * 3);
|
||||
RecastVectors.copy(ref tmax, verts, v0 * 3);
|
||||
RecastVectors.min(ref tmin, verts, v1 * 3);
|
||||
RecastVectors.min(ref tmin, verts, v2 * 3);
|
||||
RecastVectors.max(ref tmax, verts, v1 * 3);
|
||||
RecastVectors.max(ref tmax, verts, v2 * 3);
|
||||
RecastVectors.Copy(ref tmin, verts, v0 * 3);
|
||||
RecastVectors.Copy(ref tmax, verts, v0 * 3);
|
||||
RecastVectors.Min(ref tmin, verts, v1 * 3);
|
||||
RecastVectors.Min(ref tmin, verts, v2 * 3);
|
||||
RecastVectors.Max(ref tmax, verts, v1 * 3);
|
||||
RecastVectors.Max(ref tmax, verts, v2 * 3);
|
||||
|
||||
// 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;
|
||||
|
||||
// Calculate the footprint of the triangle on the grid's y-axis
|
||||
|
@ -281,8 +281,8 @@ namespace DotRecast.Recast
|
|||
int w = hf.width;
|
||||
int h = hf.height;
|
||||
// use -1 rather than 0 to cut the polygon properly at the start of the tile
|
||||
z0 = clamp(z0, -1, h - 1);
|
||||
z1 = clamp(z1, 0, h - 1);
|
||||
z0 = Clamp(z0, -1, h - 1);
|
||||
z1 = Clamp(z1, 0, h - 1);
|
||||
|
||||
// Clip the triangle into all grid cells it touches.
|
||||
float[] buf = new float[7 * 3 * 4];
|
||||
|
@ -291,16 +291,16 @@ namespace DotRecast.Recast
|
|||
int p1 = inRow + 7 * 3;
|
||||
int p2 = p1 + 7 * 3;
|
||||
|
||||
RecastVectors.copy(buf, 0, verts, v0 * 3);
|
||||
RecastVectors.copy(buf, 3, verts, v1 * 3);
|
||||
RecastVectors.copy(buf, 6, verts, v2 * 3);
|
||||
RecastVectors.Copy(buf, 0, verts, v0 * 3);
|
||||
RecastVectors.Copy(buf, 3, verts, v1 * 3);
|
||||
RecastVectors.Copy(buf, 6, verts, v2 * 3);
|
||||
int nvRow, nvIn = 3;
|
||||
|
||||
for (int z = z0; z <= z1; ++z)
|
||||
{
|
||||
// Clip polygon to row. Store the remaining polygon as well
|
||||
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];
|
||||
nvIn = nvrowin[1];
|
||||
{
|
||||
|
@ -332,15 +332,15 @@ namespace DotRecast.Recast
|
|||
continue;
|
||||
}
|
||||
|
||||
x0 = clamp(x0, -1, w - 1);
|
||||
x1 = clamp(x1, 0, w - 1);
|
||||
x0 = Clamp(x0, -1, w - 1);
|
||||
x1 = Clamp(x1, 0, w - 1);
|
||||
|
||||
int nv, nv2 = nvRow;
|
||||
for (int x = x0; x <= x1; ++x)
|
||||
{
|
||||
// Clip polygon to column. store the remaining polygon as well
|
||||
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];
|
||||
nv2 = nvnv2[1];
|
||||
{
|
||||
|
@ -378,10 +378,10 @@ namespace DotRecast.Recast
|
|||
spanMax = by;
|
||||
|
||||
// Snap the span to the heightfield height grid.
|
||||
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 spanMinCellIndex = Clamp((int)Math.Floor(spanMin * inverseCellHeight), 0, 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]
|
||||
* @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)
|
||||
{
|
||||
ctx.startTimer("RASTERIZE_TRIANGLES");
|
||||
ctx.StartTimer("RASTERIZE_TRIANGLES");
|
||||
|
||||
float inverseCellSize = 1.0f / heightfield.cs;
|
||||
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);
|
||||
|
||||
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]
|
||||
* @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)
|
||||
{
|
||||
ctx.startTimer("RASTERIZE_TRIANGLES");
|
||||
ctx.StartTimer("RASTERIZE_TRIANGLES");
|
||||
|
||||
float inverseCellSize = 1.0f / heightfield.cs;
|
||||
float inverseCellHeight = 1.0f / heightfield.ch;
|
||||
|
@ -450,11 +450,11 @@ namespace DotRecast.Recast
|
|||
int v0 = tris[triIndex * 3 + 0];
|
||||
int v1 = tris[triIndex * 3 + 1];
|
||||
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);
|
||||
}
|
||||
|
||||
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]
|
||||
* @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)
|
||||
{
|
||||
ctx.startTimer("RASTERIZE_TRIANGLES");
|
||||
ctx.StartTimer("RASTERIZE_TRIANGLES");
|
||||
|
||||
float inverseCellSize = 1.0f / heightfield.cs;
|
||||
float inverseCellHeight = 1.0f / heightfield.ch;
|
||||
|
@ -487,11 +487,11 @@ namespace DotRecast.Recast
|
|||
int v0 = (triIndex * 3 + 0);
|
||||
int v1 = (triIndex * 3 + 1);
|
||||
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);
|
||||
}
|
||||
|
||||
ctx.stopTimer("RASTERIZE_TRIANGLES");
|
||||
ctx.StopTimer("RASTERIZE_TRIANGLES");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace DotRecast.Recast
|
|||
public int nei; // neighbour id
|
||||
}
|
||||
|
||||
public static int calculateDistanceField(CompactHeightfield chf, int[] src)
|
||||
public static int CalculateDistanceField(CompactHeightfield chf, int[] src)
|
||||
{
|
||||
int maxDist;
|
||||
int w = chf.width;
|
||||
|
@ -219,7 +219,7 @@ namespace DotRecast.Recast
|
|||
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 h = chf.height;
|
||||
|
@ -280,7 +280,7 @@ namespace DotRecast.Recast
|
|||
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 w = chf.width;
|
||||
|
@ -398,7 +398,7 @@ namespace DotRecast.Recast
|
|||
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)
|
||||
{
|
||||
int w = chf.width;
|
||||
|
@ -524,7 +524,7 @@ namespace DotRecast.Recast
|
|||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -607,7 +607,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
}
|
||||
|
||||
private static void removeAdjacentNeighbours(Region reg)
|
||||
private static void RemoveAdjacentNeighbours(Region reg)
|
||||
{
|
||||
// Remove adjacent duplicates.
|
||||
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;
|
||||
for (int i = 0; i < reg.connections.Count; ++i)
|
||||
|
@ -646,11 +646,11 @@ namespace DotRecast.Recast
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -682,7 +682,7 @@ namespace DotRecast.Recast
|
|||
return true;
|
||||
}
|
||||
|
||||
private static void addUniqueFloorRegion(Region reg, int n)
|
||||
private static void AddUniqueFloorRegion(Region reg, int 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 bid = regb.id;
|
||||
|
@ -743,11 +743,11 @@ namespace DotRecast.Recast
|
|||
rega.connections.Add(bcon[(insb + 1 + i) % ni]);
|
||||
}
|
||||
|
||||
removeAdjacentNeighbours(rega);
|
||||
RemoveAdjacentNeighbours(rega);
|
||||
|
||||
for (int j = 0; j < regb.floors.Count; ++j)
|
||||
{
|
||||
addUniqueFloorRegion(rega, regb.floors[j]);
|
||||
AddUniqueFloorRegion(rega, regb.floors[j]);
|
||||
}
|
||||
|
||||
rega.spanCount += regb.spanCount;
|
||||
|
@ -757,14 +757,14 @@ namespace DotRecast.Recast
|
|||
return true;
|
||||
}
|
||||
|
||||
private static bool isRegionConnectedToBorder(Region reg)
|
||||
private static bool IsRegionConnectedToBorder(Region reg)
|
||||
{
|
||||
// Region is connected to border if
|
||||
// one of the neighbours is null id.
|
||||
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];
|
||||
int r = 0;
|
||||
|
@ -784,7 +784,7 @@ namespace DotRecast.Recast
|
|||
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)
|
||||
{
|
||||
int startDir = dir;
|
||||
|
@ -807,7 +807,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
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
|
||||
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)
|
||||
{
|
||||
int w = chf.width;
|
||||
|
@ -925,7 +925,7 @@ namespace DotRecast.Recast
|
|||
reg.overlap = true;
|
||||
}
|
||||
|
||||
addUniqueFloorRegion(reg, floorId);
|
||||
AddUniqueFloorRegion(reg, floorId);
|
||||
}
|
||||
|
||||
// Have found contour
|
||||
|
@ -940,7 +940,7 @@ namespace DotRecast.Recast
|
|||
int ndir = -1;
|
||||
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;
|
||||
break;
|
||||
|
@ -951,7 +951,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
// The cell is at border.
|
||||
// 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.
|
||||
if (reg.spanCount > mergeRegionSize && isRegionConnectedToBorder(reg))
|
||||
if (reg.spanCount > mergeRegionSize && IsRegionConnectedToBorder(reg))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -1086,7 +1086,7 @@ namespace DotRecast.Recast
|
|||
continue;
|
||||
}
|
||||
|
||||
if (mreg.spanCount < smallest && canMergeWithRegion(reg, mreg) && canMergeWithRegion(mreg, reg))
|
||||
if (mreg.spanCount < smallest && CanMergeWithRegion(reg, mreg) && CanMergeWithRegion(mreg, reg))
|
||||
{
|
||||
smallest = mreg.spanCount;
|
||||
mergeId = mreg.id;
|
||||
|
@ -1100,7 +1100,7 @@ namespace DotRecast.Recast
|
|||
Region target = regions[mergeId];
|
||||
|
||||
// Merge neighbours.
|
||||
if (mergeRegions(target, reg))
|
||||
if (MergeRegions(target, reg))
|
||||
{
|
||||
// Fixup regions pointing to current region.
|
||||
for (int j = 0; j < nreg; ++j)
|
||||
|
@ -1119,7 +1119,7 @@ namespace DotRecast.Recast
|
|||
|
||||
// Replace the current region with the new one if the
|
||||
// current regions is neighbour.
|
||||
replaceNeighbour(regions[j], oldId, mergeId);
|
||||
ReplaceNeighbour(regions[j], oldId, mergeId);
|
||||
}
|
||||
|
||||
mergeCount++;
|
||||
|
@ -1188,7 +1188,7 @@ namespace DotRecast.Recast
|
|||
return maxRegionId;
|
||||
}
|
||||
|
||||
private static void addUniqueConnection(Region reg, int n)
|
||||
private static void AddUniqueConnection(Region reg, int 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)
|
||||
{
|
||||
int w = chf.width;
|
||||
|
@ -1250,7 +1250,7 @@ namespace DotRecast.Recast
|
|||
int rai = srcReg[ai];
|
||||
if (rai > 0 && rai < nreg && rai != ri)
|
||||
{
|
||||
addUniqueConnection(reg, rai);
|
||||
AddUniqueConnection(reg, rai);
|
||||
}
|
||||
|
||||
if ((rai & RC_BORDER_REG) != 0)
|
||||
|
@ -1270,8 +1270,8 @@ namespace DotRecast.Recast
|
|||
{
|
||||
Region ri = regions[lregs[i]];
|
||||
Region rj = regions[lregs[j]];
|
||||
addUniqueFloorRegion(ri, lregs[j]);
|
||||
addUniqueFloorRegion(rj, lregs[i]);
|
||||
AddUniqueFloorRegion(ri, lregs[j]);
|
||||
AddUniqueFloorRegion(rj, lregs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1351,7 +1351,7 @@ namespace DotRecast.Recast
|
|||
// Merge current layers to root.
|
||||
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);
|
||||
|
@ -1442,31 +1442,31 @@ namespace DotRecast.Recast
|
|||
/// and rcCompactHeightfield::dist fields.
|
||||
///
|
||||
/// @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];
|
||||
ctx.startTimer("DISTANCEFIELD_DIST");
|
||||
ctx.StartTimer("DISTANCEFIELD_DIST");
|
||||
|
||||
int maxDist = calculateDistanceField(chf, src);
|
||||
int maxDist = CalculateDistanceField(chf, src);
|
||||
chf.maxDistance = maxDist;
|
||||
|
||||
ctx.stopTimer("DISTANCEFIELD_DIST");
|
||||
ctx.StopTimer("DISTANCEFIELD_DIST");
|
||||
|
||||
ctx.startTimer("DISTANCEFIELD_BLUR");
|
||||
ctx.StartTimer("DISTANCEFIELD_BLUR");
|
||||
|
||||
// Blur
|
||||
src = boxBlur(chf, 1, src);
|
||||
src = BoxBlur(chf, 1, src);
|
||||
|
||||
// Store distance.
|
||||
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 w = chf.width;
|
||||
|
@ -1505,10 +1505,10 @@ namespace DotRecast.Recast
|
|||
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
||||
///
|
||||
/// @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)
|
||||
{
|
||||
ctx.startTimer("REGIONS");
|
||||
ctx.StartTimer("REGIONS");
|
||||
|
||||
int w = chf.width;
|
||||
int h = chf.height;
|
||||
|
@ -1531,13 +1531,13 @@ namespace DotRecast.Recast
|
|||
int bw = Math.Min(w, borderSize);
|
||||
int bh = Math.Min(h, borderSize);
|
||||
// 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++;
|
||||
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++;
|
||||
paintRectRegion(0, w, 0, bh, id | RC_BORDER_REG, chf, srcReg);
|
||||
PaintRectRegion(0, w, 0, bh, id | RC_BORDER_REG, chf, srcReg);
|
||||
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++;
|
||||
}
|
||||
|
||||
|
@ -1650,15 +1650,15 @@ namespace DotRecast.Recast
|
|||
}
|
||||
}
|
||||
|
||||
ctx.startTimer("REGIONS_FILTER");
|
||||
ctx.StartTimer("REGIONS_FILTER");
|
||||
|
||||
// Merge regions and filter out small regions.
|
||||
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.
|
||||
|
||||
ctx.stopTimer("REGIONS_FILTER");
|
||||
ctx.StopTimer("REGIONS_FILTER");
|
||||
|
||||
// Store the result out.
|
||||
for (int i = 0; i < chf.spanCount; ++i)
|
||||
|
@ -1666,7 +1666,7 @@ namespace DotRecast.Recast
|
|||
chf.spans[i].reg = srcReg[i];
|
||||
}
|
||||
|
||||
ctx.stopTimer("REGIONS");
|
||||
ctx.StopTimer("REGIONS");
|
||||
}
|
||||
|
||||
/// @par
|
||||
|
@ -1688,16 +1688,16 @@ namespace DotRecast.Recast
|
|||
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
||||
///
|
||||
/// @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)
|
||||
{
|
||||
ctx.startTimer("REGIONS");
|
||||
ctx.StartTimer("REGIONS");
|
||||
|
||||
int w = chf.width;
|
||||
int h = chf.height;
|
||||
int borderSize = chf.borderSize;
|
||||
|
||||
ctx.startTimer("REGIONS_WATERSHED");
|
||||
ctx.StartTimer("REGIONS_WATERSHED");
|
||||
|
||||
int LOG_NB_STACKS = 3;
|
||||
int NB_STACKS = 1 << LOG_NB_STACKS;
|
||||
|
@ -1727,13 +1727,13 @@ namespace DotRecast.Recast
|
|||
int bw = Math.Min(w, borderSize);
|
||||
int bh = Math.Min(h, borderSize);
|
||||
// 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++;
|
||||
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++;
|
||||
paintRectRegion(0, w, 0, bh, regionId | RC_BORDER_REG, chf, srcReg);
|
||||
PaintRectRegion(0, w, 0, bh, regionId | RC_BORDER_REG, chf, srcReg);
|
||||
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++;
|
||||
}
|
||||
|
||||
|
@ -1745,27 +1745,27 @@ namespace DotRecast.Recast
|
|||
level = level >= 2 ? level - 2 : 0;
|
||||
sId = (sId + 1) & (NB_STACKS - 1);
|
||||
|
||||
// ctx->startTimer(RC_TIMER_DIVIDE_TO_LEVELS);
|
||||
// ctx->StartTimer(RC_TIMER_DIVIDE_TO_LEVELS);
|
||||
|
||||
if (sId == 0)
|
||||
{
|
||||
sortCellsByLevel(level, chf, srcReg, NB_STACKS, lvlStacks, 1);
|
||||
SortCellsByLevel(level, chf, srcReg, NB_STACKS, lvlStacks, 1);
|
||||
}
|
||||
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.
|
||||
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.
|
||||
for (int j = 0; j < lvlStacks[sId].Count; j += 3)
|
||||
|
@ -1775,34 +1775,34 @@ namespace DotRecast.Recast
|
|||
int i = lvlStacks[sId][j + 2];
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.stopTimer("REGIONS_FLOOD");
|
||||
ctx.StopTimer("REGIONS_FLOOD");
|
||||
}
|
||||
|
||||
// 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.
|
||||
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 (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.
|
||||
for (int i = 0; i < chf.spanCount; ++i)
|
||||
|
@ -1810,12 +1810,12 @@ namespace DotRecast.Recast
|
|||
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 h = chf.height;
|
||||
|
@ -1837,13 +1837,13 @@ namespace DotRecast.Recast
|
|||
int bw = Math.Min(w, borderSize);
|
||||
int bh = Math.Min(h, borderSize);
|
||||
// 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++;
|
||||
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++;
|
||||
paintRectRegion(0, w, 0, bh, id | RC_BORDER_REG, chf, srcReg);
|
||||
PaintRectRegion(0, w, 0, bh, id | RC_BORDER_REG, chf, srcReg);
|
||||
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++;
|
||||
}
|
||||
|
||||
|
@ -1956,13 +1956,13 @@ namespace DotRecast.Recast
|
|||
}
|
||||
}
|
||||
|
||||
ctx.startTimer("REGIONS_FILTER");
|
||||
ctx.StartTimer("REGIONS_FILTER");
|
||||
|
||||
// Merge monotone regions to layers and remove small regions.
|
||||
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.
|
||||
for (int i = 0; i < chf.spanCount; ++i)
|
||||
|
@ -1970,7 +1970,7 @@ namespace DotRecast.Recast
|
|||
chf.spans[i].reg = srcReg[i];
|
||||
}
|
||||
|
||||
ctx.stopTimer("REGIONS");
|
||||
ctx.StopTimer("REGIONS");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,61 +25,61 @@ namespace DotRecast.Recast
|
|||
{
|
||||
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.y = Math.Min(a.y, b[i + 1]);
|
||||
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.y = Math.Min(a.y, b.y);
|
||||
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.y = Math.Max(a.y, b[i + 1]);
|
||||
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.y = Math.Max(a.y, b.y);
|
||||
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 + 1] = @in[m + 1];
|
||||
@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 + 1] = @in[m + 1];
|
||||
@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 + 1] = @in[m + 1];
|
||||
@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.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.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.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[1] = v1[2] * v2[0] - v1[0] * v2[2];
|
||||
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[1] = v1.z * v2.x - v1.x * v2.z;
|
||||
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.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]));
|
||||
v[0] *= d;
|
||||
|
@ -133,7 +133,7 @@ namespace DotRecast.Recast
|
|||
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));
|
||||
v.x *= d;
|
||||
|
@ -141,17 +141,17 @@ namespace DotRecast.Recast
|
|||
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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
public class RecastVoxelization
|
||||
{
|
||||
public static Heightfield buildSolidHeightfield(InputGeomProvider geomProvider, RecastBuilderConfig builderCfg,
|
||||
public static Heightfield BuildSolidHeightfield(InputGeomProvider geomProvider, RecastBuilderConfig builderCfg,
|
||||
Telemetry ctx)
|
||||
{
|
||||
RecastConfig cfg = builderCfg.cfg;
|
||||
|
@ -41,9 +41,9 @@ namespace DotRecast.Recast
|
|||
// If your input data is multiple meshes, you can transform them here,
|
||||
// calculate
|
||||
// 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)
|
||||
{
|
||||
float[] tbmin = new float[2];
|
||||
|
@ -52,21 +52,21 @@ namespace DotRecast.Recast
|
|||
tbmin[1] = builderCfg.bmin.z;
|
||||
tbmax[0] = builderCfg.bmax.x;
|
||||
tbmax[1] = builderCfg.bmax.z;
|
||||
List<ChunkyTriMeshNode> nodes = geom.getChunksOverlappingRect(tbmin, tbmax);
|
||||
List<ChunkyTriMeshNode> nodes = geom.GetChunksOverlappingRect(tbmin, tbmax);
|
||||
foreach (ChunkyTriMeshNode node in nodes)
|
||||
{
|
||||
int[] tris = node.tris;
|
||||
int ntris = tris.Length / 3;
|
||||
int[] m_triareas = Recast.markWalkableTriangles(ctx, cfg.walkableSlopeAngle, verts, tris, ntris, cfg.walkableAreaMod);
|
||||
RecastRasterization.rasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.walkableClimb, ctx);
|
||||
int[] m_triareas = Recast.MarkWalkableTriangles(ctx, cfg.walkableSlopeAngle, verts, tris, ntris, cfg.walkableAreaMod);
|
||||
RecastRasterization.RasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.walkableClimb, ctx);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int[] tris = geom.getTris();
|
||||
int[] tris = geom.GetTris();
|
||||
int ntris = tris.Length / 3;
|
||||
int[] m_triareas = Recast.markWalkableTriangles(ctx, cfg.walkableSlopeAngle, verts, tris, ntris, cfg.walkableAreaMod);
|
||||
RecastRasterization.rasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.walkableClimb, ctx);
|
||||
int[] m_triareas = Recast.MarkWalkableTriangles(ctx, cfg.walkableSlopeAngle, verts, tris, ntris, cfg.walkableAreaMod);
|
||||
RecastRasterization.RasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.walkableClimb, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 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);
|
||||
}
|
||||
|
||||
public void stopTimer(string name)
|
||||
public void StopTimer(string name)
|
||||
{
|
||||
timerAccum
|
||||
.GetOrAdd(name, _ => new AtomicLong(0))
|
||||
.AddAndGet(FrequencyWatch.Ticks - timerStart.Value?[name].Read() ?? 0);
|
||||
}
|
||||
|
||||
public void warn(string @string)
|
||||
public void Warn(string @string)
|
||||
{
|
||||
Console.WriteLine(@string);
|
||||
}
|
||||
|
|
|
@ -64,9 +64,9 @@ public class AbstractCrowdTest
|
|||
protected List<CrowdAgent> agents;
|
||||
|
||||
[SetUp]
|
||||
public void setUp()
|
||||
public void SetUp()
|
||||
{
|
||||
nmd = new RecastTestMeshBuilder().getMeshData();
|
||||
nmd = new RecastTestMeshBuilder().GetMeshData();
|
||||
navmesh = new NavMesh(nmd, 6, 0);
|
||||
query = new NavMeshQuery(navmesh);
|
||||
CrowdConfig config = new CrowdConfig(0.6f);
|
||||
|
@ -76,29 +76,29 @@ public class AbstractCrowdTest
|
|||
option.adaptiveDivs = 5;
|
||||
option.adaptiveRings = 2;
|
||||
option.adaptiveDepth = 1;
|
||||
crowd.setObstacleAvoidanceParams(0, option);
|
||||
crowd.SetObstacleAvoidanceParams(0, option);
|
||||
option = new ObstacleAvoidanceParams();
|
||||
option.velBias = 0.5f;
|
||||
option.adaptiveDivs = 5;
|
||||
option.adaptiveRings = 2;
|
||||
option.adaptiveDepth = 2;
|
||||
crowd.setObstacleAvoidanceParams(1, option);
|
||||
crowd.SetObstacleAvoidanceParams(1, option);
|
||||
option = new ObstacleAvoidanceParams();
|
||||
option.velBias = 0.5f;
|
||||
option.adaptiveDivs = 7;
|
||||
option.adaptiveRings = 2;
|
||||
option.adaptiveDepth = 3;
|
||||
crowd.setObstacleAvoidanceParams(2, option);
|
||||
crowd.SetObstacleAvoidanceParams(2, option);
|
||||
option = new ObstacleAvoidanceParams();
|
||||
option.velBias = 0.5f;
|
||||
option.adaptiveDivs = 7;
|
||||
option.adaptiveRings = 3;
|
||||
option.adaptiveDepth = 3;
|
||||
crowd.setObstacleAvoidanceParams(3, option);
|
||||
crowd.SetObstacleAvoidanceParams(3, option);
|
||||
agents = new();
|
||||
}
|
||||
|
||||
protected CrowdAgentParams getAgentParams(int updateFlags, int obstacleAvoidanceType)
|
||||
protected CrowdAgentParams GetAgentParams(int updateFlags, int obstacleAvoidanceType)
|
||||
{
|
||||
CrowdAgentParams ap = new CrowdAgentParams();
|
||||
ap.radius = 0.6f;
|
||||
|
@ -113,9 +113,9 @@ public class AbstractCrowdTest
|
|||
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 j = 0; j < size; j++)
|
||||
|
@ -124,46 +124,46 @@ public class AbstractCrowdTest
|
|||
pos.x = startPos.x + i * distance;
|
||||
pos.y = startPos.y;
|
||||
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();
|
||||
QueryFilter filter = crowd.getFilter(0);
|
||||
Vector3f ext = crowd.GetQueryExtents();
|
||||
QueryFilter filter = crowd.GetFilter(0);
|
||||
if (adjust)
|
||||
{
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
Vector3f vel = calcVel(ag.npos, pos, ag.option.maxSpeed);
|
||||
crowd.requestMoveVelocity(ag, vel);
|
||||
Vector3f vel = CalcVel(ag.npos, pos, ag.option.maxSpeed);
|
||||
crowd.RequestMoveVelocity(ag, vel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Result<FindNearestPolyResult> nearest = query.findNearestPoly(pos, ext, filter);
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
Result<FindNearestPolyResult> nearest = query.FindNearestPoly(pos, ext, filter);
|
||||
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;
|
||||
vNormalize(ref vel);
|
||||
vel = vScale(vel, speed);
|
||||
VNormalize(ref vel);
|
||||
vel = VScale(vel, speed);
|
||||
return vel;
|
||||
}
|
||||
|
||||
protected void dumpActiveAgents(int i)
|
||||
protected void DumpActiveAgents(int i)
|
||||
{
|
||||
Console.WriteLine(crowd.getActiveAgents().Count);
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
Console.WriteLine(crowd.GetActiveAgents().Count);
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
Console.WriteLine(ag.state + ", " + ag.targetState);
|
||||
Console.WriteLine(ag.npos.x + ", " + ag.npos.y + ", " + ag.npos.z);
|
||||
|
|
|
@ -563,17 +563,17 @@ public class Crowd1Test : AbstractCrowdTest
|
|||
};
|
||||
|
||||
[Test]
|
||||
public void testAgent1Quality0TVTA()
|
||||
public void TestAgent1Quality0TVTA()
|
||||
{
|
||||
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
|
||||
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE;
|
||||
|
||||
addAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]);
|
||||
setMoveTarget(endPoss[0], false);
|
||||
AddAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]);
|
||||
SetMoveTarget(endPoss[0], false);
|
||||
for (int i = 0; i < EXPECTED_A1Q0TVTA.Length; i++)
|
||||
{
|
||||
crowd.update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
crowd.Update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
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));
|
||||
|
@ -586,17 +586,17 @@ public class Crowd1Test : AbstractCrowdTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testAgent1Quality0TVT()
|
||||
public void TestAgent1Quality0TVT()
|
||||
{
|
||||
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
|
||||
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO;
|
||||
|
||||
addAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]);
|
||||
setMoveTarget(endPoss[0], false);
|
||||
AddAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]);
|
||||
SetMoveTarget(endPoss[0], false);
|
||||
for (int i = 0; i < EXPECTED_A1Q0TVT.Length; i++)
|
||||
{
|
||||
crowd.update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
crowd.Update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
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));
|
||||
|
@ -609,16 +609,16 @@ public class Crowd1Test : AbstractCrowdTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testAgent1Quality0TV()
|
||||
public void TestAgent1Quality0TV()
|
||||
{
|
||||
int updateFlags = CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS;
|
||||
|
||||
addAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]);
|
||||
setMoveTarget(endPoss[0], false);
|
||||
AddAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]);
|
||||
SetMoveTarget(endPoss[0], false);
|
||||
for (int i = 0; i < EXPECTED_A1Q0TV.Length; i++)
|
||||
{
|
||||
crowd.update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
crowd.Update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
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));
|
||||
|
@ -631,16 +631,16 @@ public class Crowd1Test : AbstractCrowdTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testAgent1Quality0T()
|
||||
public void TestAgent1Quality0T()
|
||||
{
|
||||
int updateFlags = CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO;
|
||||
|
||||
addAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]);
|
||||
setMoveTarget(endPoss[0], false);
|
||||
AddAgentGrid(1, 0.4f, updateFlags, 0, startPoss[0]);
|
||||
SetMoveTarget(endPoss[0], false);
|
||||
for (int i = 0; i < EXPECTED_A1Q0T.Length; i++)
|
||||
{
|
||||
crowd.update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
crowd.Update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
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));
|
||||
|
@ -653,17 +653,17 @@ public class Crowd1Test : AbstractCrowdTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testAgent1Quality1TVTA()
|
||||
public void TestAgent1Quality1TVTA()
|
||||
{
|
||||
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
|
||||
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE;
|
||||
|
||||
addAgentGrid(1, 0.4f, updateFlags, 1, startPoss[0]);
|
||||
setMoveTarget(endPoss[0], false);
|
||||
AddAgentGrid(1, 0.4f, updateFlags, 1, startPoss[0]);
|
||||
SetMoveTarget(endPoss[0], false);
|
||||
for (int i = 0; i < EXPECTED_A1Q1TVTA.Length; i++)
|
||||
{
|
||||
crowd.update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
crowd.Update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
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));
|
||||
|
@ -676,17 +676,17 @@ public class Crowd1Test : AbstractCrowdTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testAgent1Quality2TVTA()
|
||||
public void TestAgent1Quality2TVTA()
|
||||
{
|
||||
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
|
||||
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE;
|
||||
|
||||
addAgentGrid(1, 0.4f, updateFlags, 2, startPoss[0]);
|
||||
setMoveTarget(endPoss[0], false);
|
||||
AddAgentGrid(1, 0.4f, updateFlags, 2, startPoss[0]);
|
||||
SetMoveTarget(endPoss[0], false);
|
||||
for (int i = 0; i < EXPECTED_A1Q2TVTA.Length; i++)
|
||||
{
|
||||
crowd.update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
crowd.Update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
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));
|
||||
|
@ -699,17 +699,17 @@ public class Crowd1Test : AbstractCrowdTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testAgent1Quality3TVTA()
|
||||
public void TestAgent1Quality3TVTA()
|
||||
{
|
||||
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
|
||||
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE;
|
||||
|
||||
addAgentGrid(1, 0.4f, updateFlags, 3, startPoss[0]);
|
||||
setMoveTarget(endPoss[0], false);
|
||||
AddAgentGrid(1, 0.4f, updateFlags, 3, startPoss[0]);
|
||||
SetMoveTarget(endPoss[0], false);
|
||||
for (int i = 0; i < EXPECTED_A1Q3TVTA.Length; i++)
|
||||
{
|
||||
crowd.update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
crowd.Update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
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));
|
||||
|
@ -722,18 +722,18 @@ public class Crowd1Test : AbstractCrowdTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testAgent1Quality3TVTAS()
|
||||
public void TestAgent1Quality3TVTAS()
|
||||
{
|
||||
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_SEPARATION;
|
||||
|
||||
addAgentGrid(1, 0.4f, updateFlags, 3, startPoss[0]);
|
||||
setMoveTarget(endPoss[0], false);
|
||||
AddAgentGrid(1, 0.4f, updateFlags, 3, startPoss[0]);
|
||||
SetMoveTarget(endPoss[0], false);
|
||||
for (int i = 0; i < EXPECTED_A1Q3TVTAS.Length; i++)
|
||||
{
|
||||
crowd.update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.getActiveAgents())
|
||||
crowd.Update(1 / 5f, null);
|
||||
foreach (CrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
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));
|
||||
|
|
|
@ -306,16 +306,16 @@ public class Crowd4Test : AbstractCrowdTest
|
|||
};
|
||||
|
||||
[Test]
|
||||
public void testAgent1Quality2TVTA()
|
||||
public void TestAgent1Quality2TVTA()
|
||||
{
|
||||
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
|
||||
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE;
|
||||
|
||||
addAgentGrid(2, 0.3f, updateFlags, 2, startPoss[0]);
|
||||
setMoveTarget(endPoss[0], false);
|
||||
AddAgentGrid(2, 0.3f, updateFlags, 2, startPoss[0]);
|
||||
SetMoveTarget(endPoss[0], false);
|
||||
for (int i = 0; i < EXPECTED_A1Q2TVTA.Length; i++)
|
||||
{
|
||||
crowd.update(1 / 5f, null);
|
||||
crowd.Update(1 / 5f, null);
|
||||
CrowdAgent ag = agents[2];
|
||||
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}");
|
||||
|
@ -327,17 +327,17 @@ public class Crowd4Test : AbstractCrowdTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testAgent1Quality2TVTAS()
|
||||
public void TestAgent1Quality2TVTAS()
|
||||
{
|
||||
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_SEPARATION;
|
||||
|
||||
addAgentGrid(2, 0.3f, updateFlags, 2, startPoss[0]);
|
||||
setMoveTarget(endPoss[0], false);
|
||||
AddAgentGrid(2, 0.3f, updateFlags, 2, startPoss[0]);
|
||||
SetMoveTarget(endPoss[0], false);
|
||||
for (int i = 0; i < EXPECTED_A1Q2TVTAS.Length; i++)
|
||||
{
|
||||
crowd.update(1 / 5f, null);
|
||||
crowd.Update(1 / 5f, null);
|
||||
CrowdAgent ag = agents[2];
|
||||
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}");
|
||||
|
@ -349,15 +349,15 @@ public class Crowd4Test : AbstractCrowdTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testAgent1Quality2T()
|
||||
public void TestAgent1Quality2T()
|
||||
{
|
||||
int updateFlags = CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO;
|
||||
|
||||
addAgentGrid(2, 0.3f, updateFlags, 2, startPoss[0]);
|
||||
setMoveTarget(endPoss[0], false);
|
||||
AddAgentGrid(2, 0.3f, updateFlags, 2, startPoss[0]);
|
||||
SetMoveTarget(endPoss[0], false);
|
||||
for (int i = 0; i < EXPECTED_A1Q2T.Length; i++)
|
||||
{
|
||||
crowd.update(1 / 5f, null);
|
||||
crowd.Update(1 / 5f, null);
|
||||
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.y, Is.EqualTo(EXPECTED_A1Q2T[i][1]).Within(0.00001f), $"{i} - {ag.npos.y} {EXPECTED_A1Q2T[i][1]}");
|
||||
|
|
|
@ -97,19 +97,19 @@ public class Crowd4VelocityTest : AbstractCrowdTest
|
|||
};
|
||||
|
||||
[Test]
|
||||
public void testAgent1Quality3TVTA()
|
||||
public void TestAgent1Quality3TVTA()
|
||||
{
|
||||
int updateFlags = CrowdAgentParams.DT_CROWD_ANTICIPATE_TURNS | CrowdAgentParams.DT_CROWD_OPTIMIZE_VIS
|
||||
| CrowdAgentParams.DT_CROWD_OPTIMIZE_TOPO | CrowdAgentParams.DT_CROWD_OBSTACLE_AVOIDANCE;
|
||||
|
||||
addAgentGrid(2, 0.3f, updateFlags, 3, endPoss[0]);
|
||||
setMoveTarget(endPoss[4], false);
|
||||
AddAgentGrid(2, 0.3f, updateFlags, 3, endPoss[0]);
|
||||
SetMoveTarget(endPoss[4], false);
|
||||
for (int i = 0; i < EXPECTED_A1Q3TVTA.Length; i++)
|
||||
{
|
||||
crowd.update(1 / 5f, null);
|
||||
crowd.Update(1 / 5f, null);
|
||||
if (i == 20)
|
||||
{
|
||||
setMoveTarget(startPoss[2], true);
|
||||
SetMoveTarget(startPoss[2], true);
|
||||
}
|
||||
|
||||
CrowdAgent ag = agents[1];
|
||||
|
|
|
@ -31,13 +31,13 @@ public class PathCorridorTest
|
|||
private readonly QueryFilter filter = new DefaultQueryFilter();
|
||||
|
||||
[SetUp]
|
||||
public void setUp()
|
||||
public void SetUp()
|
||||
{
|
||||
corridor.reset(0, Vector3f.Of(10, 20, 30));
|
||||
corridor.Reset(0, Vector3f.Of(10, 20, 30));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void shouldKeepOriginalPathInFindCornersWhenNothingCanBePruned()
|
||||
public void ShouldKeepOriginalPathInFindCornersWhenNothingCanBePruned()
|
||||
{
|
||||
List<StraightPathItem> straightPath = new();
|
||||
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));
|
||||
Result<List<StraightPathItem>> result = Results.Success(straightPath);
|
||||
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<List<long>>(),
|
||||
It.IsAny<int>(),
|
||||
It.IsAny<int>())
|
||||
).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, Is.EqualTo(straightPath));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void shouldPrunePathInFindCorners()
|
||||
public void ShouldPrunePathInFindCorners()
|
||||
{
|
||||
List<StraightPathItem> straightPath = new();
|
||||
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);
|
||||
|
||||
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<List<long>>(),
|
||||
|
@ -78,7 +78,7 @@ public class PathCorridorTest
|
|||
It.IsAny<int>())
|
||||
).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, Is.EqualTo(new List<StraightPathItem> { straightPath[2], straightPath[3] }));
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public class RecastTestMeshBuilder
|
|||
public const float m_detailSampleDist = 6.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,
|
||||
m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist,
|
||||
m_detailSampleMaxError)
|
||||
|
@ -54,16 +54,16 @@ public class RecastTestMeshBuilder
|
|||
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_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();
|
||||
RecastBuilderResult rcResult = rcBuilder.build(m_geom, bcfg);
|
||||
PolyMesh m_pmesh = rcResult.getMesh();
|
||||
RecastBuilderResult rcResult = rcBuilder.Build(m_geom, bcfg);
|
||||
PolyMesh m_pmesh = rcResult.GetMesh();
|
||||
for (int i = 0; i < m_pmesh.npolys; ++i)
|
||||
{
|
||||
m_pmesh.flags[i] = 1;
|
||||
}
|
||||
|
||||
PolyMeshDetail m_dmesh = rcResult.getMeshDetail();
|
||||
PolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
|
||||
NavMeshDataCreateParams option = new NavMeshDataCreateParams();
|
||||
option.verts = m_pmesh.verts;
|
||||
option.vertCount = m_pmesh.nverts;
|
||||
|
@ -104,10 +104,10 @@ public class RecastTestMeshBuilder
|
|||
option.offMeshConUserID = new int[1];
|
||||
option.offMeshConUserID[0] = 0x4567;
|
||||
option.offMeshConCount = 1;
|
||||
meshData = NavMeshBuilder.createNavMeshData(option);
|
||||
meshData = NavMeshBuilder.CreateNavMeshData(option);
|
||||
}
|
||||
|
||||
public MeshData getMeshData()
|
||||
public MeshData GetMeshData()
|
||||
{
|
||||
return meshData;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ public class DynamicNavMeshTest
|
|||
|
||||
|
||||
[Test]
|
||||
public void e2eTest()
|
||||
public void E2eTest()
|
||||
{
|
||||
byte[] bytes = Loader.ToBytes("test_tiles.voxels");
|
||||
using var ms = new MemoryStream(bytes);
|
||||
|
@ -27,51 +27,51 @@ public class DynamicNavMeshTest
|
|||
|
||||
// load voxels from file
|
||||
VoxelFileReader reader = new VoxelFileReader();
|
||||
VoxelFile f = reader.read(bis);
|
||||
VoxelFile f = reader.Read(bis);
|
||||
// create dynamic navmesh
|
||||
DynamicNavMesh mesh = new DynamicNavMesh(f);
|
||||
// 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
|
||||
bool _ = future.Result;
|
||||
// create new query
|
||||
NavMeshQuery query = new NavMeshQuery(mesh.navMesh());
|
||||
NavMeshQuery query = new NavMeshQuery(mesh.NavMesh());
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
// find path
|
||||
FindNearestPolyResult start = query.findNearestPoly(START_POS, EXTENT, filter).result;
|
||||
FindNearestPolyResult end = query.findNearestPoly(END_POS, EXTENT, filter).result;
|
||||
List<long> path = query.findPath(start.getNearestRef(), end.getNearestRef(), start.getNearestPos(),
|
||||
end.getNearestPos(), filter, NavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue).result;
|
||||
FindNearestPolyResult start = query.FindNearestPoly(START_POS, EXTENT, filter).result;
|
||||
FindNearestPolyResult end = query.FindNearestPoly(END_POS, EXTENT, filter).result;
|
||||
List<long> path = query.FindPath(start.GetNearestRef(), end.GetNearestRef(), start.GetNearestPos(),
|
||||
end.GetNearestPos(), filter, NavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue).result;
|
||||
// check path length without any obstacles
|
||||
Assert.That(path.Count, Is.EqualTo(16));
|
||||
// place obstacle
|
||||
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
|
||||
future = mesh.update(Task.Factory);
|
||||
future = mesh.Update(Task.Factory);
|
||||
// wait for update to complete
|
||||
_ = future.Result;
|
||||
// create new query
|
||||
query = new NavMeshQuery(mesh.navMesh());
|
||||
query = new NavMeshQuery(mesh.NavMesh());
|
||||
// find path again
|
||||
start = query.findNearestPoly(START_POS, EXTENT, filter).result;
|
||||
end = query.findNearestPoly(END_POS, EXTENT, filter).result;
|
||||
path = query.findPath(start.getNearestRef(), end.getNearestRef(), start.getNearestPos(), end.getNearestPos(), filter,
|
||||
start = query.FindNearestPoly(START_POS, EXTENT, filter).result;
|
||||
end = query.FindNearestPoly(END_POS, EXTENT, filter).result;
|
||||
path = query.FindPath(start.GetNearestRef(), end.GetNearestRef(), start.GetNearestPos(), end.GetNearestPos(), filter,
|
||||
NavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue).result;
|
||||
// check path length with obstacles
|
||||
Assert.That(path.Count, Is.EqualTo(19));
|
||||
// remove obstacle
|
||||
mesh.removeCollider(colliderId);
|
||||
mesh.RemoveCollider(colliderId);
|
||||
// update navmesh asynchronously
|
||||
future = mesh.update(Task.Factory);
|
||||
future = mesh.Update(Task.Factory);
|
||||
// wait for update to complete
|
||||
_ = future.Result;
|
||||
// create new query
|
||||
query = new NavMeshQuery(mesh.navMesh());
|
||||
query = new NavMeshQuery(mesh.NavMesh());
|
||||
// find path one more time
|
||||
start = query.findNearestPoly(START_POS, EXTENT, filter).result;
|
||||
end = query.findNearestPoly(END_POS, EXTENT, filter).result;
|
||||
path = query.findPath(start.getNearestRef(), end.getNearestRef(), start.getNearestPos(), end.getNearestPos(), filter,
|
||||
start = query.FindNearestPoly(START_POS, EXTENT, filter).result;
|
||||
end = query.FindNearestPoly(END_POS, EXTENT, filter).result;
|
||||
path = query.FindPath(start.GetNearestRef(), end.GetNearestRef(), start.GetNearestPos(), end.GetNearestPos(), filter,
|
||||
NavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue).result;
|
||||
// path length should be back to the initial value
|
||||
Assert.That(path.Count, Is.EqualTo(16));
|
||||
|
|
|
@ -27,14 +27,14 @@ namespace DotRecast.Detour.Dynamic.Test.Io;
|
|||
public class VoxelFileReaderTest
|
||||
{
|
||||
[Test]
|
||||
public void shouldReadSingleTileFile()
|
||||
public void ShouldReadSingleTileFile()
|
||||
{
|
||||
byte[] bytes = Loader.ToBytes("test.voxels");
|
||||
using var ms = new MemoryStream(bytes);
|
||||
using var bis = new BinaryReader(ms);
|
||||
|
||||
VoxelFileReader reader = new VoxelFileReader();
|
||||
VoxelFile f = reader.read(bis);
|
||||
VoxelFile f = reader.Read(bis);
|
||||
Assert.That(f.useTiles, Is.False);
|
||||
Assert.That(f.bounds, Is.EqualTo(new float[] { -100.0f, 0f, -100f, 100f, 5f, 100f }));
|
||||
Assert.That(f.cellSize, Is.EqualTo(0.25f));
|
||||
|
@ -53,14 +53,14 @@ public class VoxelFileReaderTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void shouldReadMultiTileFile()
|
||||
public void ShouldReadMultiTileFile()
|
||||
{
|
||||
byte[] bytes = Loader.ToBytes("test_tiles.voxels");
|
||||
using var ms = new MemoryStream(bytes);
|
||||
using var bis = new BinaryReader(ms);
|
||||
|
||||
VoxelFileReader reader = new VoxelFileReader();
|
||||
VoxelFile f = reader.read(bis);
|
||||
VoxelFile f = reader.Read(bis);
|
||||
|
||||
Assert.That(f.useTiles, Is.True);
|
||||
Assert.That(f.bounds, Is.EqualTo(new float[] { -100.0f, 0f, -100f, 100f, 5f, 100f }));
|
||||
|
|
|
@ -28,13 +28,13 @@ public class VoxelFileReaderWriterTest
|
|||
{
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void shouldReadSingleTileFile(bool compression)
|
||||
public void ShouldReadSingleTileFile(bool compression)
|
||||
{
|
||||
byte[] bytes = Loader.ToBytes("test.voxels");
|
||||
using var ms = new MemoryStream(bytes);
|
||||
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.bounds, Is.EqualTo(new[] { -100.0f, 0f, -100f, 100f, 5f, 100f }));
|
||||
Assert.That(f.cellSize, Is.EqualTo(0.25f));
|
||||
|
@ -56,13 +56,13 @@ public class VoxelFileReaderWriterTest
|
|||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void shouldReadMultiTileFile(bool compression)
|
||||
public void ShouldReadMultiTileFile(bool compression)
|
||||
{
|
||||
byte[] bytes = Loader.ToBytes("test_tiles.voxels");
|
||||
using var ms = new MemoryStream(bytes);
|
||||
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.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)));
|
||||
}
|
||||
|
||||
private VoxelFile readWriteRead(BinaryReader bis, bool compression)
|
||||
private VoxelFile ReadWriteRead(BinaryReader bis, bool compression)
|
||||
{
|
||||
VoxelFileReader reader = new VoxelFileReader();
|
||||
VoxelFile f = reader.read(bis);
|
||||
VoxelFile f = reader.Read(bis);
|
||||
|
||||
using var msOut = new MemoryStream();
|
||||
using var bwOut = new BinaryWriter(msOut);
|
||||
VoxelFileWriter writer = new VoxelFileWriter();
|
||||
writer.write(bwOut, f, compression);
|
||||
writer.Write(bwOut, f, compression);
|
||||
|
||||
using var msIn = new MemoryStream(msOut.ToArray());
|
||||
using var brIn = new BinaryReader(msIn);
|
||||
return reader.read(brIn);
|
||||
return reader.Read(brIn);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public class VoxelQueryTest
|
|||
|
||||
|
||||
[Test]
|
||||
public void shouldTraverseTiles()
|
||||
public void ShouldTraverseTiles()
|
||||
{
|
||||
var hfProvider = new Mock<Func<int, int, Heightfield>>();
|
||||
|
||||
|
@ -59,7 +59,7 @@ public class VoxelQueryTest
|
|||
Vector3f end = Vector3f.Of(320, 10, 57);
|
||||
|
||||
// When
|
||||
query.raycast(start, end);
|
||||
query.Raycast(start, end);
|
||||
// Then
|
||||
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 }));
|
||||
|
@ -67,29 +67,29 @@ public class VoxelQueryTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void shouldHandleRaycastWithoutObstacles()
|
||||
public void ShouldHandleRaycastWithoutObstacles()
|
||||
{
|
||||
DynamicNavMesh mesh = createDynaMesh();
|
||||
VoxelQuery query = mesh.voxelQuery();
|
||||
DynamicNavMesh mesh = CreateDynaMesh();
|
||||
VoxelQuery query = mesh.VoxelQuery();
|
||||
Vector3f start = Vector3f.Of(7.4f, 0.5f, -64.8f);
|
||||
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);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void shouldHandleRaycastWithObstacles()
|
||||
public void ShouldHandleRaycastWithObstacles()
|
||||
{
|
||||
DynamicNavMesh mesh = createDynaMesh();
|
||||
VoxelQuery query = mesh.voxelQuery();
|
||||
DynamicNavMesh mesh = CreateDynaMesh();
|
||||
VoxelQuery query = mesh.VoxelQuery();
|
||||
Vector3f start = Vector3f.Of(32.3f, 0.5f, 47.9f);
|
||||
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.Value, Is.EqualTo(0.5263836f).Within(1e-7f));
|
||||
}
|
||||
|
||||
private DynamicNavMesh createDynaMesh()
|
||||
private DynamicNavMesh CreateDynaMesh()
|
||||
{
|
||||
var bytes = Loader.ToBytes("test_tiles.voxels");
|
||||
using var ms = new MemoryStream(bytes);
|
||||
|
@ -97,11 +97,11 @@ public class VoxelQueryTest
|
|||
|
||||
// load voxels from file
|
||||
VoxelFileReader reader = new VoxelFileReader();
|
||||
VoxelFile f = reader.read(bis);
|
||||
VoxelFile f = reader.Read(bis);
|
||||
// create dynamic navmesh
|
||||
var mesh = new DynamicNavMesh(f);
|
||||
// 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
|
||||
var _ = future.Result;
|
||||
return mesh;
|
||||
|
|
|
@ -31,53 +31,53 @@ namespace DotRecast.Detour.Extras.Test.Unity.Astar;
|
|||
public class UnityAStarPathfindingImporterTest
|
||||
{
|
||||
[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 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.result.Count, Is.EqualTo(57));
|
||||
saveMesh(mesh, "v4_0_6");
|
||||
SaveMesh(mesh, "v4_0_6");
|
||||
}
|
||||
|
||||
[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 endPos = Vector3f.Of(16.81f, -2.37f, 25.52f);
|
||||
Result<List<long>> path = findPath(mesh, startPos, endPos);
|
||||
Assert.That(path.status.isSuccess(), Is.True);
|
||||
Result<List<long>> path = FindPath(mesh, startPos, endPos);
|
||||
Assert.That(path.status.IsSuccess(), Is.True);
|
||||
Assert.That(path.result.Count, Is.EqualTo(15));
|
||||
saveMesh(mesh, "v4_1_16");
|
||||
SaveMesh(mesh, "v4_1_16");
|
||||
}
|
||||
|
||||
[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);
|
||||
|
||||
int[] tilePos = mesh.calcTileLoc(position);
|
||||
long tileRef = mesh.getTileRefAt(tilePos[0], tilePos[1], 0);
|
||||
MeshTile tile = mesh.getTileByRef(tileRef);
|
||||
int[] tilePos = mesh.CalcTileLoc(position);
|
||||
long tileRef = mesh.GetTileRefAt(tilePos[0], tilePos[1], 0);
|
||||
MeshTile tile = mesh.GetTileByRef(tileRef);
|
||||
MeshData data = tile.data;
|
||||
BVNode[] bvNodes = data.bvTree;
|
||||
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
|
||||
// important aspect in that test: BV result must equals result without BV
|
||||
// if poly not found or found other poly - tile bounds is wrong!
|
||||
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);
|
||||
using var fs = new FileStream(filepath, FileMode.Open, FileAccess.Read);
|
||||
|
@ -85,21 +85,21 @@ public class UnityAStarPathfindingImporterTest
|
|||
// Import the graphs
|
||||
UnityAStarPathfindingImporter importer = new UnityAStarPathfindingImporter();
|
||||
|
||||
NavMesh[] meshes = importer.load(fs);
|
||||
NavMesh[] meshes = importer.Load(fs);
|
||||
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
|
||||
NavMeshQuery query = new NavMeshQuery(mesh);
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
|
||||
FindNearestPolyResult[] polys = getNearestPolys(mesh, startPos, endPos);
|
||||
return query.findPath(polys[0].getNearestRef(), polys[1].getNearestRef(), startPos, endPos, filter);
|
||||
FindNearestPolyResult[] polys = GetNearestPolys(mesh, startPos, endPos);
|
||||
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);
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
|
@ -109,21 +109,21 @@ public class UnityAStarPathfindingImporterTest
|
|||
for (int i = 0; i < results.Length; 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.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;
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private void saveMesh(NavMesh mesh, string filePostfix)
|
||||
private void SaveMesh(NavMesh mesh, string filePostfix)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
@ -135,6 +135,6 @@ public class UnityAStarPathfindingImporterTest
|
|||
string filepath = Path.Combine("test-output", filename);
|
||||
using var fs = new FileStream(filename, FileMode.Create);
|
||||
using var os = new BinaryWriter(fs);
|
||||
writer.write(os, mesh, ByteOrder.LITTLE_ENDIAN, true);
|
||||
writer.Write(os, mesh, ByteOrder.LITTLE_ENDIAN, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,14 +56,14 @@ public abstract class AbstractDetourTest
|
|||
protected NavMesh navmesh;
|
||||
|
||||
[SetUp]
|
||||
public void setUp()
|
||||
public void SetUp()
|
||||
{
|
||||
navmesh = createNavMesh();
|
||||
navmesh = CreateNavMesh();
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -24,21 +24,21 @@ namespace DotRecast.Detour.Test;
|
|||
public class ConvexConvexIntersectionTest
|
||||
{
|
||||
[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[] 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, Is.EqualTo(p));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void shouldHandleIntersection()
|
||||
public void ShouldHandleIntersection()
|
||||
{
|
||||
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[] intersection = ConvexConvexIntersection.intersect(p, q);
|
||||
float[] intersection = ConvexConvexIntersection.Intersect(p, q);
|
||||
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 }));
|
||||
}
|
||||
|
|
|
@ -46,23 +46,23 @@ public class FindDistanceToWallTest : AbstractDetourTest
|
|||
};
|
||||
|
||||
[Test]
|
||||
public void testFindDistanceToWall()
|
||||
public void TestFindDistanceToWall()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
for (int i = 0; i < startRefs.Length; 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;
|
||||
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().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().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().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().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().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().z, Is.EqualTo(HIT_NORMAL[i].z).Within(0.001f));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,17 +52,17 @@ public class FindLocalNeighbourhoodTest : AbstractDetourTest
|
|||
};
|
||||
|
||||
[Test]
|
||||
public void testFindNearestPoly()
|
||||
public void TestFindNearestPoly()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
for (int i = 0; i < startRefs.Length; i++)
|
||||
{
|
||||
Vector3f startPos = startPoss[i];
|
||||
Result<FindLocalNeighbourhoodResult> poly = query.findLocalNeighbourhood(startRefs[i], startPos, 3.5f, filter);
|
||||
Assert.That(poly.result.getRefs().Count, Is.EqualTo(REFS[i].Length));
|
||||
Result<FindLocalNeighbourhoodResult> poly = query.FindLocalNeighbourhood(startRefs[i], startPos, 3.5f, filter);
|
||||
Assert.That(poly.result.GetRefs().Count, Is.EqualTo(REFS[i].Length));
|
||||
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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,31 +35,31 @@ public class FindNearestPolyTest : AbstractDetourTest
|
|||
};
|
||||
|
||||
[Test]
|
||||
public void testFindNearestPoly()
|
||||
public void TestFindNearestPoly()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
Vector3f extents = Vector3f.Of(2, 4, 2);
|
||||
for (int i = 0; i < startRefs.Length; 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.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++)
|
||||
{
|
||||
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 bool passFilter(long refs, MeshTile tile, Poly poly)
|
||||
public bool PassFilter(long refs, MeshTile tile, Poly poly)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return 0;
|
||||
|
@ -67,19 +67,19 @@ public class FindNearestPolyTest : AbstractDetourTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void shouldReturnStartPosWhenNoPolyIsValid()
|
||||
public void ShouldReturnStartPosWhenNoPolyIsValid()
|
||||
{
|
||||
var filter = new EmptyQueryFilter();
|
||||
Vector3f extents = Vector3f.Of(2, 4, 2);
|
||||
for (int i = 0; i < startRefs.Length; 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.result.getNearestRef(), Is.EqualTo(0L));
|
||||
Assert.That(poly.result.GetNearestRef(), Is.EqualTo(0L));
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ public class FindPathTest : AbstractDetourTest
|
|||
};
|
||||
|
||||
[Test]
|
||||
public void testFindPath()
|
||||
public void TestFindPath()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
for (int i = 0; i < startRefs.Length; i++)
|
||||
|
@ -138,7 +138,7 @@ public class FindPathTest : AbstractDetourTest
|
|||
long endRef = endRefs[i];
|
||||
Vector3f startPos = startPoss[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.result.Count, Is.EqualTo(RESULTS[i].Length));
|
||||
for (int j = 0; j < RESULTS[i].Length; j++)
|
||||
|
@ -149,7 +149,7 @@ public class FindPathTest : AbstractDetourTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testFindPathSliced()
|
||||
public void TestFindPathSliced()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
for (int i = 0; i < startRefs.Length; i++)
|
||||
|
@ -158,15 +158,15 @@ public class FindPathTest : AbstractDetourTest
|
|||
long endRef = endRefs[i];
|
||||
var startPos = startPoss[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;
|
||||
while (status == Status.IN_PROGRESS)
|
||||
{
|
||||
Result<int> res = query.updateSlicedFindPath(10);
|
||||
Result<int> res = query.UpdateSlicedFindPath(10);
|
||||
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.result.Count, Is.EqualTo(RESULTS[i].Length));
|
||||
for (int j = 0; j < RESULTS[i].Length; j++)
|
||||
|
@ -177,7 +177,7 @@ public class FindPathTest : AbstractDetourTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testFindPathStraight()
|
||||
public void TestFindPathStraight()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
for (int i = 0; i < STRAIGHT_PATHS.Length; i++)
|
||||
|
@ -187,8 +187,8 @@ public class FindPathTest : AbstractDetourTest
|
|||
long endRef = endRefs[i];
|
||||
var startPos = startPoss[i];
|
||||
var endPos = endPoss[i];
|
||||
Result<List<long>> path = query.findPath(startRef, endRef, startPos, endPos, filter);
|
||||
Result<List<StraightPathItem>> result = query.findStraightPath(startPos, endPos, path.result,
|
||||
Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter);
|
||||
Result<List<StraightPathItem>> result = query.FindStraightPath(startPos, endPos, path.result,
|
||||
int.MaxValue, 0);
|
||||
List<StraightPathItem> straightPath = result.result;
|
||||
Assert.That(straightPath.Count, Is.EqualTo(STRAIGHT_PATHS[i].Length));
|
||||
|
|
|
@ -99,26 +99,26 @@ public class FindPolysAroundCircleTest : AbstractDetourTest
|
|||
};
|
||||
|
||||
[Test]
|
||||
public void testFindPolysAroundCircle()
|
||||
public void TestFindPolysAroundCircle()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
for (int i = 0; i < startRefs.Length; i++)
|
||||
{
|
||||
long startRef = startRefs[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);
|
||||
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++)
|
||||
{
|
||||
bool found = false;
|
||||
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.getCosts()[w], Is.EqualTo(COSTS[i][v]).Within(0.01f));
|
||||
Assert.That(polys.GetParentRefs()[w], Is.EqualTo(PARENT_REFS[i][v]));
|
||||
Assert.That(polys.GetCosts()[w], Is.EqualTo(COSTS[i][v]).Within(0.01f));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,24 +126,24 @@ public class FindPolysAroundShapeTest : AbstractDetourTest
|
|||
};
|
||||
|
||||
[Test]
|
||||
public void testFindPolysAroundShape()
|
||||
public void TestFindPolysAroundShape()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
for (int i = 0; i < startRefs.Length; i++)
|
||||
{
|
||||
long startRef = startRefs[i];
|
||||
Vector3f startPos = startPoss[i];
|
||||
Result<FindPolysAroundResult> polys = query.findPolysAroundShape(startRef, getQueryPoly(startPos, endPoss[i]), filter);
|
||||
Assert.That(polys.result.getRefs().Count, Is.EqualTo(REFS[i].Length));
|
||||
Result<FindPolysAroundResult> polys = query.FindPolysAroundShape(startRef, GetQueryPoly(startPos, endPoss[i]), filter);
|
||||
Assert.That(polys.result.GetRefs().Count, Is.EqualTo(REFS[i].Length));
|
||||
for (int v = 0; v < REFS[i].Length; v++)
|
||||
{
|
||||
bool found = false;
|
||||
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.getCosts()[w], Is.EqualTo(COSTS[i][v]).Within(0.01f));
|
||||
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));
|
||||
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 nz = -(m_epos.x - m_spos.x) * 0.25f;
|
||||
|
|
|
@ -75,26 +75,26 @@ public class GetPolyWallSegmentsTest : AbstractDetourTest
|
|||
};
|
||||
|
||||
[Test]
|
||||
public void testFindDistanceToWall()
|
||||
public void TestFindDistanceToWall()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
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;
|
||||
Assert.That(segments.countSegmentVerts(), Is.EqualTo(VERTICES[i].Length / 6));
|
||||
Assert.That(segments.countSegmentRefs(), Is.EqualTo(REFS[i].Length));
|
||||
Assert.That(segments.CountSegmentVerts(), Is.EqualTo(VERTICES[i].Length / 6));
|
||||
Assert.That(segments.CountSegmentRefs(), Is.EqualTo(REFS[i].Length));
|
||||
for (int v = 0; v < VERTICES[i].Length / 6; v++)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
Assert.That(segments.getSegmentRef(v), Is.EqualTo(REFS[i][v]));
|
||||
Assert.That(segments.GetSegmentRef(v), Is.EqualTo(REFS[i][v]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,48 +30,48 @@ public class MeshDataReaderWriterTest
|
|||
private MeshData meshData;
|
||||
|
||||
[SetUp]
|
||||
public void setUp()
|
||||
public void SetUp()
|
||||
{
|
||||
RecastTestMeshBuilder rcBuilder = new RecastTestMeshBuilder();
|
||||
meshData = rcBuilder.getMeshData();
|
||||
meshData = rcBuilder.GetMeshData();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testCCompatibility()
|
||||
public void TestCCompatibility()
|
||||
{
|
||||
test(true, ByteOrder.BIG_ENDIAN);
|
||||
Test(true, ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testCompact()
|
||||
public void TestCompact()
|
||||
{
|
||||
test(false, ByteOrder.BIG_ENDIAN);
|
||||
Test(false, ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testCCompatibilityLE()
|
||||
public void TestCCompatibilityLE()
|
||||
{
|
||||
test(true, ByteOrder.LITTLE_ENDIAN);
|
||||
Test(true, ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
[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 bwos = new BinaryWriter(ms);
|
||||
|
||||
MeshDataWriter writer = new MeshDataWriter();
|
||||
writer.write(bwos, meshData, order, cCompatibility);
|
||||
writer.Write(bwos, meshData, order, cCompatibility);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
using var bris = new BinaryReader(ms);
|
||||
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.polyCount, Is.EqualTo(meshData.header.polyCount));
|
||||
|
|
|
@ -30,86 +30,86 @@ public class MeshSetReaderTest
|
|||
private readonly MeshSetReader reader = new MeshSetReader();
|
||||
|
||||
[Test]
|
||||
public void testNavmesh()
|
||||
public void TestNavmesh()
|
||||
{
|
||||
byte[] @is = Loader.ToBytes("all_tiles_navmesh.bin");
|
||||
using var ms = new MemoryStream(@is);
|
||||
using var bris = new BinaryReader(ms);
|
||||
NavMesh mesh = reader.read(bris, 6);
|
||||
Assert.That(mesh.getMaxTiles(), Is.EqualTo(128));
|
||||
Assert.That(mesh.getParams().maxPolys, Is.EqualTo(0x8000));
|
||||
Assert.That(mesh.getParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
|
||||
List<MeshTile> tiles = mesh.getTilesAt(4, 7);
|
||||
NavMesh mesh = reader.Read(bris, 6);
|
||||
Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128));
|
||||
Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000));
|
||||
Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
|
||||
List<MeshTile> tiles = mesh.GetTilesAt(4, 7);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(7));
|
||||
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[0].data.polys.Length, Is.EqualTo(7));
|
||||
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[0].data.polys.Length, Is.EqualTo(1));
|
||||
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[0].data.polys.Length, Is.EqualTo(8));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(24 * 3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testDungeon()
|
||||
public void TestDungeon()
|
||||
{
|
||||
byte[] @is = Loader.ToBytes("dungeon_all_tiles_navmesh.bin");
|
||||
using var ms = new MemoryStream(@is);
|
||||
using var bris = new BinaryReader(ms);
|
||||
|
||||
NavMesh mesh = reader.read(bris, 6);
|
||||
Assert.That(mesh.getMaxTiles(), Is.EqualTo(128));
|
||||
Assert.That(mesh.getParams().maxPolys, Is.EqualTo(0x8000));
|
||||
Assert.That(mesh.getParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
|
||||
List<MeshTile> tiles = mesh.getTilesAt(6, 9);
|
||||
NavMesh mesh = reader.Read(bris, 6);
|
||||
Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128));
|
||||
Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000));
|
||||
Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
|
||||
List<MeshTile> tiles = mesh.GetTilesAt(6, 9);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
|
||||
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[0].data.polys.Length, Is.EqualTo(2));
|
||||
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[0].data.polys.Length, Is.EqualTo(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[0].data.polys.Length, Is.EqualTo(5));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testDungeon32Bit()
|
||||
public void TestDungeon32Bit()
|
||||
{
|
||||
byte[] @is = Loader.ToBytes("dungeon_all_tiles_navmesh_32bit.bin");
|
||||
using var ms = new MemoryStream(@is);
|
||||
using var bris = new BinaryReader(ms);
|
||||
|
||||
NavMesh mesh = reader.read32Bit(bris, 6);
|
||||
Assert.That(mesh.getMaxTiles(), Is.EqualTo(128));
|
||||
Assert.That(mesh.getParams().maxPolys, Is.EqualTo(0x8000));
|
||||
Assert.That(mesh.getParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
|
||||
List<MeshTile> tiles = mesh.getTilesAt(6, 9);
|
||||
NavMesh mesh = reader.Read32Bit(bris, 6);
|
||||
Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128));
|
||||
Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000));
|
||||
Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
|
||||
List<MeshTile> tiles = mesh.GetTilesAt(6, 9);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
|
||||
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[0].data.polys.Length, Is.EqualTo(2));
|
||||
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[0].data.polys.Length, Is.EqualTo(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[0].data.polys.Length, Is.EqualTo(5));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3));
|
||||
|
|
|
@ -52,14 +52,14 @@ public class MeshSetReaderWriterTest
|
|||
private const int m_maxPolysPerTile = 0x8000;
|
||||
|
||||
[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();
|
||||
header.magic = NavMeshSetHeader.NAVMESHSET_MAGIC;
|
||||
header.version = NavMeshSetHeader.NAVMESHSET_VERSION;
|
||||
header.option.orig = geom.getMeshBoundsMin();
|
||||
header.option.orig = geom.GetMeshBoundsMin();
|
||||
header.option.tileWidth = m_tileSize * m_cellSize;
|
||||
header.option.tileHeight = m_tileSize * m_cellSize;
|
||||
header.option.maxTiles = m_maxTiles;
|
||||
|
@ -67,9 +67,9 @@ public class MeshSetReaderWriterTest
|
|||
header.numTiles = 0;
|
||||
NavMesh mesh = new NavMesh(header.option, 6);
|
||||
|
||||
Vector3f bmin = geom.getMeshBoundsMin();
|
||||
Vector3f bmax = geom.getMeshBoundsMax();
|
||||
int[] twh = DotRecast.Recast.Recast.calcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize);
|
||||
Vector3f bmin = geom.GetMeshBoundsMin();
|
||||
Vector3f bmax = geom.GetMeshBoundsMax();
|
||||
int[] twh = DotRecast.Recast.Recast.CalcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize);
|
||||
int tw = twh[0];
|
||||
int th = twh[1];
|
||||
for (int y = 0; y < th; ++y)
|
||||
|
@ -77,44 +77,44 @@ public class MeshSetReaderWriterTest
|
|||
for (int x = 0; x < tw; ++x)
|
||||
{
|
||||
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_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true, m_detailSampleDist,
|
||||
m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
|
||||
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, bmin, bmax, x, y);
|
||||
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)
|
||||
{
|
||||
mesh.removeTile(mesh.getTileRefAt(x, y, 0));
|
||||
mesh.addTile(data, 0, 0);
|
||||
mesh.RemoveTile(mesh.GetTileRefAt(x, y, 0));
|
||||
mesh.AddTile(data, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
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);
|
||||
|
||||
using var @is = new BinaryReader(ms);
|
||||
mesh = reader.read(@is, 6);
|
||||
Assert.That(mesh.getMaxTiles(), Is.EqualTo(128));
|
||||
Assert.That(mesh.getParams().maxPolys, Is.EqualTo(0x8000));
|
||||
Assert.That(mesh.getParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
|
||||
List<MeshTile> tiles = mesh.getTilesAt(6, 9);
|
||||
mesh = reader.Read(@is, 6);
|
||||
Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128));
|
||||
Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000));
|
||||
Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
|
||||
List<MeshTile> tiles = mesh.GetTilesAt(6, 9);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
|
||||
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[0].data.polys.Length, Is.EqualTo(2));
|
||||
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[0].data.polys.Length, Is.EqualTo(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[0].data.polys.Length, Is.EqualTo(5));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3));
|
||||
|
|
|
@ -66,7 +66,7 @@ public class MoveAlongSurfaceTest : AbstractDetourTest
|
|||
};
|
||||
|
||||
[Test]
|
||||
public void testMoveAlongSurface()
|
||||
public void TestMoveAlongSurface()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
for (int i = 0; i < startRefs.Length; i++)
|
||||
|
@ -74,18 +74,18 @@ public class MoveAlongSurfaceTest : AbstractDetourTest
|
|||
long startRef = startRefs[i];
|
||||
Vector3f startPos = startPoss[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);
|
||||
MoveAlongSurfaceResult path = result.result;
|
||||
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++)
|
||||
{
|
||||
Assert.That(path.getVisited()[j], Is.EqualTo(VISITED[i][j]));
|
||||
Assert.That(path.GetVisited()[j], Is.EqualTo(VISITED[i][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,13 +26,13 @@ public class NavMeshBuilderTest
|
|||
private MeshData nmd;
|
||||
|
||||
[SetUp]
|
||||
public void setUp()
|
||||
public void SetUp()
|
||||
{
|
||||
nmd = new RecastTestMeshBuilder().getMeshData();
|
||||
nmd = new RecastTestMeshBuilder().GetMeshData();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testBVTree()
|
||||
public void TestBVTree()
|
||||
{
|
||||
Assert.That(nmd.verts.Length / 3, Is.EqualTo(225));
|
||||
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[1], Is.EqualTo(224));
|
||||
Assert.That(nmd.polys[118].flags, Is.EqualTo(12));
|
||||
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].GetArea(), Is.EqualTo(2));
|
||||
Assert.That(nmd.polys[118].GetType(), Is.EqualTo(Poly.DT_POLYTYPE_OFFMESH_CONNECTION));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,34 +27,34 @@ public class PolygonByCircleConstraintTest
|
|||
private readonly PolygonByCircleConstraint constraint = new PolygonByCircleConstraint.StrictPolygonByCircleConstraint();
|
||||
|
||||
[Test]
|
||||
public void shouldHandlePolygonFullyInsideCircle()
|
||||
public void ShouldHandlePolygonFullyInsideCircle()
|
||||
{
|
||||
float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 };
|
||||
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));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void shouldHandleVerticalSegment()
|
||||
public void ShouldHandleVerticalSegment()
|
||||
{
|
||||
int expectedSize = 21;
|
||||
float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 };
|
||||
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, Is.SupersetOf(new[] { 2f, 0f, 2f, 2f, 0f, -2f }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void shouldHandleCircleFullyInsidePolygon()
|
||||
public void ShouldHandleCircleFullyInsidePolygon()
|
||||
{
|
||||
int expectedSize = 12 * 3;
|
||||
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
||||
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));
|
||||
|
||||
|
@ -67,24 +67,24 @@ public class PolygonByCircleConstraintTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void shouldHandleCircleInsidePolygon()
|
||||
public void ShouldHandleCircleInsidePolygon()
|
||||
{
|
||||
int expectedSize = 9 * 3;
|
||||
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
||||
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, Is.SupersetOf(new[] { -2f, 0f, -4f, -4f, 0f, 0f, -3.4641016f, 0.0f, 1.6076951f, -2.0f, 0.0f, 2.0f }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void shouldHandleCircleOutsidePolygon()
|
||||
public void ShouldHandleCircleOutsidePolygon()
|
||||
{
|
||||
int expectedSize = 7 * 3;
|
||||
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
||||
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, Is.SupersetOf(new[] { 1.5358982f, 0f, 3f, 2f, 0f, 3f, 3f, 0f, -3f }));
|
||||
|
|
|
@ -29,15 +29,15 @@ namespace DotRecast.Detour.Test;
|
|||
public class RandomPointTest : AbstractDetourTest
|
||||
{
|
||||
[Test]
|
||||
public void testRandom()
|
||||
public void TestRandom()
|
||||
{
|
||||
FRand f = new FRand(1);
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
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);
|
||||
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[] bmax = new float[2];
|
||||
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]);
|
||||
}
|
||||
|
||||
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().z >= bmin[1], Is.True);
|
||||
Assert.That(point.result.getRandomPt().z <= bmax[1], 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().z >= bmin[1], Is.True);
|
||||
Assert.That(point.result.GetRandomPt().z <= bmax[1], Is.True);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testRandomAroundCircle()
|
||||
public void TestRandomAroundCircle()
|
||||
{
|
||||
FRand f = new FRand(1);
|
||||
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++)
|
||||
{
|
||||
Result<FindRandomPointResult> result = query.findRandomPointAroundCircle(point.getRandomRef(), point.getRandomPt(),
|
||||
Result<FindRandomPointResult> result = query.FindRandomPointAroundCircle(point.GetRandomRef(), point.GetRandomPt(),
|
||||
5f, filter, f);
|
||||
Assert.That(result.Failed(), Is.False);
|
||||
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[] bmax = new float[2];
|
||||
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]);
|
||||
}
|
||||
|
||||
Assert.That(point.getRandomPt().x >= bmin[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 <= bmax[1], Is.True);
|
||||
Assert.That(point.GetRandomPt().x >= bmin[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 <= bmax[1], Is.True);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testRandomWithinCircle()
|
||||
public void TestRandomWithinCircle()
|
||||
{
|
||||
FRand f = new FRand(1);
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
FindRandomPointResult point = query.findRandomPoint(filter, f).result;
|
||||
FindRandomPointResult point = query.FindRandomPoint(filter, f).result;
|
||||
float radius = 5f;
|
||||
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);
|
||||
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);
|
||||
point = result.result;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testPerformance()
|
||||
public void TestPerformance()
|
||||
{
|
||||
FRand f = new FRand(1);
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
FindRandomPointResult point = query.findRandomPoint(filter, f).result;
|
||||
FindRandomPointResult point = query.FindRandomPoint(filter, f).result;
|
||||
float radius = 5f;
|
||||
// jvm warmup
|
||||
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++)
|
||||
{
|
||||
query.findRandomPointWithinCircle(point.getRandomRef(), point.getRandomPt(), radius, filter, f);
|
||||
query.FindRandomPointWithinCircle(point.GetRandomRef(), point.GetRandomPt(), radius, filter, f);
|
||||
}
|
||||
|
||||
long t1 = FrequencyWatch.Ticks;
|
||||
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;
|
||||
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;
|
||||
|
|
|
@ -40,7 +40,7 @@ public class RecastTestMeshBuilder
|
|||
private const float m_detailSampleMaxError = 1.0f;
|
||||
|
||||
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,
|
||||
m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist,
|
||||
m_detailSampleMaxError)
|
||||
|
@ -55,16 +55,16 @@ public class RecastTestMeshBuilder
|
|||
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_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();
|
||||
RecastBuilderResult rcResult = rcBuilder.build(m_geom, bcfg);
|
||||
PolyMesh m_pmesh = rcResult.getMesh();
|
||||
RecastBuilderResult rcResult = rcBuilder.Build(m_geom, bcfg);
|
||||
PolyMesh m_pmesh = rcResult.GetMesh();
|
||||
for (int i = 0; i < m_pmesh.npolys; ++i)
|
||||
{
|
||||
m_pmesh.flags[i] = 1;
|
||||
}
|
||||
|
||||
PolyMeshDetail m_dmesh = rcResult.getMeshDetail();
|
||||
PolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
|
||||
NavMeshDataCreateParams option = new NavMeshDataCreateParams();
|
||||
option.verts = m_pmesh.verts;
|
||||
option.vertCount = m_pmesh.nverts;
|
||||
|
@ -105,10 +105,10 @@ public class RecastTestMeshBuilder
|
|||
option.offMeshConUserID = new int[1];
|
||||
option.offMeshConUserID[0] = 0x4567;
|
||||
option.offMeshConCount = 1;
|
||||
meshData = NavMeshBuilder.createNavMeshData(option);
|
||||
meshData = NavMeshBuilder.CreateNavMeshData(option);
|
||||
}
|
||||
|
||||
public MeshData getMeshData()
|
||||
public MeshData GetMeshData()
|
||||
{
|
||||
return meshData;
|
||||
}
|
||||
|
|
|
@ -23,12 +23,12 @@ namespace DotRecast.Detour.Test;
|
|||
|
||||
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)
|
||||
{
|
||||
RecastBuilder rcBuilder = new RecastBuilder();
|
||||
RecastBuilderResult rcResult = rcBuilder.build(geom, rcConfig);
|
||||
PolyMesh pmesh = rcResult.getMesh();
|
||||
RecastBuilderResult rcResult = rcBuilder.Build(geom, rcConfig);
|
||||
PolyMesh pmesh = rcResult.GetMesh();
|
||||
|
||||
if (applyRecastDemoFlags)
|
||||
{
|
||||
|
@ -58,13 +58,13 @@ public class TestDetourBuilder : DetourBuilder
|
|||
}
|
||||
}
|
||||
|
||||
PolyMeshDetail dmesh = rcResult.getMeshDetail();
|
||||
NavMeshDataCreateParams option = getNavMeshCreateParams(rcConfig.cfg, pmesh, dmesh, agentHeight, agentRadius,
|
||||
PolyMeshDetail dmesh = rcResult.GetMeshDetail();
|
||||
NavMeshDataCreateParams option = GetNavMeshCreateParams(rcConfig.cfg, pmesh, dmesh, agentHeight, agentRadius,
|
||||
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)
|
||||
{
|
||||
NavMeshDataCreateParams option = new NavMeshDataCreateParams();
|
||||
|
@ -93,11 +93,11 @@ public class TestDetourBuilder : DetourBuilder
|
|||
option.ch = rcConfig.ch;
|
||||
option.buildBvTree = true;
|
||||
/*
|
||||
* option.offMeshConVerts = m_geom->getOffMeshConnectionVerts(); option.offMeshConRad =
|
||||
* m_geom->getOffMeshConnectionRads(); option.offMeshConDir = m_geom->getOffMeshConnectionDirs();
|
||||
* option.offMeshConAreas = m_geom->getOffMeshConnectionAreas(); option.offMeshConFlags =
|
||||
* m_geom->getOffMeshConnectionFlags(); option.offMeshConUserID = m_geom->getOffMeshConnectionId();
|
||||
* option.offMeshConCount = m_geom->getOffMeshConnectionCount();
|
||||
* option.offMeshConVerts = m_geom->GetOffMeshConnectionVerts(); option.offMeshConRad =
|
||||
* m_geom->GetOffMeshConnectionRads(); option.offMeshConDir = m_geom->GetOffMeshConnectionDirs();
|
||||
* option.offMeshConAreas = m_geom->GetOffMeshConnectionAreas(); option.offMeshConFlags =
|
||||
* m_geom->GetOffMeshConnectionFlags(); option.offMeshConUserID = m_geom->GetOffMeshConnectionId();
|
||||
* option.offMeshConCount = m_geom->GetOffMeshConnectionCount();
|
||||
*/
|
||||
return option;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ public class TestTiledNavMeshBuilder
|
|||
private const int m_tileSize = 32;
|
||||
|
||||
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,
|
||||
m_regionMinSize, m_regionMergeSize, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, m_detailSampleDist,
|
||||
m_detailSampleMaxError, m_tileSize)
|
||||
|
@ -59,7 +59,7 @@ public class TestTiledNavMeshBuilder
|
|||
{
|
||||
// Create empty nav mesh
|
||||
NavMeshParams navMeshParams = new NavMeshParams();
|
||||
navMeshParams.orig = m_geom.getMeshBoundsMin();
|
||||
navMeshParams.orig = m_geom.GetMeshBoundsMin();
|
||||
navMeshParams.tileWidth = m_tileSize * m_cellSize;
|
||||
navMeshParams.tileHeight = m_tileSize * m_cellSize;
|
||||
navMeshParams.maxTiles = 128;
|
||||
|
@ -67,18 +67,18 @@ public class TestTiledNavMeshBuilder
|
|||
navMesh = new NavMesh(navMeshParams, 6);
|
||||
|
||||
// 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_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true,
|
||||
m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
|
||||
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
|
||||
|
||||
foreach (RecastBuilderResult result in rcResult)
|
||||
{
|
||||
PolyMesh pmesh = result.getMesh();
|
||||
PolyMesh pmesh = result.GetMesh();
|
||||
if (pmesh.npolys == 0)
|
||||
{
|
||||
continue;
|
||||
|
@ -97,7 +97,7 @@ public class TestTiledNavMeshBuilder
|
|||
option.polyFlags = pmesh.flags;
|
||||
option.polyCount = pmesh.npolys;
|
||||
option.nvp = pmesh.nvp;
|
||||
PolyMeshDetail dmesh = result.getMeshDetail();
|
||||
PolyMeshDetail dmesh = result.GetMeshDetail();
|
||||
option.detailMeshes = dmesh.meshes;
|
||||
option.detailVerts = dmesh.verts;
|
||||
option.detailVertsCount = dmesh.nverts;
|
||||
|
@ -113,11 +113,11 @@ public class TestTiledNavMeshBuilder
|
|||
option.tileX = result.tileX;
|
||||
option.tileZ = result.tileZ;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -50,19 +50,19 @@ public class TiledFindPathTest
|
|||
protected NavMesh navmesh;
|
||||
|
||||
[SetUp]
|
||||
public void setUp()
|
||||
public void SetUp()
|
||||
{
|
||||
navmesh = createNavMesh();
|
||||
navmesh = CreateNavMesh();
|
||||
query = new NavMeshQuery(navmesh);
|
||||
}
|
||||
|
||||
protected NavMesh createNavMesh()
|
||||
protected NavMesh CreateNavMesh()
|
||||
{
|
||||
return new TestTiledNavMeshBuilder().getNavMesh();
|
||||
return new TestTiledNavMeshBuilder().GetNavMesh();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testFindPath()
|
||||
public void TestFindPath()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
for (int i = 0; i < START_REFS.Length; i++)
|
||||
|
@ -71,7 +71,7 @@ public class TiledFindPathTest
|
|||
long endRef = END_REFS[i];
|
||||
Vector3f startPos = START_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.result.Count, Is.EqualTo(RESULTS[i].Length));
|
||||
for (int j = 0; j < RESULTS[i].Length; j++)
|
||||
|
|
|
@ -41,7 +41,7 @@ public class AbstractTileCacheTest
|
|||
|
||||
protected class TestTileCacheMeshProcess : TileCacheMeshProcess
|
||||
{
|
||||
public void process(NavMeshDataCreateParams option)
|
||||
public void Process(NavMeshDataCreateParams option)
|
||||
{
|
||||
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();
|
||||
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.cs = m_cellSize;
|
||||
option.orig = geom.getMeshBoundsMin();
|
||||
option.orig = geom.GetMeshBoundsMin();
|
||||
option.height = m_tileSize;
|
||||
option.width = m_tileSize;
|
||||
option.walkableHeight = m_agentHeight;
|
||||
|
@ -66,14 +66,14 @@ public class AbstractTileCacheTest
|
|||
option.maxTiles = twh[0] * twh[1] * EXPECTED_LAYERS_PER_TILE;
|
||||
option.maxObstacles = 128;
|
||||
NavMeshParams navMeshParams = new NavMeshParams();
|
||||
navMeshParams.orig = geom.getMeshBoundsMin();
|
||||
navMeshParams.orig = geom.GetMeshBoundsMin();
|
||||
navMeshParams.tileWidth = m_tileSize * m_cellSize;
|
||||
navMeshParams.tileHeight = m_tileSize * m_cellSize;
|
||||
navMeshParams.maxTiles = 256;
|
||||
navMeshParams.maxPolys = 16384;
|
||||
NavMesh navMesh = new NavMesh(navMeshParams, 6);
|
||||
TileCache tc = new TileCache(option, new TileCacheStorageParams(order, cCompatibility), navMesh,
|
||||
TileCacheCompressorFactory.get(cCompatibility), new TestTileCacheMeshProcess());
|
||||
TileCacheCompressorFactory.Get(cCompatibility), new TestTileCacheMeshProcess());
|
||||
return tc;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,28 +32,28 @@ public class TileCacheReaderTest
|
|||
private readonly TileCacheReader reader = new TileCacheReader();
|
||||
|
||||
[Test]
|
||||
public void testNavmesh()
|
||||
public void TestNavmesh()
|
||||
{
|
||||
using var ms = new MemoryStream(Loader.ToBytes("all_tiles_tilecache.bin"));
|
||||
using var @is = new BinaryReader(ms);
|
||||
TileCache tc = reader.read(@is, 6, null);
|
||||
Assert.That(tc.getNavMesh().getMaxTiles(), Is.EqualTo(256));
|
||||
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().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
|
||||
Assert.That(tc.getNavMesh().getMaxVertsPerPoly(), Is.EqualTo(6));
|
||||
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().walkableClimb, Is.EqualTo(0.9f).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().width, Is.EqualTo(48));
|
||||
Assert.That(tc.getParams().maxTiles, Is.EqualTo(6 * 7 * 4));
|
||||
Assert.That(tc.getParams().maxObstacles, Is.EqualTo(128));
|
||||
Assert.That(tc.getTileCount(), Is.EqualTo(168));
|
||||
TileCache tc = reader.Read(@is, 6, null);
|
||||
Assert.That(tc.GetNavMesh().GetMaxTiles(), Is.EqualTo(256));
|
||||
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().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
|
||||
Assert.That(tc.GetNavMesh().GetMaxVertsPerPoly(), Is.EqualTo(6));
|
||||
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().walkableClimb, Is.EqualTo(0.9f).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().width, Is.EqualTo(48));
|
||||
Assert.That(tc.GetParams().maxTiles, Is.EqualTo(6 * 7 * 4));
|
||||
Assert.That(tc.GetParams().maxObstacles, Is.EqualTo(128));
|
||||
Assert.That(tc.GetTileCount(), Is.EqualTo(168));
|
||||
// Tile0: Tris: 1, Verts: 4 Detail Meshed: 1 Detail Verts: 0 Detail Tris: 2
|
||||
// Verts: -2.269517, 28.710686, 28.710686
|
||||
MeshTile tile = tc.getNavMesh().getTile(0);
|
||||
MeshTile tile = tc.GetNavMesh().GetTile(0);
|
||||
MeshData data = tile.data;
|
||||
MeshHeader header = data.header;
|
||||
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));
|
||||
// Tile8: Tris: 7, Verts: 10 Detail Meshed: 7 Detail Verts: 0 Detail Tris: 10
|
||||
// Verts: 0.330483, 43.110687, 43.110687
|
||||
tile = tc.getNavMesh().getTile(8);
|
||||
tile = tc.GetNavMesh().GetTile(8);
|
||||
data = tile.data;
|
||||
header = data.header;
|
||||
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));
|
||||
// Tile16: Tris: 13, Verts: 33 Detail Meshed: 13 Detail Verts: 0 Detail Tris: 25
|
||||
// Verts: 1.130483, 5.610685, 6.510685
|
||||
tile = tc.getNavMesh().getTile(16);
|
||||
tile = tc.GetNavMesh().GetTile(16);
|
||||
data = tile.data;
|
||||
header = data.header;
|
||||
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));
|
||||
// Tile29: Tris: 5, Verts: 15 Detail Meshed: 5 Detail Verts: 0 Detail Tris: 11
|
||||
// Verts: 10.330483, 10.110685, 10.110685
|
||||
tile = tc.getNavMesh().getTile(29);
|
||||
tile = tc.GetNavMesh().GetTile(29);
|
||||
data = tile.data;
|
||||
header = data.header;
|
||||
Assert.That(header.vertCount, Is.EqualTo(15));
|
||||
|
@ -130,28 +130,28 @@ public class TileCacheReaderTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testDungeon()
|
||||
public void TestDungeon()
|
||||
{
|
||||
using var ms = new MemoryStream(Loader.ToBytes("dungeon_all_tiles_tilecache.bin"));
|
||||
using var @is = new BinaryReader(ms);
|
||||
TileCache tc = reader.read(@is, 6, null);
|
||||
Assert.That(tc.getNavMesh().getMaxTiles(), Is.EqualTo(256));
|
||||
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().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
|
||||
Assert.That(tc.getNavMesh().getMaxVertsPerPoly(), Is.EqualTo(6));
|
||||
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().walkableClimb, Is.EqualTo(0.9f).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().width, Is.EqualTo(48));
|
||||
Assert.That(tc.getParams().maxTiles, Is.EqualTo(6 * 7 * 4));
|
||||
Assert.That(tc.getParams().maxObstacles, Is.EqualTo(128));
|
||||
Assert.That(tc.getTileCount(), Is.EqualTo(168));
|
||||
TileCache tc = reader.Read(@is, 6, null);
|
||||
Assert.That(tc.GetNavMesh().GetMaxTiles(), Is.EqualTo(256));
|
||||
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().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
|
||||
Assert.That(tc.GetNavMesh().GetMaxVertsPerPoly(), Is.EqualTo(6));
|
||||
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().walkableClimb, Is.EqualTo(0.9f).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().width, Is.EqualTo(48));
|
||||
Assert.That(tc.GetParams().maxTiles, Is.EqualTo(6 * 7 * 4));
|
||||
Assert.That(tc.GetParams().maxObstacles, Is.EqualTo(128));
|
||||
Assert.That(tc.GetTileCount(), Is.EqualTo(168));
|
||||
// Tile0: Tris: 8, Verts: 18 Detail Meshed: 8 Detail Verts: 0 Detail Tris: 14
|
||||
// Verts: 14.997294, 15.484785, 15.484785
|
||||
MeshTile tile = tc.getNavMesh().getTile(0);
|
||||
MeshTile tile = tc.GetNavMesh().GetTile(0);
|
||||
MeshData data = tile.data;
|
||||
MeshHeader header = data.header;
|
||||
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));
|
||||
// Tile8: Tris: 3, Verts: 8 Detail Meshed: 3 Detail Verts: 0 Detail Tris: 6
|
||||
// Verts: 13.597294, 17.584785, 17.584785
|
||||
tile = tc.getNavMesh().getTile(8);
|
||||
tile = tc.GetNavMesh().GetTile(8);
|
||||
data = tile.data;
|
||||
header = data.header;
|
||||
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));
|
||||
// Tile16: Tris: 10, Verts: 20 Detail Meshed: 10 Detail Verts: 0 Detail Tris: 18
|
||||
// Verts: 6.197294, -22.315216, -22.315216
|
||||
tile = tc.getNavMesh().getTile(16);
|
||||
tile = tc.GetNavMesh().GetTile(16);
|
||||
data = tile.data;
|
||||
header = data.header;
|
||||
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));
|
||||
// Tile29: Tris: 1, Verts: 5 Detail Meshed: 1 Detail Verts: 0 Detail Tris: 3
|
||||
// Verts: 10.197294, 48.484783, 48.484783
|
||||
tile = tc.getNavMesh().getTile(29);
|
||||
tile = tc.GetNavMesh().GetTile(29);
|
||||
data = tile.data;
|
||||
header = data.header;
|
||||
Assert.That(header.vertCount, Is.EqualTo(5));
|
||||
|
|
|
@ -35,54 +35,54 @@ public class TileCacheReaderWriterTest : AbstractTileCacheTest
|
|||
private readonly TileCacheWriter writer = new TileCacheWriter();
|
||||
|
||||
[Test]
|
||||
public void testFastLz()
|
||||
public void TestFastLz()
|
||||
{
|
||||
testDungeon(false);
|
||||
testDungeon(true);
|
||||
TestDungeon(false);
|
||||
TestDungeon(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testLZ4()
|
||||
public void TestLZ4()
|
||||
{
|
||||
testDungeon(true);
|
||||
testDungeon(false);
|
||||
TestDungeon(true);
|
||||
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);
|
||||
List<byte[]> layers = layerBuilder.build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1);
|
||||
TileCache tc = getTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility);
|
||||
List<byte[]> layers = layerBuilder.Build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1);
|
||||
TileCache tc = GetTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility);
|
||||
foreach (byte[] layer in layers)
|
||||
{
|
||||
long refs = tc.addTile(layer, 0);
|
||||
tc.buildNavMeshTile(refs);
|
||||
long refs = tc.AddTile(layer, 0);
|
||||
tc.BuildNavMeshTile(refs);
|
||||
}
|
||||
|
||||
using var msout = new MemoryStream();
|
||||
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 bais = new BinaryReader(msis);
|
||||
tc = reader.read(bais, 6, null);
|
||||
Assert.That(tc.getNavMesh().getMaxTiles(), Is.EqualTo(256));
|
||||
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().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
|
||||
Assert.That(tc.getNavMesh().getMaxVertsPerPoly(), Is.EqualTo(6));
|
||||
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().walkableClimb, Is.EqualTo(0.9f).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().width, Is.EqualTo(48));
|
||||
Assert.That(tc.getParams().maxTiles, Is.EqualTo(6 * 7 * 4));
|
||||
Assert.That(tc.getParams().maxObstacles, Is.EqualTo(128));
|
||||
Assert.That(tc.getTileCount(), Is.EqualTo(168));
|
||||
tc = reader.Read(bais, 6, null);
|
||||
Assert.That(tc.GetNavMesh().GetMaxTiles(), Is.EqualTo(256));
|
||||
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().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
|
||||
Assert.That(tc.GetNavMesh().GetMaxVertsPerPoly(), Is.EqualTo(6));
|
||||
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().walkableClimb, Is.EqualTo(0.9f).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().width, Is.EqualTo(48));
|
||||
Assert.That(tc.GetParams().maxTiles, Is.EqualTo(6 * 7 * 4));
|
||||
Assert.That(tc.GetParams().maxObstacles, Is.EqualTo(128));
|
||||
Assert.That(tc.GetTileCount(), Is.EqualTo(168));
|
||||
// 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;
|
||||
MeshHeader header = data.header;
|
||||
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.detailTris.Length, Is.EqualTo(4 * 14));
|
||||
// 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;
|
||||
header = data.header;
|
||||
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.detailTris.Length, Is.EqualTo(4 * 6));
|
||||
// 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;
|
||||
header = data.header;
|
||||
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.detailTris.Length, Is.EqualTo(4 * 18));
|
||||
// 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;
|
||||
header = data.header;
|
||||
Assert.That(header.vertCount, Is.EqualTo(5));
|
||||
|
|
|
@ -30,71 +30,71 @@ namespace DotRecast.Detour.TileCache.Test;
|
|||
public class TempObstaclesTest : AbstractTileCacheTest
|
||||
{
|
||||
[Test]
|
||||
public void testDungeon()
|
||||
public void TestDungeon()
|
||||
{
|
||||
bool cCompatibility = true;
|
||||
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("dungeon.obj"));
|
||||
InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
|
||||
TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom);
|
||||
List<byte[]> layers = layerBuilder.build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1);
|
||||
TileCache tc = getTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility);
|
||||
List<byte[]> layers = layerBuilder.Build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1);
|
||||
TileCache tc = GetTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility);
|
||||
foreach (byte[] data in layers)
|
||||
{
|
||||
long refs = tc.addTile(data, 0);
|
||||
tc.buildNavMeshTile(refs);
|
||||
long refs = tc.AddTile(data, 0);
|
||||
tc.BuildNavMeshTile(refs);
|
||||
}
|
||||
|
||||
List<MeshTile> tiles = tc.getNavMesh().getTilesAt(1, 4);
|
||||
List<MeshTile> tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||
MeshTile tile = tiles[0];
|
||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
|
||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
|
||||
long o = tc.addObstacle(Vector3f.Of(-1.815208f, 9.998184f, -20.307983f), 1f, 2f);
|
||||
bool upToDate = tc.update();
|
||||
long o = tc.AddObstacle(Vector3f.Of(-1.815208f, 9.998184f, -20.307983f), 1f, 2f);
|
||||
bool upToDate = tc.Update();
|
||||
Assert.That(upToDate, Is.True);
|
||||
tiles = tc.getNavMesh().getTilesAt(1, 4);
|
||||
tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||
tile = tiles[0];
|
||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(22));
|
||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(11));
|
||||
tc.removeObstacle(o);
|
||||
upToDate = tc.update();
|
||||
tc.RemoveObstacle(o);
|
||||
upToDate = tc.Update();
|
||||
Assert.That(upToDate, Is.True);
|
||||
tiles = tc.getNavMesh().getTilesAt(1, 4);
|
||||
tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||
tile = tiles[0];
|
||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
|
||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testDungeonBox()
|
||||
public void TestDungeonBox()
|
||||
{
|
||||
bool cCompatibility = true;
|
||||
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("dungeon.obj"));
|
||||
InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
|
||||
TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom);
|
||||
List<byte[]> layers = layerBuilder.build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1);
|
||||
TileCache tc = getTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility);
|
||||
List<byte[]> layers = layerBuilder.Build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1);
|
||||
TileCache tc = GetTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility);
|
||||
foreach (byte[] data in layers)
|
||||
{
|
||||
long refs = tc.addTile(data, 0);
|
||||
tc.buildNavMeshTile(refs);
|
||||
long refs = tc.AddTile(data, 0);
|
||||
tc.BuildNavMeshTile(refs);
|
||||
}
|
||||
|
||||
List<MeshTile> tiles = tc.getNavMesh().getTilesAt(1, 4);
|
||||
List<MeshTile> tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||
MeshTile tile = tiles[0];
|
||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
|
||||
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(-1.315208f, 11.998184f, -19.807983f)
|
||||
);
|
||||
bool upToDate = tc.update();
|
||||
bool upToDate = tc.Update();
|
||||
Assert.That(upToDate, Is.True);
|
||||
tiles = tc.getNavMesh().getTilesAt(1, 4);
|
||||
tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||
tile = tiles[0];
|
||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(22));
|
||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(11));
|
||||
tc.removeObstacle(o);
|
||||
upToDate = tc.update();
|
||||
tc.RemoveObstacle(o);
|
||||
upToDate = tc.Update();
|
||||
Assert.That(upToDate, Is.True);
|
||||
tiles = tc.getNavMesh().getTilesAt(1, 4);
|
||||
tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||
tile = tiles[0];
|
||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
|
||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
|
||||
|
|
|
@ -52,35 +52,35 @@ public class TestTileLayerBuilder : AbstractTileLayersBuilder
|
|||
public TestTileLayerBuilder(InputGeomProvider 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,
|
||||
m_agentRadius, m_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly,
|
||||
true, m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
|
||||
Vector3f bmin = geom.getMeshBoundsMin();
|
||||
Vector3f bmax = geom.getMeshBoundsMax();
|
||||
int[] twh = Recast.Recast.calcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize);
|
||||
Vector3f bmin = geom.GetMeshBoundsMin();
|
||||
Vector3f bmax = geom.GetMeshBoundsMax();
|
||||
int[] twh = Recast.Recast.CalcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize);
|
||||
tw = twh[0];
|
||||
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;
|
||||
}
|
||||
|
||||
public int getTh()
|
||||
public int GetTh()
|
||||
{
|
||||
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();
|
||||
if (lset != null)
|
||||
{
|
||||
|
@ -110,20 +110,20 @@ public class TestTileLayerBuilder : AbstractTileLayersBuilder
|
|||
header.maxy = layer.maxy;
|
||||
header.hmin = layer.hmin;
|
||||
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;
|
||||
}
|
||||
|
||||
protected HeightfieldLayerSet getHeightfieldSet(int tx, int ty)
|
||||
protected HeightfieldLayerSet GetHeightfieldSet(int tx, int ty)
|
||||
{
|
||||
RecastBuilder rcBuilder = new RecastBuilder();
|
||||
Vector3f bmin = geom.getMeshBoundsMin();
|
||||
Vector3f bmax = geom.getMeshBoundsMax();
|
||||
Vector3f bmin = geom.GetMeshBoundsMin();
|
||||
Vector3f bmax = geom.GetMeshBoundsMax();
|
||||
RecastBuilderConfig cfg = new RecastBuilderConfig(rcConfig, bmin, bmax, tx, ty);
|
||||
HeightfieldLayerSet lset = rcBuilder.buildLayers(geom, cfg);
|
||||
HeightfieldLayerSet lset = rcBuilder.BuildLayers(geom, cfg);
|
||||
return lset;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,26 +39,26 @@ public class TileCacheFindPathTest : AbstractTileCacheTest
|
|||
{
|
||||
using var msis = new MemoryStream(Loader.ToBytes("dungeon_all_tiles_tilecache.bin"));
|
||||
using var @is = new BinaryReader(msis);
|
||||
TileCache tcC = new TileCacheReader().read(@is, 6, new TestTileCacheMeshProcess());
|
||||
navmesh = tcC.getNavMesh();
|
||||
TileCache tcC = new TileCacheReader().Read(@is, 6, new TestTileCacheMeshProcess());
|
||||
navmesh = tcC.GetNavMesh();
|
||||
query = new NavMeshQuery(navmesh);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testFindPath()
|
||||
public void TestFindPath()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
Vector3f extents = Vector3f.Of(2f, 4f, 2f);
|
||||
Result<FindNearestPolyResult> findPolyStart = query.findNearestPoly(start, extents, filter);
|
||||
Result<FindNearestPolyResult> findPolyEnd = query.findNearestPoly(end, extents, filter);
|
||||
long startRef = findPolyStart.result.getNearestRef();
|
||||
long endRef = findPolyEnd.result.getNearestRef();
|
||||
Vector3f startPos = findPolyStart.result.getNearestPos();
|
||||
Vector3f endPos = findPolyEnd.result.getNearestPos();
|
||||
Result<List<long>> path = query.findPath(startRef, endRef, startPos, endPos, filter);
|
||||
Result<FindNearestPolyResult> findPolyStart = query.FindNearestPoly(start, extents, filter);
|
||||
Result<FindNearestPolyResult> findPolyEnd = query.FindNearestPoly(end, extents, filter);
|
||||
long startRef = findPolyStart.result.GetNearestRef();
|
||||
long endRef = findPolyEnd.result.GetNearestRef();
|
||||
Vector3f startPos = findPolyStart.result.GetNearestPos();
|
||||
Vector3f endPos = findPolyEnd.result.GetNearestPos();
|
||||
Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter);
|
||||
int maxStraightPath = 256;
|
||||
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));
|
||||
}
|
||||
}
|
|
@ -53,35 +53,35 @@ public class TileCacheNavigationTest : AbstractTileCacheTest
|
|||
protected NavMeshQuery query;
|
||||
|
||||
[SetUp]
|
||||
public void setUp()
|
||||
public void SetUp()
|
||||
{
|
||||
bool cCompatibility = true;
|
||||
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("dungeon.obj"));
|
||||
InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
|
||||
TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom);
|
||||
List<byte[]> layers = layerBuilder.build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1);
|
||||
TileCache tc = getTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility);
|
||||
List<byte[]> layers = layerBuilder.Build(ByteOrder.LITTLE_ENDIAN, cCompatibility, 1);
|
||||
TileCache tc = GetTileCache(geom, ByteOrder.LITTLE_ENDIAN, cCompatibility);
|
||||
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);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testFindPathWithDefaultHeuristic()
|
||||
public void TestFindPathWithDefaultHeuristic()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
for (int i = 0; i < startRefs.Length; i++)
|
||||
|
@ -90,7 +90,7 @@ public class TileCacheNavigationTest : AbstractTileCacheTest
|
|||
long endRef = endRefs[i];
|
||||
Vector3f startPos = startPoss[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.result.Count, Is.EqualTo(results[i].Length));
|
||||
for (int j = 0; j < results[i].Length; j++)
|
||||
|
@ -101,7 +101,7 @@ public class TileCacheNavigationTest : AbstractTileCacheTest
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void testFindPathWithNoHeuristic()
|
||||
public void TestFindPathWithNoHeuristic()
|
||||
{
|
||||
QueryFilter filter = new DefaultQueryFilter();
|
||||
for (int i = 0; i < startRefs.Length; i++)
|
||||
|
@ -110,7 +110,7 @@ public class TileCacheNavigationTest : AbstractTileCacheTest
|
|||
long endRef = endRefs[i];
|
||||
Vector3f startPos = startPoss[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);
|
||||
Assert.That(path.status, Is.EqualTo(statuses[i]));
|
||||
Assert.That(path.result.Count, Is.EqualTo(results[i].Length));
|
||||
|
|
|
@ -32,68 +32,68 @@ namespace DotRecast.Detour.TileCache.Test;
|
|||
public class TileCacheTest : AbstractTileCacheTest
|
||||
{
|
||||
[Test]
|
||||
public void testFastLz()
|
||||
public void TestFastLz()
|
||||
{
|
||||
testDungeon(ByteOrder.LITTLE_ENDIAN, false);
|
||||
testDungeon(ByteOrder.LITTLE_ENDIAN, true);
|
||||
testDungeon(ByteOrder.BIG_ENDIAN, false);
|
||||
testDungeon(ByteOrder.BIG_ENDIAN, true);
|
||||
test(ByteOrder.LITTLE_ENDIAN, false);
|
||||
test(ByteOrder.LITTLE_ENDIAN, true);
|
||||
test(ByteOrder.BIG_ENDIAN, false);
|
||||
test(ByteOrder.BIG_ENDIAN, true);
|
||||
TestDungeon(ByteOrder.LITTLE_ENDIAN, false);
|
||||
TestDungeon(ByteOrder.LITTLE_ENDIAN, true);
|
||||
TestDungeon(ByteOrder.BIG_ENDIAN, false);
|
||||
TestDungeon(ByteOrder.BIG_ENDIAN, true);
|
||||
Test(ByteOrder.LITTLE_ENDIAN, false);
|
||||
Test(ByteOrder.LITTLE_ENDIAN, true);
|
||||
Test(ByteOrder.BIG_ENDIAN, false);
|
||||
Test(ByteOrder.BIG_ENDIAN, true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testLZ4()
|
||||
public void TestLZ4()
|
||||
{
|
||||
testDungeon(ByteOrder.LITTLE_ENDIAN, false);
|
||||
testDungeon(ByteOrder.LITTLE_ENDIAN, true);
|
||||
testDungeon(ByteOrder.BIG_ENDIAN, false);
|
||||
testDungeon(ByteOrder.BIG_ENDIAN, true);
|
||||
test(ByteOrder.LITTLE_ENDIAN, false);
|
||||
test(ByteOrder.LITTLE_ENDIAN, true);
|
||||
test(ByteOrder.BIG_ENDIAN, false);
|
||||
test(ByteOrder.BIG_ENDIAN, true);
|
||||
TestDungeon(ByteOrder.LITTLE_ENDIAN, false);
|
||||
TestDungeon(ByteOrder.LITTLE_ENDIAN, true);
|
||||
TestDungeon(ByteOrder.BIG_ENDIAN, false);
|
||||
TestDungeon(ByteOrder.BIG_ENDIAN, true);
|
||||
Test(ByteOrder.LITTLE_ENDIAN, false);
|
||||
Test(ByteOrder.LITTLE_ENDIAN, true);
|
||||
Test(ByteOrder.BIG_ENDIAN, false);
|
||||
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"));
|
||||
TileCache tc = getTileCache(geom, order, cCompatibility);
|
||||
InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
|
||||
TileCache tc = GetTileCache(geom, order, cCompatibility);
|
||||
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 cacheCompressedSize = 0;
|
||||
int cacheRawSize = 0;
|
||||
foreach (byte[] layer in layers)
|
||||
{
|
||||
long refs = tc.addTile(layer, 0);
|
||||
tc.buildNavMeshTile(refs);
|
||||
long refs = tc.AddTile(layer, 0);
|
||||
tc.BuildNavMeshTile(refs);
|
||||
cacheLayerCount++;
|
||||
cacheCompressedSize += layer.Length;
|
||||
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);
|
||||
Assert.That(tc.getNavMesh().getMaxTiles(), Is.EqualTo(256));
|
||||
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().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
|
||||
Assert.That(tc.getNavMesh().getMaxVertsPerPoly(), Is.EqualTo(6));
|
||||
Assert.That(tc.getParams().cs, Is.EqualTo(0.3f));
|
||||
Assert.That(tc.getParams().ch, Is.EqualTo(0.2f));
|
||||
Assert.That(tc.getParams().walkableClimb, Is.EqualTo(0.9f));
|
||||
Assert.That(tc.getParams().walkableHeight, Is.EqualTo(2f));
|
||||
Assert.That(tc.getParams().walkableRadius, Is.EqualTo(0.6f));
|
||||
Assert.That(tc.getParams().width, Is.EqualTo(48));
|
||||
Assert.That(tc.getParams().maxTiles, Is.EqualTo(6 * 7 * 4));
|
||||
Assert.That(tc.getParams().maxObstacles, Is.EqualTo(128));
|
||||
Assert.That(tc.getTileCount(), Is.EqualTo(168));
|
||||
Assert.That(tc.GetNavMesh().GetMaxTiles(), Is.EqualTo(256));
|
||||
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().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
|
||||
Assert.That(tc.GetNavMesh().GetMaxVertsPerPoly(), Is.EqualTo(6));
|
||||
Assert.That(tc.GetParams().cs, Is.EqualTo(0.3f));
|
||||
Assert.That(tc.GetParams().ch, Is.EqualTo(0.2f));
|
||||
Assert.That(tc.GetParams().walkableClimb, Is.EqualTo(0.9f));
|
||||
Assert.That(tc.GetParams().walkableHeight, Is.EqualTo(2f));
|
||||
Assert.That(tc.GetParams().walkableRadius, Is.EqualTo(0.6f));
|
||||
Assert.That(tc.GetParams().width, Is.EqualTo(48));
|
||||
Assert.That(tc.GetParams().maxTiles, Is.EqualTo(6 * 7 * 4));
|
||||
Assert.That(tc.GetParams().maxObstacles, Is.EqualTo(128));
|
||||
Assert.That(tc.GetTileCount(), Is.EqualTo(168));
|
||||
|
||||
// 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;
|
||||
MeshHeader header = data.header;
|
||||
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[9], Is.EqualTo(15.484785f).Within(0.0001f));
|
||||
// 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;
|
||||
header = data.header;
|
||||
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.detailTris.Length, Is.EqualTo(4 * 6));
|
||||
// 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;
|
||||
header = data.header;
|
||||
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.detailTris.Length, Is.EqualTo(4 * 18));
|
||||
// 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;
|
||||
header = data.header;
|
||||
Assert.That(header.vertCount, Is.EqualTo(5));
|
||||
|
@ -153,81 +153,81 @@ public class TileCacheTest : AbstractTileCacheTest
|
|||
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"));
|
||||
TileCache tc = getTileCache(geom, order, cCompatibility);
|
||||
InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("nav_test.obj"));
|
||||
TileCache tc = GetTileCache(geom, order, cCompatibility);
|
||||
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 cacheCompressedSize = 0;
|
||||
int cacheRawSize = 0;
|
||||
foreach (byte[] layer in layers)
|
||||
{
|
||||
long refs = tc.addTile(layer, 0);
|
||||
tc.buildNavMeshTile(refs);
|
||||
long refs = tc.AddTile(layer, 0);
|
||||
tc.BuildNavMeshTile(refs);
|
||||
cacheLayerCount++;
|
||||
cacheCompressedSize += layer.Length;
|
||||
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);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void testPerformance()
|
||||
public void TestPerformance()
|
||||
{
|
||||
int threads = 4;
|
||||
ByteOrder order = ByteOrder.LITTLE_ENDIAN;
|
||||
bool cCompatibility = false;
|
||||
InputGeomProvider geom = ObjImporter.load(Loader.ToBytes("dungeon.obj"));
|
||||
InputGeomProvider geom = ObjImporter.Load(Loader.ToBytes("dungeon.obj"));
|
||||
TestTileLayerBuilder layerBuilder = new TestTileLayerBuilder(geom);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
layerBuilder.build(order, cCompatibility, 1);
|
||||
layerBuilder.build(order, cCompatibility, threads);
|
||||
layerBuilder.Build(order, cCompatibility, 1);
|
||||
layerBuilder.Build(order, cCompatibility, threads);
|
||||
}
|
||||
|
||||
long t1 = FrequencyWatch.Ticks;
|
||||
List<byte[]> layers = null;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
layers = layerBuilder.build(order, cCompatibility, 1);
|
||||
layers = layerBuilder.Build(order, cCompatibility, 1);
|
||||
}
|
||||
|
||||
long t2 = FrequencyWatch.Ticks;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
layers = layerBuilder.build(order, cCompatibility, threads);
|
||||
layers = layerBuilder.Build(order, cCompatibility, threads);
|
||||
}
|
||||
|
||||
long t3 = FrequencyWatch.Ticks;
|
||||
Console.WriteLine(" Time ST : " + (t2 - t1) / 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)
|
||||
{
|
||||
long refs = tc.addTile(layer, 0);
|
||||
tc.buildNavMeshTile(refs);
|
||||
long refs = tc.AddTile(layer, 0);
|
||||
tc.BuildNavMeshTile(refs);
|
||||
}
|
||||
|
||||
Assert.That(tc.getNavMesh().getMaxTiles(), Is.EqualTo(256));
|
||||
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().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
|
||||
Assert.That(tc.getNavMesh().getMaxVertsPerPoly(), Is.EqualTo(6));
|
||||
Assert.That(tc.getParams().cs, Is.EqualTo(0.3f));
|
||||
Assert.That(tc.getParams().ch, Is.EqualTo(0.2f));
|
||||
Assert.That(tc.getParams().walkableClimb, Is.EqualTo(0.9f));
|
||||
Assert.That(tc.getParams().walkableHeight, Is.EqualTo(2f));
|
||||
Assert.That(tc.getParams().walkableRadius, Is.EqualTo(0.6f));
|
||||
Assert.That(tc.getParams().width, Is.EqualTo(48));
|
||||
Assert.That(tc.getParams().maxTiles, Is.EqualTo(6 * 7 * 4));
|
||||
Assert.That(tc.getParams().maxObstacles, Is.EqualTo(128));
|
||||
Assert.That(tc.getTileCount(), Is.EqualTo(168));
|
||||
Assert.That(tc.GetNavMesh().GetMaxTiles(), Is.EqualTo(256));
|
||||
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().tileHeight, Is.EqualTo(14.4f).Within(0.001f));
|
||||
Assert.That(tc.GetNavMesh().GetMaxVertsPerPoly(), Is.EqualTo(6));
|
||||
Assert.That(tc.GetParams().cs, Is.EqualTo(0.3f));
|
||||
Assert.That(tc.GetParams().ch, Is.EqualTo(0.2f));
|
||||
Assert.That(tc.GetParams().walkableClimb, Is.EqualTo(0.9f));
|
||||
Assert.That(tc.GetParams().walkableHeight, Is.EqualTo(2f));
|
||||
Assert.That(tc.GetParams().walkableRadius, Is.EqualTo(0.6f));
|
||||
Assert.That(tc.GetParams().width, Is.EqualTo(48));
|
||||
Assert.That(tc.GetParams().maxTiles, Is.EqualTo(6 * 7 * 4));
|
||||
Assert.That(tc.GetParams().maxObstacles, Is.EqualTo(128));
|
||||
Assert.That(tc.GetTileCount(), Is.EqualTo(168));
|
||||
// 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;
|
||||
MeshHeader header = data.header;
|
||||
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[9], Is.EqualTo(15.484785f).Within(0.0001f));
|
||||
// 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;
|
||||
header = data.header;
|
||||
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.detailTris.Length, Is.EqualTo(4 * 6));
|
||||
// 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;
|
||||
header = data.header;
|
||||
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.detailTris.Length, Is.EqualTo(4 * 18));
|
||||
// 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;
|
||||
header = data.header;
|
||||
Assert.That(header.vertCount, Is.EqualTo(5));
|
||||
|
|
|
@ -48,15 +48,15 @@ public class RecastLayersTest
|
|||
private const int m_tileSize = 48;
|
||||
|
||||
[Test]
|
||||
public void testDungeon2()
|
||||
public void TestDungeon2()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
[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[0].width, Is.EqualTo(48));
|
||||
Assert.That(lset.layers[0].hmin, Is.EqualTo(51));
|
||||
|
@ -72,9 +72,9 @@ public class RecastLayersTest
|
|||
}
|
||||
|
||||
[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[0].width, Is.EqualTo(48));
|
||||
Assert.That(lset.layers[0].hmin, Is.EqualTo(13));
|
||||
|
@ -114,9 +114,9 @@ public class RecastLayersTest
|
|||
}
|
||||
|
||||
[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[0].width, Is.EqualTo(48));
|
||||
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));
|
||||
}
|
||||
|
||||
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();
|
||||
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_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true,
|
||||
m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
|
||||
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), x, y);
|
||||
HeightfieldLayerSet lset = builder.buildLayers(geom, bcfg);
|
||||
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), x, y);
|
||||
HeightfieldLayerSet lset = builder.BuildLayers(geom, bcfg);
|
||||
return lset;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,60 +46,60 @@ public class RecastSoloMeshTest
|
|||
private PartitionType m_partitionType = PartitionType.WATERSHED;
|
||||
|
||||
[Test]
|
||||
public void testPerformance()
|
||||
public void TestPerformance()
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
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.LAYERS, 0, 5, 5, 203, 97, 97, 446, 266);
|
||||
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.LAYERS, 0, 5, 5, 203, 97, 97, 446, 266);
|
||||
}
|
||||
}
|
||||
|
||||
[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]
|
||||
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]
|
||||
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]
|
||||
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]
|
||||
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]
|
||||
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)
|
||||
{
|
||||
m_partitionType = partitionType;
|
||||
InputGeomProvider geomProvider = ObjImporter.load(Loader.ToBytes(filename));
|
||||
InputGeomProvider geomProvider = ObjImporter.Load(Loader.ToBytes(filename));
|
||||
long time = FrequencyWatch.Ticks;
|
||||
Vector3f bmin = geomProvider.getMeshBoundsMin();
|
||||
Vector3f bmax = geomProvider.getMeshBoundsMax();
|
||||
Vector3f bmin = geomProvider.GetMeshBoundsMin();
|
||||
Vector3f bmax = geomProvider.GetMeshBoundsMax();
|
||||
Telemetry m_ctx = new Telemetry();
|
||||
//
|
||||
// Step 1. Initialize build config.
|
||||
|
@ -117,10 +117,10 @@ public class RecastSoloMeshTest
|
|||
// 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);
|
||||
|
||||
foreach (TriMesh geom in geomProvider.meshes())
|
||||
foreach (TriMesh geom in geomProvider.Meshes())
|
||||
{
|
||||
float[] verts = geom.getVerts();
|
||||
int[] tris = geom.getTris();
|
||||
float[] verts = geom.GetVerts();
|
||||
int[] tris = geom.GetTris();
|
||||
int ntris = tris.Length / 3;
|
||||
|
||||
// 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,
|
||||
// calculate
|
||||
// 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);
|
||||
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.
|
||||
//
|
||||
|
@ -144,9 +144,9 @@ public class RecastSoloMeshTest
|
|||
// Once all geometry is rasterized, we do initial pass of filtering to
|
||||
// remove unwanted overhangs caused by the conservative rasterization
|
||||
// as well as filter spans where the character cannot possibly stand.
|
||||
RecastFilter.filterLowHangingWalkableObstacles(m_ctx, cfg.walkableClimb, m_solid);
|
||||
RecastFilter.filterLedgeSpans(m_ctx, cfg.walkableHeight, cfg.walkableClimb, m_solid);
|
||||
RecastFilter.filterWalkableLowHeightSpans(m_ctx, cfg.walkableHeight, m_solid);
|
||||
RecastFilter.FilterLowHangingWalkableObstacles(m_ctx, cfg.walkableClimb, m_solid);
|
||||
RecastFilter.FilterLedgeSpans(m_ctx, cfg.walkableHeight, cfg.walkableClimb, m_solid);
|
||||
RecastFilter.FilterWalkableLowHeightSpans(m_ctx, cfg.walkableHeight, m_solid);
|
||||
|
||||
//
|
||||
// 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.
|
||||
// This will result more cache coherent data as well as the neighbours
|
||||
// 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);
|
||||
|
||||
// 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.
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
* char)vols[i].area, *m_chf);
|
||||
*/
|
||||
|
||||
|
@ -211,20 +211,20 @@ public class RecastSoloMeshTest
|
|||
{
|
||||
// Prepare for region partitioning, by calculating distance field
|
||||
// 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.
|
||||
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)
|
||||
{
|
||||
// Partition the walkable surface into simple regions without holes.
|
||||
// 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
|
||||
{
|
||||
// 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");
|
||||
|
@ -234,7 +234,7 @@ public class RecastSoloMeshTest
|
|||
//
|
||||
|
||||
// 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);
|
||||
|
||||
Assert.That(m_cset.conts.Count, Is.EqualTo(expContours), "Contours");
|
||||
|
@ -243,7 +243,7 @@ public class RecastSoloMeshTest
|
|||
//
|
||||
|
||||
// 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.npolys, Is.EqualTo(expPolys), "Mesh Polys");
|
||||
|
||||
|
@ -252,7 +252,7 @@ public class RecastSoloMeshTest
|
|||
// 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);
|
||||
Assert.That(m_dmesh.nmeshes, Is.EqualTo(expDetMeshes), "Mesh Detail Meshes");
|
||||
Assert.That(m_dmesh.nverts, Is.EqualTo(expDetVerts), "Mesh Detail Verts");
|
||||
|
@ -260,15 +260,15 @@ public class RecastSoloMeshTest
|
|||
long time2 = FrequencyWatch.Ticks;
|
||||
Console.WriteLine(filename + " : " + partitionType + " " + (time2 - 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 + ".obj", m_pmesh);
|
||||
SaveObj(filename.Substring(0, filename.LastIndexOf('.')) + "_" + partitionType + "_detail.obj", m_dmesh);
|
||||
SaveObj(filename.Substring(0, filename.LastIndexOf('.')) + "_" + partitionType + ".obj", m_pmesh);
|
||||
foreach (var (key, millis) in m_ctx.ToList())
|
||||
{
|
||||
Console.WriteLine($"{key} : {millis} ms");
|
||||
}
|
||||
}
|
||||
|
||||
private void saveObj(string filename, PolyMesh mesh)
|
||||
private void SaveObj(string filename, PolyMesh mesh)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -308,7 +308,7 @@ public class RecastSoloMeshTest
|
|||
}
|
||||
}
|
||||
|
||||
private void saveObj(string filename, PolyMeshDetail dmesh)
|
||||
private void SaveObj(string filename, PolyMeshDetail dmesh)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -26,7 +26,7 @@ using static RecastConstants;
|
|||
public class RecastTest
|
||||
{
|
||||
[Test]
|
||||
public void testClearUnwalkableTriangles()
|
||||
public void TestClearUnwalkableTriangles()
|
||||
{
|
||||
float walkableSlopeAngle = 45;
|
||||
float[] verts = { 0, 0, 0, 1, 0, 0, 0, 0, -1 };
|
||||
|
@ -38,18 +38,18 @@ public class RecastTest
|
|||
Telemetry ctx = new Telemetry();
|
||||
{
|
||||
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");
|
||||
}
|
||||
{
|
||||
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");
|
||||
}
|
||||
{
|
||||
int[] areas = { 42 };
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,70 +53,70 @@ public class RecastTileMeshTest
|
|||
private const int m_tileSize = 32;
|
||||
|
||||
[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();
|
||||
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_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true,
|
||||
m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
|
||||
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), 7, 8);
|
||||
RecastBuilderResult rcResult = builder.build(geom, bcfg);
|
||||
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(1));
|
||||
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(5));
|
||||
bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), 6, 9);
|
||||
rcResult = builder.build(geom, bcfg);
|
||||
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(7));
|
||||
bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), 2, 9);
|
||||
rcResult = builder.build(geom, bcfg);
|
||||
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(9));
|
||||
bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), 4, 3);
|
||||
rcResult = builder.build(geom, bcfg);
|
||||
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(3));
|
||||
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(6));
|
||||
bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), 2, 8);
|
||||
rcResult = builder.build(geom, bcfg);
|
||||
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(5));
|
||||
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(17));
|
||||
bcfg = new RecastBuilderConfig(cfg, geom.getMeshBoundsMin(), geom.getMeshBoundsMax(), 0, 8);
|
||||
rcResult = builder.build(geom, bcfg);
|
||||
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(6));
|
||||
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(15));
|
||||
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 7, 8);
|
||||
RecastBuilderResult rcResult = builder.Build(geom, bcfg);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5));
|
||||
bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 6, 9);
|
||||
rcResult = builder.Build(geom, bcfg);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(7));
|
||||
bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 9);
|
||||
rcResult = builder.Build(geom, bcfg);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(9));
|
||||
bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 4, 3);
|
||||
rcResult = builder.Build(geom, bcfg);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(3));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(6));
|
||||
bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 8);
|
||||
rcResult = builder.Build(geom, bcfg);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(5));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(17));
|
||||
bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 0, 8);
|
||||
rcResult = builder.Build(geom, bcfg);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(6));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(15));
|
||||
}
|
||||
|
||||
[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();
|
||||
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_agentMaxClimb, m_regionMinArea, m_regionMergeArea, m_edgeMaxLen, m_edgeMaxError, m_vertsPerPoly, true,
|
||||
m_detailSampleDist, m_detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_GROUND);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
build(geom, builder, cfg, 1, true);
|
||||
build(geom, builder, cfg, 4, true);
|
||||
Build(geom, builder, cfg, 1, true);
|
||||
Build(geom, builder, cfg, 4, true);
|
||||
}
|
||||
|
||||
long t1 = FrequencyWatch.Ticks;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
build(geom, builder, cfg, 1, false);
|
||||
Build(geom, builder, cfg, 1, false);
|
||||
}
|
||||
|
||||
long t2 = FrequencyWatch.Ticks;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
build(geom, builder, cfg, 4, false);
|
||||
Build(geom, builder, cfg, 4, false);
|
||||
}
|
||||
|
||||
long t3 = FrequencyWatch.Ticks;
|
||||
|
@ -124,37 +124,37 @@ public class RecastTileMeshTest
|
|||
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();
|
||||
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)
|
||||
{
|
||||
RecastBuilderResult rcResult = getTile(tiles, 7, 8);
|
||||
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(1));
|
||||
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(5));
|
||||
rcResult = getTile(tiles, 6, 9);
|
||||
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(7));
|
||||
rcResult = getTile(tiles, 2, 9);
|
||||
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(9));
|
||||
rcResult = getTile(tiles, 4, 3);
|
||||
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(3));
|
||||
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(6));
|
||||
rcResult = getTile(tiles, 2, 8);
|
||||
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(5));
|
||||
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(17));
|
||||
rcResult = getTile(tiles, 0, 8);
|
||||
Assert.That(rcResult.getMesh().npolys, Is.EqualTo(6));
|
||||
Assert.That(rcResult.getMesh().nverts, Is.EqualTo(15));
|
||||
RecastBuilderResult rcResult = GetTile(tiles, 7, 8);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5));
|
||||
rcResult = GetTile(tiles, 6, 9);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(7));
|
||||
rcResult = GetTile(tiles, 2, 9);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(9));
|
||||
rcResult = GetTile(tiles, 4, 3);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(3));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(6));
|
||||
rcResult = GetTile(tiles, 2, 8);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(5));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(17));
|
||||
rcResult = GetTile(tiles, 0, 8);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(6));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(15));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
cts.Cancel();
|
||||
//executor.awaitTermination(1000, TimeUnit.HOURS);
|
||||
//executor.AwaitTermination(1000, TimeUnit.HOURS);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue