272 lines
8.2 KiB
C#
272 lines
8.2 KiB
C#
// Copyright (c) 2013-2015 Robert Rouhani <robert.rouhani@gmail.com> and other contributors (see CONTRIBUTORS file).
|
|
// Licensed under the MIT License - https://raw.github.com/Robmaister/SharpNav/master/LICENSE
|
|
|
|
using SharpNav.Geometry;
|
|
|
|
#if MONOGAME
|
|
using Vector3 = Microsoft.Xna.Framework.Vector3;
|
|
#elif OPENTK
|
|
using Vector3 = OpenTK.Vector3;
|
|
#elif SHARPDX
|
|
using Vector3 = SharpDX.Vector3;
|
|
#endif
|
|
|
|
namespace SharpNav
|
|
{
|
|
/// <summary>
|
|
/// A class where all the small, miscellaneous math functions are stored.
|
|
/// </summary>
|
|
internal static class MathHelper
|
|
{
|
|
/// <summary>
|
|
/// Clamps an integer value to be within a specified range.
|
|
/// </summary>
|
|
/// <param name="val">The value to clamp.</param>
|
|
/// <param name="min">The inclusive minimum of the range.</param>
|
|
/// <param name="max">The inclusive maximum of the range.</param>
|
|
/// <returns>The clamped value.</returns>
|
|
internal static int Clamp(int val, int min, int max)
|
|
{
|
|
return val < min ? min : (val > max ? max : val);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clamps an integer value to be within a specified range.
|
|
/// </summary>
|
|
/// <param name="val">The value to clamp.</param>
|
|
/// <param name="min">The inclusive minimum of the range.</param>
|
|
/// <param name="max">The inclusive maximum of the range.</param>
|
|
internal static void Clamp(ref int val, int min, int max)
|
|
{
|
|
val = val < min ? min : (val > max ? max : val);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clamps an integer value to be within a specified range.
|
|
/// </summary>
|
|
/// <param name="val">The value to clamp.</param>
|
|
/// <param name="min">The inclusive minimum of the range.</param>
|
|
/// <param name="max">The inclusive maximum of the range.</param>
|
|
/// <returns>The clamped value.</returns>
|
|
internal static uint Clamp(uint val, uint min, uint max)
|
|
{
|
|
return val < min ? min : (val > max ? max : val);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clamps an integer value to be within a specified range.
|
|
/// </summary>
|
|
/// <param name="val">The value to clamp.</param>
|
|
/// <param name="min">The inclusive minimum of the range.</param>
|
|
/// <param name="max">The inclusive maximum of the range.</param>
|
|
internal static void Clamp(ref uint val, uint min, uint max)
|
|
{
|
|
val = val < min ? min : (val > max ? max : val);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clamps an integer value to be within a specified range.
|
|
/// </summary>
|
|
/// <param name="val">The value to clamp.</param>
|
|
/// <param name="min">The inclusive minimum of the range.</param>
|
|
/// <param name="max">The inclusive maximum of the range.</param>
|
|
/// <returns>The clamped value.</returns>
|
|
internal static float Clamp(float val, float min, float max)
|
|
{
|
|
return val < min ? min : (val > max ? max : val);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clamps an integer value to be within a specified range.
|
|
/// </summary>
|
|
/// <param name="val">The value to clamp.</param>
|
|
/// <param name="min">The inclusive minimum of the range.</param>
|
|
/// <param name="max">The inclusive maximum of the range.</param>
|
|
internal static void Clamp(ref float val, float min, float max)
|
|
{
|
|
val = val < min ? min : (val > max ? max : val);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Normalizes a value in a specified range to be between 0 and 1.
|
|
/// </summary>
|
|
/// <param name="t">The value</param>
|
|
/// <param name="t0">The lower bound of the range.</param>
|
|
/// <param name="t1">The upper bound of the range.</param>
|
|
/// <returns>A normalized value.</returns>
|
|
public static float Normalize(float t, float t0, float t1)
|
|
{
|
|
return MathHelper.Clamp((t - t0) / (t1 - t0), 0.0f, 1.0f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the next highest power of two.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This is a minimal method meant to be fast. There is a known edge case where an input of 0 will output 0
|
|
/// instead of the mathematically correct value of 1. It will not be fixed.
|
|
/// </remarks>
|
|
/// <param name="v">A value.</param>
|
|
/// <returns>The next power of two after the value.</returns>
|
|
internal static int NextPowerOfTwo(int v)
|
|
{
|
|
v--;
|
|
v |= v >> 1;
|
|
v |= v >> 2;
|
|
v |= v >> 4;
|
|
v |= v >> 8;
|
|
v |= v >> 16;
|
|
v++;
|
|
|
|
return v;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the next highest power of two.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This is a minimal method meant to be fast. There is a known edge case where an input of 0 will output 0
|
|
/// instead of the mathematically correct value of 1. It will not be fixed.
|
|
/// </remarks>
|
|
/// <param name="v">A value.</param>
|
|
/// <returns>The next power of two after the value.</returns>
|
|
internal static uint NextPowerOfTwo(uint v)
|
|
{
|
|
v--;
|
|
v |= v >> 1;
|
|
v |= v >> 2;
|
|
v |= v >> 4;
|
|
v |= v >> 8;
|
|
v |= v >> 16;
|
|
v++;
|
|
|
|
return v;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the binary logarithm of the input.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Inputs 0 and below have undefined output.
|
|
/// </remarks>
|
|
/// <param name="v">A value.</param>
|
|
/// <returns>The binary logarithm of v.</returns>
|
|
internal static int Log2(int v)
|
|
{
|
|
int r;
|
|
int shift;
|
|
|
|
r = (v > 0xffff) ? 1 << 4 : 0 << 4;
|
|
v >>= r;
|
|
|
|
shift = (v > 0xff) ? 1 << 3 : 0 << 3;
|
|
v >>= shift;
|
|
r |= shift;
|
|
|
|
shift = (v > 0xf) ? 1 << 2 : 0 << 2;
|
|
v >>= shift;
|
|
r |= shift;
|
|
|
|
shift = (v > 0x3) ? 1 << 1 : 0 << 1;
|
|
v >>= shift;
|
|
r |= shift;
|
|
|
|
r |= v >> 1;
|
|
|
|
return r;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the binary logarithm of the input.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// An input of 0 has an undefined output.
|
|
/// </remarks>
|
|
/// <param name="v">A value.</param>
|
|
/// <returns>The binary logarithm of v.</returns>
|
|
internal static uint Log2(uint v)
|
|
{
|
|
uint r;
|
|
int shift;
|
|
|
|
r = (uint)((v > 0xffff) ? 1 << 4 : 0 << 4);
|
|
v >>= (int)r;
|
|
|
|
shift = (v > 0xff) ? 1 << 3 : 0 << 3;
|
|
v >>= shift;
|
|
r |= (uint)shift;
|
|
|
|
shift = (v > 0xf) ? 1 << 2 : 0 << 2;
|
|
v >>= shift;
|
|
r |= (uint)shift;
|
|
|
|
shift = (v > 0x3) ? 1 << 1 : 0 << 1;
|
|
v >>= shift;
|
|
r |= (uint)shift;
|
|
|
|
r |= v >> 1;
|
|
|
|
return r;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clips a polygon to a plane using the Sutherland-Hodgman algorithm.
|
|
/// </summary>
|
|
/// <param name="inVertices">The input array of vertices.</param>
|
|
/// <param name="outVertices">The output array of vertices.</param>
|
|
/// <param name="numVerts">The number of vertices to read from the arrays.</param>
|
|
/// <param name="planeX">The clip plane's X component.</param>
|
|
/// <param name="planeZ">The clip plane's Z component.</param>
|
|
/// <param name="planeD">The clip plane's D component.</param>
|
|
/// <returns>The number of vertices stored in outVertices.</returns>
|
|
internal static int ClipPolygonToPlane(Vector3[] inVertices, Vector3[] outVertices, int numVerts, float planeX, float planeZ, float planeD)
|
|
{
|
|
float[] distances = new float[12];
|
|
return ClipPolygonToPlane(inVertices, outVertices, distances, numVerts, planeX, planeZ, planeD);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clips a polygon to a plane using the Sutherland-Hodgman algorithm.
|
|
/// </summary>
|
|
/// <param name="inVertices">The input array of vertices.</param>
|
|
/// <param name="outVertices">The output array of vertices.</param>
|
|
/// <param name="distances">A buffer that stores intermediate data</param>
|
|
/// <param name="numVerts">The number of vertices to read from the arrays.</param>
|
|
/// <param name="planeX">The clip plane's X component.</param>
|
|
/// <param name="planeZ">The clip plane's Z component.</param>
|
|
/// <param name="planeD">The clip plane's D component.</param>
|
|
/// <returns>The number of vertices stored in outVertices.</returns>
|
|
internal static int ClipPolygonToPlane(Vector3[] inVertices, Vector3[] outVertices, float[] distances, int numVerts, float planeX, float planeZ, float planeD)
|
|
{
|
|
for (int i = 0; i < numVerts; i++)
|
|
distances[i] = planeX * inVertices[i].X + planeZ * inVertices[i].Z + planeD;
|
|
|
|
int m = 0;
|
|
Vector3 temp;
|
|
for (int i = 0, j = numVerts - 1; i < numVerts; j = i, i++)
|
|
{
|
|
bool inj = distances[j] >= 0;
|
|
bool ini = distances[i] >= 0;
|
|
|
|
if (inj != ini)
|
|
{
|
|
float s = distances[j] / (distances[j] - distances[i]);
|
|
|
|
Vector3.Subtract(ref inVertices[i], ref inVertices[j], out temp);
|
|
Vector3.Multiply(ref temp, s, out temp);
|
|
Vector3.Add(ref inVertices[j], ref temp, out outVertices[m]);
|
|
m++;
|
|
}
|
|
|
|
if (ini)
|
|
{
|
|
outVertices[m] = inVertices[i];
|
|
m++;
|
|
}
|
|
}
|
|
|
|
return m;
|
|
}
|
|
}
|
|
}
|