From 8b07f95ba0df0ceac26eb789473d96610804708e Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Mon, 16 Jan 2023 04:21:17 +0100 Subject: C#: Add float an double overloads to Mathf - Add `float` and `double` overloads to all methods of `Mathf`. This allows the methods to be usable with `float`, `double` or `real_t`. - Use `System.MathF` in the `float` overloads which may result in better performance. - Constants remain as `real_t` for the time being. - Add aggresive inlining for methods that wrap `System.Math` calls. --- .../mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs | 1111 +++++++++++++++++--- .../glue/GodotSharp/GodotSharp/Core/MathfEx.cs | 112 +- 2 files changed, 1050 insertions(+), 173 deletions(-) (limited to 'modules/mono/glue/GodotSharp') diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs index 137a42a6de..ca0032df73 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; namespace Godot { @@ -35,15 +36,18 @@ namespace Godot public const real_t NaN = real_t.NaN; // 0.0174532924f and 0.0174532925199433 - private const real_t _degToRadConst = (real_t)0.0174532925199432957692369077M; + private const float _degToRadConstF = (float)0.0174532925199432957692369077M; + private const double _degToRadConstD = (double)0.0174532925199432957692369077M; // 57.29578f and 57.2957795130823 - private const real_t _radToDegConst = (real_t)57.295779513082320876798154814M; + private const float _radToDegConstF = (float)57.295779513082320876798154814M; + private const double _radToDegConstD = (double)57.295779513082320876798154814M; /// /// Returns the absolute value of (i.e. positive value). /// /// The input number. /// The absolute value of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Abs(int s) { return Math.Abs(s); @@ -54,7 +58,19 @@ namespace Godot /// /// The input number. /// The absolute value of . - public static real_t Abs(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Abs(float s) + { + return Math.Abs(s); + } + + /// + /// Returns the absolute value of (i.e. positive value). + /// + /// The input number. + /// The absolute value of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Abs(double s) { return Math.Abs(s); } @@ -67,9 +83,24 @@ namespace Godot /// /// An angle that would result in the given cosine value. On the range 0 to Tau/2. /// - public static real_t Acos(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Acos(float s) { - return (real_t)Math.Acos(s); + return MathF.Acos(s); + } + + /// + /// Returns the arc cosine of in radians. + /// Use to get the angle of cosine . + /// + /// The input cosine value. Must be on the range of -1.0 to 1.0. + /// + /// An angle that would result in the given cosine value. On the range 0 to Tau/2. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Acos(double s) + { + return Math.Acos(s); } /// @@ -80,9 +111,41 @@ namespace Godot /// /// An angle that would result in the given sine value. On the range -Tau/4 to Tau/4. /// - public static real_t Asin(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Asin(float s) + { + return MathF.Asin(s); + } + + /// + /// Returns the arc sine of in radians. + /// Use to get the angle of sine . + /// + /// The input sine value. Must be on the range of -1.0 to 1.0. + /// + /// An angle that would result in the given sine value. On the range -Tau/4 to Tau/4. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Asin(double s) + { + return Math.Asin(s); + } + + /// + /// Returns the arc tangent of in radians. + /// Use to get the angle of tangent . + /// + /// The method cannot know in which quadrant the angle should fall. + /// See if you have both y and x. + /// + /// The input tangent value. + /// + /// An angle that would result in the given tangent value. On the range -Tau/4 to Tau/4. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Atan(float s) { - return (real_t)Math.Asin(s); + return MathF.Atan(s); } /// @@ -90,15 +153,16 @@ namespace Godot /// Use to get the angle of tangent . /// /// The method cannot know in which quadrant the angle should fall. - /// See if you have both y and x. + /// See if you have both y and x. /// /// The input tangent value. /// /// An angle that would result in the given tangent value. On the range -Tau/4 to Tau/4. /// - public static real_t Atan(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Atan(double s) { - return (real_t)Math.Atan(s); + return Math.Atan(s); } /// @@ -113,9 +177,28 @@ namespace Godot /// /// An angle that would result in the given tangent value. On the range -Tau/2 to Tau/2. /// - public static real_t Atan2(real_t y, real_t x) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Atan2(float y, float x) { - return (real_t)Math.Atan2(y, x); + return MathF.Atan2(y, x); + } + + /// + /// Returns the arc tangent of and in radians. + /// Use to get the angle of the tangent of y/x. To compute the value, the method takes into + /// account the sign of both arguments in order to determine the quadrant. + /// + /// Important note: The Y coordinate comes first, by convention. + /// + /// The Y coordinate of the point to find the angle to. + /// The X coordinate of the point to find the angle to. + /// + /// An angle that would result in the given tangent value. On the range -Tau/2 to Tau/2. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Atan2(double y, double x) + { + return Math.Atan2(y, x); } /// @@ -123,9 +206,21 @@ namespace Godot /// /// The number to ceil. /// The smallest whole number that is not less than . - public static real_t Ceil(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Ceil(float s) { - return (real_t)Math.Ceiling(s); + return MathF.Ceiling(s); + } + + /// + /// Rounds upward (towards positive infinity). + /// + /// The number to ceil. + /// The smallest whole number that is not less than . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Ceil(double s) + { + return Math.Ceiling(s); } /// @@ -136,9 +231,24 @@ namespace Godot /// The minimum allowed value. /// The maximum allowed value. /// The clamped value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Clamp(int value, int min, int max) { - return value < min ? min : value > max ? max : value; + return Math.Clamp(value, min, max); + } + + /// + /// Clamps a so that it is not less than + /// and not more than . + /// + /// The value to clamp. + /// The minimum allowed value. + /// The maximum allowed value. + /// The clamped value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Clamp(float value, float min, float max) + { + return Math.Clamp(value, min, max); } /// @@ -149,9 +259,21 @@ namespace Godot /// The minimum allowed value. /// The maximum allowed value. /// The clamped value. - public static real_t Clamp(real_t value, real_t min, real_t max) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Clamp(double value, double min, double max) + { + return Math.Clamp(value, min, max); + } + + /// + /// Returns the cosine of angle in radians. + /// + /// The angle in radians. + /// The cosine of that angle. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Cos(float s) { - return value < min ? min : value > max ? max : value; + return MathF.Cos(s); } /// @@ -159,9 +281,10 @@ namespace Godot /// /// The angle in radians. /// The cosine of that angle. - public static real_t Cos(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Cos(double s) { - return (real_t)Math.Cos(s); + return Math.Cos(s); } /// @@ -169,9 +292,21 @@ namespace Godot /// /// The angle in radians. /// The hyperbolic cosine of that angle. - public static real_t Cosh(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Cosh(float s) { - return (real_t)Math.Cosh(s); + return MathF.Cosh(s); + } + + /// + /// Returns the hyperbolic cosine of angle in radians. + /// + /// The angle in radians. + /// The hyperbolic cosine of that angle. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Cosh(double s) + { + return Math.Cosh(s); } /// @@ -184,7 +319,7 @@ namespace Godot /// The value which after "to" value for interpolation. /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. /// The resulting value of the interpolation. - public static real_t CubicInterpolate(real_t from, real_t to, real_t pre, real_t post, real_t weight) + public static float CubicInterpolate(float from, float to, float pre, float post, float weight) { return 0.5f * ((from * 2.0f) + @@ -193,10 +328,56 @@ namespace Godot (-pre + 3.0f * from - 3.0f * to + post) * (weight * weight * weight)); } + /// + /// Cubic interpolates between two values by the factor defined in + /// with pre and post values. + /// + /// The start value for interpolation. + /// The destination value for interpolation. + /// The value which before "from" value for interpolation. + /// The value which after "to" value for interpolation. + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// The resulting value of the interpolation. + public static double CubicInterpolate(double from, double to, double pre, double post, double weight) + { + return 0.5 * + ((from * 2.0) + + (-pre + to) * weight + + (2.0 * pre - 5.0 * from + 4.0 * to - post) * (weight * weight) + + (-pre + 3.0 * from - 3.0 * to + post) * (weight * weight * weight)); + } + + /// + /// Cubic interpolates between two rotation values with shortest path + /// by the factor defined in with pre and post values. + /// See also . + /// + /// The start value for interpolation. + /// The destination value for interpolation. + /// The value which before "from" value for interpolation. + /// The value which after "to" value for interpolation. + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// The resulting value of the interpolation. + public static float CubicInterpolateAngle(float from, float to, float pre, float post, float weight) + { + float fromRot = from % MathF.Tau; + + float preDiff = (pre - fromRot) % MathF.Tau; + float preRot = fromRot + (2.0f * preDiff) % MathF.Tau - preDiff; + + float toDiff = (to - fromRot) % MathF.Tau; + float toRot = fromRot + (2.0f * toDiff) % MathF.Tau - toDiff; + + float postDiff = (post - toRot) % MathF.Tau; + float postRot = toRot + (2.0f * postDiff) % MathF.Tau - postDiff; + + return CubicInterpolate(fromRot, toRot, preRot, postRot, weight); + } + /// /// Cubic interpolates between two rotation values with shortest path /// by the factor defined in with pre and post values. - /// See also . + /// See also . /// /// The start value for interpolation. /// The destination value for interpolation. @@ -204,18 +385,18 @@ namespace Godot /// The value which after "to" value for interpolation. /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. /// The resulting value of the interpolation. - public static real_t CubicInterpolateAngle(real_t from, real_t to, real_t pre, real_t post, real_t weight) + public static double CubicInterpolateAngle(double from, double to, double pre, double post, double weight) { - real_t fromRot = from % Mathf.Tau; + double fromRot = from % Math.Tau; - real_t preDiff = (pre - fromRot) % Mathf.Tau; - real_t preRot = fromRot + (2.0f * preDiff) % Mathf.Tau - preDiff; + double preDiff = (pre - fromRot) % Math.Tau; + double preRot = fromRot + (2.0 * preDiff) % Math.Tau - preDiff; - real_t toDiff = (to - fromRot) % Mathf.Tau; - real_t toRot = fromRot + (2.0f * toDiff) % Mathf.Tau - toDiff; + double toDiff = (to - fromRot) % Math.Tau; + double toRot = fromRot + (2.0 * toDiff) % Math.Tau - toDiff; - real_t postDiff = (post - toRot) % Mathf.Tau; - real_t postRot = toRot + (2.0f * postDiff) % Mathf.Tau - postDiff; + double postDiff = (post - toRot) % Math.Tau; + double postRot = toRot + (2.0 * postDiff) % Math.Tau - postDiff; return CubicInterpolate(fromRot, toRot, preRot, postRot, weight); } @@ -223,7 +404,8 @@ namespace Godot /// /// Cubic interpolates between two values by the factor defined in /// with pre and post values. - /// It can perform smoother interpolation than + /// It can perform smoother interpolation than + /// /// by the time values. /// /// The start value for interpolation. @@ -235,23 +417,52 @@ namespace Godot /// /// /// The resulting value of the interpolation. - public static real_t CubicInterpolateInTime(real_t from, real_t to, real_t pre, real_t post, real_t weight, real_t toT, real_t preT, real_t postT) + public static float CubicInterpolateInTime(float from, float to, float pre, float post, float weight, float toT, float preT, float postT) { /* Barry-Goldman method */ - real_t t = Lerp(0.0f, toT, weight); - real_t a1 = Lerp(pre, from, preT == 0 ? 0.0f : (t - preT) / -preT); - real_t a2 = Lerp(from, to, toT == 0 ? 0.5f : t / toT); - real_t a3 = Lerp(to, post, postT - toT == 0 ? 1.0f : (t - toT) / (postT - toT)); - real_t b1 = Lerp(a1, a2, toT - preT == 0 ? 0.0f : (t - preT) / (toT - preT)); - real_t b2 = Lerp(a2, a3, postT == 0 ? 1.0f : t / postT); + float t = Lerp(0.0f, toT, weight); + float a1 = Lerp(pre, from, preT == 0 ? 0.0f : (t - preT) / -preT); + float a2 = Lerp(from, to, toT == 0 ? 0.5f : t / toT); + float a3 = Lerp(to, post, postT - toT == 0 ? 1.0f : (t - toT) / (postT - toT)); + float b1 = Lerp(a1, a2, toT - preT == 0 ? 0.0f : (t - preT) / (toT - preT)); + float b2 = Lerp(a2, a3, postT == 0 ? 1.0f : t / postT); return Lerp(b1, b2, toT == 0 ? 0.5f : t / toT); } + /// + /// Cubic interpolates between two values by the factor defined in + /// with pre and post values. + /// It can perform smoother interpolation than + /// + /// by the time values. + /// + /// The start value for interpolation. + /// The destination value for interpolation. + /// The value which before "from" value for interpolation. + /// The value which after "to" value for interpolation. + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// + /// + /// + /// The resulting value of the interpolation. + public static double CubicInterpolateInTime(double from, double to, double pre, double post, double weight, double toT, double preT, double postT) + { + /* Barry-Goldman method */ + double t = Lerp(0.0, toT, weight); + double a1 = Lerp(pre, from, preT == 0 ? 0.0 : (t - preT) / -preT); + double a2 = Lerp(from, to, toT == 0 ? 0.5 : t / toT); + double a3 = Lerp(to, post, postT - toT == 0 ? 1.0 : (t - toT) / (postT - toT)); + double b1 = Lerp(a1, a2, toT - preT == 0 ? 0.0 : (t - preT) / (toT - preT)); + double b2 = Lerp(a2, a3, postT == 0 ? 1.0 : t / postT); + return Lerp(b1, b2, toT == 0 ? 0.5 : t / toT); + } + /// /// Cubic interpolates between two rotation values with shortest path /// by the factor defined in with pre and post values. - /// See also . - /// It can perform smoother interpolation than + /// See also . + /// It can perform smoother interpolation than + /// /// by the time values. /// /// The start value for interpolation. @@ -263,19 +474,51 @@ namespace Godot /// /// /// The resulting value of the interpolation. - public static real_t CubicInterpolateAngleInTime(real_t from, real_t to, real_t pre, real_t post, real_t weight, - real_t toT, real_t preT, real_t postT) + public static float CubicInterpolateAngleInTime(float from, float to, float pre, float post, float weight, float toT, float preT, float postT) { - real_t fromRot = from % Mathf.Tau; + float fromRot = from % MathF.Tau; - real_t preDiff = (pre - fromRot) % Mathf.Tau; - real_t preRot = fromRot + (2.0f * preDiff) % Mathf.Tau - preDiff; + float preDiff = (pre - fromRot) % MathF.Tau; + float preRot = fromRot + (2.0f * preDiff) % MathF.Tau - preDiff; - real_t toDiff = (to - fromRot) % Mathf.Tau; - real_t toRot = fromRot + (2.0f * toDiff) % Mathf.Tau - toDiff; + float toDiff = (to - fromRot) % MathF.Tau; + float toRot = fromRot + (2.0f * toDiff) % MathF.Tau - toDiff; - real_t postDiff = (post - toRot) % Mathf.Tau; - real_t postRot = toRot + (2.0f * postDiff) % Mathf.Tau - postDiff; + float postDiff = (post - toRot) % MathF.Tau; + float postRot = toRot + (2.0f * postDiff) % MathF.Tau - postDiff; + + return CubicInterpolateInTime(fromRot, toRot, preRot, postRot, weight, toT, preT, postT); + } + + /// + /// Cubic interpolates between two rotation values with shortest path + /// by the factor defined in with pre and post values. + /// See also . + /// It can perform smoother interpolation than + /// + /// by the time values. + /// + /// The start value for interpolation. + /// The destination value for interpolation. + /// The value which before "from" value for interpolation. + /// The value which after "to" value for interpolation. + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// + /// + /// + /// The resulting value of the interpolation. + public static double CubicInterpolateAngleInTime(double from, double to, double pre, double post, double weight, double toT, double preT, double postT) + { + double fromRot = from % Math.Tau; + + double preDiff = (pre - fromRot) % Math.Tau; + double preRot = fromRot + (2.0 * preDiff) % Math.Tau - preDiff; + + double toDiff = (to - fromRot) % Math.Tau; + double toRot = fromRot + (2.0 * toDiff) % Math.Tau - toDiff; + + double postDiff = (post - toRot) % Math.Tau; + double postRot = toRot + (2.0 * postDiff) % Math.Tau - postDiff; return CubicInterpolateInTime(fromRot, toRot, preRot, postRot, weight, toT, preT, postT); } @@ -290,16 +533,38 @@ namespace Godot /// The destination value for the interpolation. /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. /// The resulting value of the interpolation. - public static real_t BezierInterpolate(real_t start, real_t control1, real_t control2, real_t end, real_t t) + public static float BezierInterpolate(float start, float control1, float control2, float end, float t) { // Formula from Wikipedia article on Bezier curves - real_t omt = 1 - t; - real_t omt2 = omt * omt; - real_t omt3 = omt2 * omt; - real_t t2 = t * t; - real_t t3 = t2 * t; + float omt = 1.0f - t; + float omt2 = omt * omt; + float omt3 = omt2 * omt; + float t2 = t * t; + float t3 = t2 * t; - return start * omt3 + control1 * omt2 * t * 3 + control2 * omt * t2 * 3 + end * t3; + return start * omt3 + control1 * omt2 * t * 3.0f + control2 * omt * t2 * 3.0f + end * t3; + } + + /// + /// Returns the point at the given on a one-dimensional Bezier curve defined by + /// the given , , and points. + /// + /// The start value for the interpolation. + /// Control point that defines the bezier curve. + /// Control point that defines the bezier curve. + /// The destination value for the interpolation. + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// The resulting value of the interpolation. + public static double BezierInterpolate(double start, double control1, double control2, double end, double t) + { + // Formula from Wikipedia article on Bezier curves + double omt = 1.0 - t; + double omt2 = omt * omt; + double omt3 = omt2 * omt; + double t2 = t * t; + double t3 = t2 * t; + + return start * omt3 + control1 * omt2 * t * 3.0 + control2 * omt * t2 * 3.0 + end * t3; } /// @@ -312,26 +577,58 @@ namespace Godot /// The destination value for the interpolation. /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. /// The resulting value of the interpolation. - public static real_t BezierDerivative(real_t start, real_t control1, real_t control2, real_t end, real_t t) + public static float BezierDerivative(float start, float control1, float control2, float end, float t) { // Formula from Wikipedia article on Bezier curves - real_t omt = 1 - t; - real_t omt2 = omt * omt; - real_t t2 = t * t; + float omt = 1.0f - t; + float omt2 = omt * omt; + float t2 = t * t; - real_t d = (control1 - start) * 3 * omt2 + (control2 - control1) * 6 * omt * t + (end - control2) * 3 * t2; + float d = (control1 - start) * 3.0f * omt2 + (control2 - control1) * 6.0f * omt * t + (end - control2) * 3.0f * t2; return d; } + /// + /// Returns the derivative at the given on a one dimensional Bezier curve defined by + /// the given , , and points. + /// + /// The start value for the interpolation. + /// Control point that defines the bezier curve. + /// Control point that defines the bezier curve. + /// The destination value for the interpolation. + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// The resulting value of the interpolation. + public static double BezierDerivative(double start, double control1, double control2, double end, double t) + { + // Formula from Wikipedia article on Bezier curves + double omt = 1.0 - t; + double omt2 = omt * omt; + double t2 = t * t; + + double d = (control1 - start) * 3.0 * omt2 + (control2 - control1) * 6.0 * omt * t + (end - control2) * 3.0 * t2; + return d; + } + + /// + /// Converts from decibels to linear energy (audio). + /// + /// + /// Decibels to convert. + /// Audio volume as linear energy. + public static float DbToLinear(float db) + { + return MathF.Exp(db * 0.11512925464970228420089957273422f); + } + /// /// Converts from decibels to linear energy (audio). /// - /// + /// /// Decibels to convert. /// Audio volume as linear energy. - public static real_t DbToLinear(real_t db) + public static double DbToLinear(double db) { - return (real_t)Math.Exp(db * 0.11512925464970228420089957273422); + return Math.Exp(db * 0.11512925464970228420089957273422); } /// @@ -339,9 +636,19 @@ namespace Godot /// /// An angle expressed in degrees. /// The same angle expressed in radians. - public static real_t DegToRad(real_t deg) + public static float DegToRad(float deg) { - return deg * _degToRadConst; + return deg * _degToRadConstF; + } + + /// + /// Converts an angle expressed in degrees to radians. + /// + /// An angle expressed in degrees. + /// The same angle expressed in radians. + public static double DegToRad(double deg) + { + return deg * _degToRadConstD; } /// @@ -354,38 +661,82 @@ namespace Godot /// 0 is constant, 1 is linear, 0 to 1 is ease-in, 1 or more is ease-out. /// /// The eased value. - public static real_t Ease(real_t s, real_t curve) + public static float Ease(float s, float curve) { - if (s < 0f) + if (s < 0.0f) { - s = 0f; + s = 0.0f; } else if (s > 1.0f) { s = 1.0f; } - if (curve > 0f) + if (curve > 0.0f) { if (curve < 1.0f) { - return 1.0f - Pow(1.0f - s, 1.0f / curve); + return 1.0f - MathF.Pow(1.0f - s, 1.0f / curve); } - return Pow(s, curve); + return MathF.Pow(s, curve); } - if (curve < 0f) + if (curve < 0.0f) { if (s < 0.5f) { - return Pow(s * 2.0f, -curve) * 0.5f; + return MathF.Pow(s * 2.0f, -curve) * 0.5f; } - return ((1.0f - Pow(1.0f - ((s - 0.5f) * 2.0f), -curve)) * 0.5f) + 0.5f; + return ((1.0f - MathF.Pow(1.0f - ((s - 0.5f) * 2.0f), -curve)) * 0.5f) + 0.5f; } - return 0f; + return 0.0f; + } + + /// + /// Easing function, based on exponent. The values are: + /// 0 is constant, 1 is linear, 0 to 1 is ease-in, 1 or more is ease-out. + /// Negative values are in-out/out-in. + /// + /// The value to ease. + /// + /// 0 is constant, 1 is linear, 0 to 1 is ease-in, 1 or more is ease-out. + /// + /// The eased value. + public static double Ease(double s, double curve) + { + if (s < 0.0) + { + s = 0.0; + } + else if (s > 1.0) + { + s = 1.0; + } + + if (curve > 0) + { + if (curve < 1.0) + { + return 1.0 - Math.Pow(1.0 - s, 1.0 / curve); + } + + return Math.Pow(s, curve); + } + + if (curve < 0.0) + { + if (s < 0.5) + { + return Math.Pow(s * 2.0, -curve) * 0.5; + } + + return ((1.0 - Math.Pow(1.0 - ((s - 0.5) * 2.0), -curve)) * 0.5) + 0.5; + } + + return 0.0; } /// @@ -394,9 +745,22 @@ namespace Godot /// /// The exponent to raise e to. /// e raised to the power of . - public static real_t Exp(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Exp(float s) { - return (real_t)Math.Exp(s); + return MathF.Exp(s); + } + + /// + /// The natural exponential function. It raises the mathematical + /// constant e to the power of and returns it. + /// + /// The exponent to raise e to. + /// e raised to the power of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Exp(double s) + { + return Math.Exp(s); } /// @@ -404,14 +768,26 @@ namespace Godot /// /// The number to floor. /// The largest whole number that is not more than . - public static real_t Floor(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Floor(float s) { - return (real_t)Math.Floor(s); + return MathF.Floor(s); + } + + /// + /// Rounds downward (towards negative infinity). + /// + /// The number to floor. + /// The largest whole number that is not more than . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Floor(double s) + { + return Math.Floor(s); } /// /// Returns a normalized value considering the given range. - /// This is the opposite of . + /// This is the opposite of . /// /// The start value for interpolation. /// The destination value for interpolation. @@ -421,7 +797,24 @@ namespace Godot /// The returned value will be between 0.0 and 1.0 if is /// between and (inclusive). /// - public static real_t InverseLerp(real_t from, real_t to, real_t weight) + public static float InverseLerp(float from, float to, float weight) + { + return (weight - from) / (to - from); + } + + /// + /// Returns a normalized value considering the given range. + /// This is the opposite of . + /// + /// The start value for interpolation. + /// The destination value for interpolation. + /// The interpolated value. + /// + /// The resulting value of the inverse interpolation. + /// The returned value will be between 0.0 and 1.0 if is + /// between and (inclusive). + /// + public static double InverseLerp(double from, double to, double weight) { return (weight - from) / (to - from); } @@ -434,7 +827,7 @@ namespace Godot /// One of the values. /// The other value. /// A for whether or not the two values are approximately equal. - public static bool IsEqualApprox(real_t a, real_t b) + public static bool IsEqualApprox(float a, float b) { // Check for exact equality first, required to handle "infinity" values. if (a == b) @@ -442,12 +835,48 @@ namespace Godot return true; } // Then check for approximate equality. - real_t tolerance = Epsilon * Abs(a); - if (tolerance < Epsilon) + float tolerance = _epsilonF * Math.Abs(a); + if (tolerance < _epsilonF) { - tolerance = Epsilon; + tolerance = _epsilonF; } - return Abs(a - b) < tolerance; + return Math.Abs(a - b) < tolerance; + } + + /// + /// Returns if and are approximately equal + /// to each other. + /// The comparison is done using a tolerance calculation with . + /// + /// One of the values. + /// The other value. + /// A for whether or not the two values are approximately equal. + public static bool IsEqualApprox(double a, double b) + { + // Check for exact equality first, required to handle "infinity" values. + if (a == b) + { + return true; + } + // Then check for approximate equality. + double tolerance = _epsilonD * Math.Abs(a); + if (tolerance < _epsilonD) + { + tolerance = _epsilonD; + } + return Math.Abs(a - b) < tolerance; + } + + /// + /// Returns whether is a finite value, i.e. it is not + /// , positive infinite, or negative infinity. + /// + /// The value to check. + /// A for whether or not the value is a finite value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsFinite(float s) + { + return float.IsFinite(s); } /// @@ -456,9 +885,21 @@ namespace Godot /// /// The value to check. /// A for whether or not the value is a finite value. - public static bool IsFinite(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsFinite(double s) + { + return double.IsFinite(s); + } + + /// + /// Returns whether is an infinity value (either positive infinity or negative infinity). + /// + /// The value to check. + /// A for whether or not the value is an infinity value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsInf(float s) { - return real_t.IsFinite(s); + return float.IsInfinity(s); } /// @@ -466,44 +907,86 @@ namespace Godot /// /// The value to check. /// A for whether or not the value is an infinity value. - public static bool IsInf(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsInf(double s) + { + return double.IsInfinity(s); + } + + /// + /// Returns whether is a NaN ("Not a Number" or invalid) value. + /// + /// The value to check. + /// A for whether or not the value is a NaN value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNaN(float s) { - return real_t.IsInfinity(s); + return float.IsNaN(s); } /// /// Returns whether is a NaN ("Not a Number" or invalid) value. /// /// The value to check. - /// A for whether or not the value is a NaN value. - public static bool IsNaN(real_t s) + /// A for whether or not the value is a NaN value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNaN(double s) + { + return double.IsNaN(s); + } + + /// + /// Returns if is zero or almost zero. + /// The comparison is done using a tolerance calculation with . + /// + /// This method is faster than using with + /// one value as zero. + /// + /// The value to check. + /// A for whether or not the value is nearly zero. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsZeroApprox(float s) { - return real_t.IsNaN(s); + return Math.Abs(s) < _epsilonF; } /// /// Returns if is zero or almost zero. /// The comparison is done using a tolerance calculation with . /// - /// This method is faster than using with + /// This method is faster than using with /// one value as zero. /// /// The value to check. /// A for whether or not the value is nearly zero. - public static bool IsZeroApprox(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsZeroApprox(double s) + { + return Math.Abs(s) < _epsilonD; + } + + /// + /// Linearly interpolates between two values by a normalized value. + /// This is the opposite . + /// + /// The start value for interpolation. + /// The destination value for interpolation. + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// The resulting value of the interpolation. + public static float Lerp(float from, float to, float weight) { - return Abs(s) < Epsilon; + return from + ((to - from) * weight); } /// /// Linearly interpolates between two values by a normalized value. - /// This is the opposite . + /// This is the opposite . /// /// The start value for interpolation. /// The destination value for interpolation. /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. /// The resulting value of the interpolation. - public static real_t Lerp(real_t from, real_t to, real_t weight) + public static double Lerp(double from, double to, double weight) { return from + ((to - from) * weight); } @@ -511,25 +994,62 @@ namespace Godot /// /// Linearly interpolates between two angles (in radians) by a normalized value. /// - /// Similar to , + /// Similar to , /// but interpolates correctly when the angles wrap around . /// /// The start angle for interpolation. /// The destination angle for interpolation. /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. /// The resulting angle of the interpolation. - public static real_t LerpAngle(real_t from, real_t to, real_t weight) + public static float LerpAngle(float from, float to, float weight) { - real_t difference = (to - from) % Mathf.Tau; - real_t distance = ((2 * difference) % Mathf.Tau) - difference; + float difference = (to - from) % MathF.Tau; + float distance = ((2 * difference) % MathF.Tau) - difference; return from + (distance * weight); } + /// + /// Linearly interpolates between two angles (in radians) by a normalized value. + /// + /// Similar to , + /// but interpolates correctly when the angles wrap around . + /// + /// The start angle for interpolation. + /// The destination angle for interpolation. + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// The resulting angle of the interpolation. + public static double LerpAngle(double from, double to, double weight) + { + double difference = (to - from) % Math.Tau; + double distance = ((2 * difference) % Math.Tau) - difference; + return from + (distance * weight); + } + + /// + /// Converts from linear energy to decibels (audio). + /// This can be used to implement volume sliders that behave as expected (since volume isn't linear). + /// + /// + /// + /// + /// // "slider" refers to a node that inherits Range such as HSlider or VSlider. + /// // Its range must be configured to go from 0 to 1. + /// // Change the bus name if you'd like to change the volume of a specific bus only. + /// AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Master"), GD.LinearToDb(slider.value)); + /// + /// + /// The linear energy to convert. + /// Audio as decibels. + public static float LinearToDb(float linear) + { + return MathF.Log(linear) * 8.6858896380650365530225783783321f; + } + /// /// Converts from linear energy to decibels (audio). /// This can be used to implement volume sliders that behave as expected (since volume isn't linear). /// - /// + /// /// /// /// // "slider" refers to a node that inherits Range such as HSlider or VSlider. @@ -540,9 +1060,22 @@ namespace Godot /// /// The linear energy to convert. /// Audio as decibels. - public static real_t LinearToDb(real_t linear) + public static double LinearToDb(double linear) + { + return Math.Log(linear) * 8.6858896380650365530225783783321; + } + + /// + /// Natural logarithm. The amount of time needed to reach a certain level of continuous growth. + /// + /// Note: This is not the same as the "log" function on most calculators, which uses a base 10 logarithm. + /// + /// The input value. + /// The natural log of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Log(float s) { - return (real_t)(Math.Log(linear) * 8.6858896380650365530225783783321); + return MathF.Log(s); } /// @@ -552,9 +1085,10 @@ namespace Godot /// /// The input value. /// The natural log of . - public static real_t Log(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Log(double s) { - return (real_t)Math.Log(s); + return Math.Log(s); } /// @@ -563,9 +1097,22 @@ namespace Godot /// One of the values. /// The other value. /// Whichever of the two values is higher. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Max(int a, int b) { - return a > b ? a : b; + return Math.Max(a, b); + } + + /// + /// Returns the maximum of two values. + /// + /// One of the values. + /// The other value. + /// Whichever of the two values is higher. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Max(float a, float b) + { + return Math.Max(a, b); } /// @@ -574,9 +1121,10 @@ namespace Godot /// One of the values. /// The other value. /// Whichever of the two values is higher. - public static real_t Max(real_t a, real_t b) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Max(double a, double b) { - return a > b ? a : b; + return Math.Max(a, b); } /// @@ -585,9 +1133,22 @@ namespace Godot /// One of the values. /// The other value. /// Whichever of the two values is lower. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Min(int a, int b) { - return a < b ? a : b; + return Math.Min(a, b); + } + + /// + /// Returns the minimum of two values. + /// + /// One of the values. + /// The other value. + /// Whichever of the two values is lower. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Min(float a, float b) + { + return Math.Min(a, b); } /// @@ -596,9 +1157,27 @@ namespace Godot /// One of the values. /// The other value. /// Whichever of the two values is lower. - public static real_t Min(real_t a, real_t b) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Min(double a, double b) + { + return Math.Min(a, b); + } + + /// + /// Moves toward by the value. + /// + /// Use a negative value to move away. + /// + /// The start value. + /// The value to move towards. + /// The amount to move by. + /// The value after moving. + public static float MoveToward(float from, float to, float delta) { - return a < b ? a : b; + if (Math.Abs(to - from) <= delta) + return to; + + return from + (Math.Sign(to - from) * delta); } /// @@ -610,12 +1189,12 @@ namespace Godot /// The value to move towards. /// The amount to move by. /// The value after moving. - public static real_t MoveToward(real_t from, real_t to, real_t delta) + public static double MoveToward(double from, double to, double delta) { - if (Abs(to - from) <= delta) + if (Math.Abs(to - from) <= delta) return to; - return from + (Sign(to - from) * delta); + return from + (Math.Sign(to - from) * delta); } /// @@ -657,9 +1236,25 @@ namespace Godot /// The dividend, the primary input. /// The divisor. The output is on the range [0, ). /// The resulting output. - public static real_t PosMod(real_t a, real_t b) + public static float PosMod(float a, float b) + { + float c = a % b; + if ((c < 0 && b > 0) || (c > 0 && b < 0)) + { + c += b; + } + return c; + } + + /// + /// Performs a canonical Modulus operation, where the output is on the range [0, ). + /// + /// The dividend, the primary input. + /// The divisor. The output is on the range [0, ). + /// The resulting output. + public static double PosMod(double a, double b) { - real_t c = a % b; + double c = a % b; if ((c < 0 && b > 0) || (c > 0 && b < 0)) { c += b; @@ -673,9 +1268,33 @@ namespace Godot /// The base. /// The exponent. /// raised to the power of . - public static real_t Pow(real_t x, real_t y) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Pow(float x, float y) + { + return MathF.Pow(x, y); + } + + /// + /// Returns the result of raised to the power of . + /// + /// The base. + /// The exponent. + /// raised to the power of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Pow(double x, double y) + { + return Math.Pow(x, y); + } + + /// + /// Converts an angle expressed in radians to degrees. + /// + /// An angle expressed in radians. + /// The same angle expressed in degrees. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float RadToDeg(float rad) { - return (real_t)Math.Pow(x, y); + return rad * _radToDegConstF; } /// @@ -683,9 +1302,25 @@ namespace Godot /// /// An angle expressed in radians. /// The same angle expressed in degrees. - public static real_t RadToDeg(real_t rad) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double RadToDeg(double rad) + { + return rad * _radToDegConstD; + } + + /// + /// Maps a from [, ] + /// to [, ]. + /// + /// The value to map. + /// The start value for the input interpolation. + /// The destination value for the input interpolation. + /// The start value for the output interpolation. + /// The destination value for the output interpolation. + /// The resulting mapped value mapped. + public static float Remap(float value, float inFrom, float inTo, float outFrom, float outTo) { - return rad * _radToDegConst; + return Lerp(outFrom, outTo, InverseLerp(inFrom, inTo, value)); } /// @@ -698,7 +1333,7 @@ namespace Godot /// The start value for the output interpolation. /// The destination value for the output interpolation. /// The resulting mapped value mapped. - public static real_t Remap(real_t value, real_t inFrom, real_t inTo, real_t outFrom, real_t outTo) + public static double Remap(double value, double inFrom, double inTo, double outFrom, double outTo) { return Lerp(outFrom, outTo, InverseLerp(inFrom, inTo, value)); } @@ -709,9 +1344,22 @@ namespace Godot /// /// The number to round. /// The rounded number. - public static real_t Round(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Round(float s) + { + return MathF.Round(s); + } + + /// + /// Rounds to the nearest whole number, + /// with halfway cases rounded towards the nearest multiple of two. + /// + /// The number to round. + /// The rounded number. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Round(double s) { - return (real_t)Math.Round(s); + return Math.Round(s); } /// @@ -720,11 +1368,22 @@ namespace Godot /// /// The input number. /// One of three possible values: 1, -1, or 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Sign(int s) { - if (s == 0) - return 0; - return s < 0 ? -1 : 1; + return Math.Sign(s); + } + + /// + /// Returns the sign of : -1 or 1. + /// Returns 0 if is 0. + /// + /// The input number. + /// One of three possible values: 1, -1, or 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Sign(float s) + { + return Math.Sign(s); } /// @@ -733,11 +1392,21 @@ namespace Godot /// /// The input number. /// One of three possible values: 1, -1, or 0. - public static int Sign(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Sign(double s) + { + return Math.Sign(s); + } + + /// + /// Returns the sine of angle in radians. + /// + /// The angle in radians. + /// The sine of that angle. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Sin(float s) { - if (s == 0) - return 0; - return s < 0 ? -1 : 1; + return MathF.Sin(s); } /// @@ -745,9 +1414,21 @@ namespace Godot /// /// The angle in radians. /// The sine of that angle. - public static real_t Sin(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Sin(double s) + { + return Math.Sin(s); + } + + /// + /// Returns the hyperbolic sine of angle in radians. + /// + /// The angle in radians. + /// The hyperbolic sine of that angle. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Sinh(float s) { - return (real_t)Math.Sin(s); + return MathF.Sinh(s); } /// @@ -755,27 +1436,47 @@ namespace Godot /// /// The angle in radians. /// The hyperbolic sine of that angle. - public static real_t Sinh(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Sinh(double s) + { + return Math.Sinh(s); + } + + /// + /// Returns a number smoothly interpolated between and , + /// based on the . Similar to , + /// but interpolates faster at the beginning and slower at the end. + /// + /// The start value for interpolation. + /// The destination value for interpolation. + /// A value representing the amount of interpolation. + /// The resulting value of the interpolation. + public static float SmoothStep(float from, float to, float weight) { - return (real_t)Math.Sinh(s); + if (IsEqualApprox(from, to)) + { + return from; + } + float x = Math.Clamp((weight - from) / (to - from), 0.0f, 1.0f); + return x * x * (3 - (2 * x)); } /// /// Returns a number smoothly interpolated between and , - /// based on the . Similar to , + /// based on the . Similar to , /// but interpolates faster at the beginning and slower at the end. /// /// The start value for interpolation. /// The destination value for interpolation. /// A value representing the amount of interpolation. /// The resulting value of the interpolation. - public static real_t SmoothStep(real_t from, real_t to, real_t weight) + public static double SmoothStep(double from, double to, double weight) { if (IsEqualApprox(from, to)) { return from; } - real_t x = Clamp((weight - from) / (to - from), (real_t)0.0, (real_t)1.0); + double x = Math.Clamp((weight - from) / (to - from), 0.0, 1.0); return x * x * (3 - (2 * x)); } @@ -786,9 +1487,23 @@ namespace Godot /// /// The input number. Must not be negative. /// The square root of . - public static real_t Sqrt(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Sqrt(float s) + { + return MathF.Sqrt(s); + } + + /// + /// Returns the square root of , where is a non-negative number. + /// + /// If you need negative inputs, use . + /// + /// The input number. Must not be negative. + /// The square root of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Sqrt(double s) { - return (real_t)Math.Sqrt(s); + return Math.Sqrt(s); } /// @@ -798,7 +1513,7 @@ namespace Godot /// /// The input value. /// The position of the first non-zero digit. - public static int StepDecimals(real_t step) + public static int StepDecimals(double step) { double[] sd = new double[] { @@ -812,7 +1527,7 @@ namespace Godot 0.00000009999, 0.000000009999, }; - double abs = Abs(step); + double abs = Math.Abs(step); double decs = abs - (int)abs; // Strip away integer part for (int i = 0; i < sd.Length; i++) { @@ -831,11 +1546,28 @@ namespace Godot /// The value to snap. /// The step size to snap to. /// The snapped value. - public static real_t Snapped(real_t s, real_t step) + public static float Snapped(float s, float step) + { + if (step != 0f) + { + return MathF.Floor((s / step) + 0.5f) * step; + } + + return s; + } + + /// + /// Snaps float value to a given . + /// This can also be used to round a floating point number to an arbitrary number of decimals. + /// + /// The value to snap. + /// The step size to snap to. + /// The snapped value. + public static double Snapped(double s, double step) { if (step != 0f) { - return Floor((s / step) + 0.5f) * step; + return Math.Floor((s / step) + 0.5f) * step; } return s; @@ -846,9 +1578,32 @@ namespace Godot /// /// The angle in radians. /// The tangent of that angle. - public static real_t Tan(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Tan(float s) + { + return MathF.Tan(s); + } + + /// + /// Returns the tangent of angle in radians. + /// + /// The angle in radians. + /// The tangent of that angle. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Tan(double s) + { + return Math.Tan(s); + } + + /// + /// Returns the hyperbolic tangent of angle in radians. + /// + /// The angle in radians. + /// The hyperbolic tangent of that angle. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Tanh(float s) { - return (real_t)Math.Tan(s); + return MathF.Tanh(s); } /// @@ -856,9 +1611,10 @@ namespace Godot /// /// The angle in radians. /// The hyperbolic tangent of that angle. - public static real_t Tanh(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Tanh(double s) { - return (real_t)Math.Tanh(s); + return Math.Tanh(s); } /// @@ -884,15 +1640,15 @@ namespace Godot /// Wraps between and . /// Usable for creating loop-alike behavior or infinite surfaces. /// If is 0, this is equivalent - /// to , so prefer using that instead. + /// to , so prefer using that instead. /// /// The value to wrap. /// The minimum allowed value and lower bound of the range. /// The maximum allowed value and upper bound of the range. /// The wrapped value. - public static real_t Wrap(real_t value, real_t min, real_t max) + public static float Wrap(float value, float min, float max) { - real_t range = max - min; + float range = max - min; if (IsZeroApprox(range)) { return min; @@ -900,9 +1656,43 @@ namespace Godot return min + ((((value - min) % range) + range) % range); } - private static real_t Fract(real_t value) + /// + /// Wraps between and . + /// Usable for creating loop-alike behavior or infinite surfaces. + /// If is 0, this is equivalent + /// to , so prefer using that instead. + /// + /// The value to wrap. + /// The minimum allowed value and lower bound of the range. + /// The maximum allowed value and upper bound of the range. + /// The wrapped value. + public static double Wrap(double value, double min, double max) + { + double range = max - min; + if (IsZeroApprox(range)) + { + return min; + } + return min + ((((value - min) % range) + range) % range); + } + + /// + /// Returns the wrapped between 0 and the . + /// If the limit is reached, the next value the function returned is decreased to the 0 side + /// or increased to the side (like a triangle wave). + /// If is less than zero, it becomes positive. + /// + /// The value to pingpong. + /// The maximum value of the function. + /// The ping-ponged value. + public static float PingPong(float value, float length) { - return value - (real_t)Math.Floor(value); + return (length != 0.0f) ? Math.Abs(Fract((value - length) / (length * 2.0f)) * length * 2.0f - length) : 0.0f; + + static float Fract(float value) + { + return value - MathF.Floor(value); + } } /// @@ -914,9 +1704,14 @@ namespace Godot /// The value to pingpong. /// The maximum value of the function. /// The ping-ponged value. - public static real_t PingPong(real_t value, real_t length) + public static double PingPong(double value, double length) { - return (length != (real_t)0.0) ? Abs(Fract((value - length) / (length * (real_t)2.0)) * length * (real_t)2.0 - length) : (real_t)0.0; + return (length != 0.0) ? Math.Abs(Fract((value - length) / (length * 2.0)) * length * 2.0 - length) : 0.0; + + static double Fract(double value) + { + return value - Math.Floor(value); + } } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs index 72a1868964..cc2d61f58d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs @@ -1,4 +1,8 @@ using System; +using System.Runtime.CompilerServices; + +// This file contains extra members for the Mathf class that aren't part of Godot's Core API. +// Math API that is also part of Core should go into Mathf.cs. namespace Godot { @@ -16,14 +20,18 @@ namespace Godot /// public const real_t Sqrt2 = (real_t)1.4142135623730950488016887242M; // 1.4142136f and 1.414213562373095 + // Epsilon size should depend on the precision used. + private const float _epsilonF = 1e-06f; + private const double _epsilonD = 1e-14; + /// /// A very small number used for float comparison with error tolerance. /// 1e-06 with single-precision floats, but 1e-14 if REAL_T_IS_DOUBLE. /// #if REAL_T_IS_DOUBLE - public const real_t Epsilon = 1e-14; // Epsilon size should depend on the precision used. + public const real_t Epsilon = _epsilonD; #else - public const real_t Epsilon = 1e-06f; + public const real_t Epsilon = _epsilonF; #endif /// @@ -31,7 +39,8 @@ namespace Godot /// /// The input value. /// The amount of digits. - public static int DecimalCount(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int DecimalCount(double s) { return DecimalCount((decimal)s); } @@ -41,6 +50,7 @@ namespace Godot /// /// The input value. /// The amount of digits. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DecimalCount(decimal s) { return BitConverter.GetBytes(decimal.GetBits(s)[3])[2]; @@ -49,11 +59,25 @@ namespace Godot /// /// Rounds upward (towards positive infinity). /// - /// This is the same as , but returns an . + /// This is the same as , but returns an . + /// + /// The number to ceil. + /// The smallest whole number that is not less than . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int CeilToInt(float s) + { + return (int)MathF.Ceiling(s); + } + + /// + /// Rounds upward (towards positive infinity). + /// + /// This is the same as , but returns an . /// /// The number to ceil. /// The smallest whole number that is not less than . - public static int CeilToInt(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int CeilToInt(double s) { return (int)Math.Ceiling(s); } @@ -61,11 +85,25 @@ namespace Godot /// /// Rounds downward (towards negative infinity). /// - /// This is the same as , but returns an . + /// This is the same as , but returns an . + /// + /// The number to floor. + /// The largest whole number that is not more than . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int FloorToInt(float s) + { + return (int)MathF.Floor(s); + } + + /// + /// Rounds downward (towards negative infinity). + /// + /// This is the same as , but returns an . /// /// The number to floor. /// The largest whole number that is not more than . - public static int FloorToInt(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int FloorToInt(double s) { return (int)Math.Floor(s); } @@ -73,11 +111,25 @@ namespace Godot /// /// Rounds to the nearest whole number. /// - /// This is the same as , but returns an . + /// This is the same as , but returns an . /// /// The number to round. /// The rounded number. - public static int RoundToInt(real_t s) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int RoundToInt(float s) + { + return (int)MathF.Round(s); + } + + /// + /// Rounds to the nearest whole number. + /// + /// This is the same as , but returns an . + /// + /// The number to round. + /// The rounded number. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int RoundToInt(double s) { return (int)Math.Round(s); } @@ -87,23 +139,53 @@ namespace Godot /// /// The angle in radians. /// The sine and cosine of that angle. - public static (real_t Sin, real_t Cos) SinCos(real_t s) + public static (float Sin, float Cos) SinCos(float s) + { + return MathF.SinCos(s); + } + + /// + /// Returns the sine and cosine of angle in radians. + /// + /// The angle in radians. + /// The sine and cosine of that angle. + public static (double Sin, double Cos) SinCos(double s) { - (double sin, double cos) = Math.SinCos(s); - return ((real_t)sin, (real_t)cos); + return Math.SinCos(s); + } + + /// + /// Returns if and are approximately + /// equal to each other. + /// The comparison is done using the provided tolerance value. + /// If you want the tolerance to be calculated for you, use . + /// + /// One of the values. + /// The other value. + /// The pre-calculated tolerance value. + /// A for whether or not the two values are equal. + public static bool IsEqualApprox(float a, float b, float tolerance) + { + // Check for exact equality first, required to handle "infinity" values. + if (a == b) + { + return true; + } + // Then check for approximate equality. + return Math.Abs(a - b) < tolerance; } /// /// Returns if and are approximately /// equal to each other. /// The comparison is done using the provided tolerance value. - /// If you want the tolerance to be calculated for you, use . + /// If you want the tolerance to be calculated for you, use . /// /// One of the values. /// The other value. /// The pre-calculated tolerance value. /// A for whether or not the two values are equal. - public static bool IsEqualApprox(real_t a, real_t b, real_t tolerance) + public static bool IsEqualApprox(double a, double b, double tolerance) { // Check for exact equality first, required to handle "infinity" values. if (a == b) @@ -111,7 +193,7 @@ namespace Godot return true; } // Then check for approximate equality. - return Abs(a - b) < tolerance; + return Math.Abs(a - b) < tolerance; } } } -- cgit v1.2.3