// Copyright (c) 2013-2015 Robert Rouhani 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 { /// /// A class where all the small, miscellaneous math functions are stored. /// internal static class MathHelper { /// /// Clamps an integer value to be within a specified range. /// /// The value to clamp. /// The inclusive minimum of the range. /// The inclusive maximum of the range. /// The clamped value. internal static int Clamp(int val, int min, int max) { return val < min ? min : (val > max ? max : val); } /// /// Clamps an integer value to be within a specified range. /// /// The value to clamp. /// The inclusive minimum of the range. /// The inclusive maximum of the range. internal static void Clamp(ref int val, int min, int max) { val = val < min ? min : (val > max ? max : val); } /// /// Clamps an integer value to be within a specified range. /// /// The value to clamp. /// The inclusive minimum of the range. /// The inclusive maximum of the range. /// The clamped value. internal static uint Clamp(uint val, uint min, uint max) { return val < min ? min : (val > max ? max : val); } /// /// Clamps an integer value to be within a specified range. /// /// The value to clamp. /// The inclusive minimum of the range. /// The inclusive maximum of the range. internal static void Clamp(ref uint val, uint min, uint max) { val = val < min ? min : (val > max ? max : val); } /// /// Clamps an integer value to be within a specified range. /// /// The value to clamp. /// The inclusive minimum of the range. /// The inclusive maximum of the range. /// The clamped value. internal static float Clamp(float val, float min, float max) { return val < min ? min : (val > max ? max : val); } /// /// Clamps an integer value to be within a specified range. /// /// The value to clamp. /// The inclusive minimum of the range. /// The inclusive maximum of the range. internal static void Clamp(ref float val, float min, float max) { val = val < min ? min : (val > max ? max : val); } /// /// Normalizes a value in a specified range to be between 0 and 1. /// /// The value /// The lower bound of the range. /// The upper bound of the range. /// A normalized value. public static float Normalize(float t, float t0, float t1) { return MathHelper.Clamp((t - t0) / (t1 - t0), 0.0f, 1.0f); } /// /// Calculates the next highest power of two. /// /// /// 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. /// /// A value. /// The next power of two after the value. 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; } /// /// Calculates the next highest power of two. /// /// /// 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. /// /// A value. /// The next power of two after the value. 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; } /// /// Calculates the binary logarithm of the input. /// /// /// Inputs 0 and below have undefined output. /// /// A value. /// The binary logarithm of v. 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; } /// /// Calculates the binary logarithm of the input. /// /// /// An input of 0 has an undefined output. /// /// A value. /// The binary logarithm of v. 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; } /// /// Clips a polygon to a plane using the Sutherland-Hodgman algorithm. /// /// The input array of vertices. /// The output array of vertices. /// The number of vertices to read from the arrays. /// The clip plane's X component. /// The clip plane's Z component. /// The clip plane's D component. /// The number of vertices stored in outVertices. 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); } /// /// Clips a polygon to a plane using the Sutherland-Hodgman algorithm. /// /// The input array of vertices. /// The output array of vertices. /// A buffer that stores intermediate data /// The number of vertices to read from the arrays. /// The clip plane's X component. /// The clip plane's Z component. /// The clip plane's D component. /// The number of vertices stored in outVertices. 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; } } }