diff --git a/.gitignore b/.gitignore index 9399ea25..8a029402 100644 --- a/.gitignore +++ b/.gitignore @@ -174,6 +174,8 @@ temp/ # Test results produced by build TestResults.xml +output.mlpd +coverage.xml # Nuget outputs nuget/*.nupkg diff --git a/.travis.yml b/.travis.yml index 88b294ad..76cae9fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,3 +7,8 @@ before_install: script: - ./build.sh NuGet + +after_script: + - mono --debug --profile=log:coverage,covfilter=+OpenTK,covfilter=-OpenTK.Tests,covfilter=-FSharp.Core,covfilter=-FsCheck,covfilter=-xunit.assert "packages/xunit.runner.console/tools/xunit.console.exe" "tests/OpenTK.Tests/bin/Release/OpenTK.Tests.dll" -parallel none + - mprof-report --reports=coverage --coverage-out=coverage.xml output.mlpd + - bash <(curl -s https://codecov.io/bash) diff --git a/OpenTK.sln b/OpenTK.sln index a33d8dd6..a57a63b9 100644 --- a/OpenTK.sln +++ b/OpenTK.sln @@ -21,8 +21,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTK.GLWidget", "src\Open EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1857BB8E-1A35-4EBF-9F6D-685F11DC025B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTK.Tests", "tests\OpenTK.Tests\OpenTK.Tests.csproj", "{930A780C-A67C-422F-9EED-DB38DAA47AB0}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.API.Desktop", "tests\Test.API.Desktop\Test.API.Desktop.csproj", "{C4DDD20F-CB4E-43F4-A75C-4A3D668E1F99}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{F1A57014-71CE-4032-A652-01B7E35E14DB}" @@ -38,6 +36,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "project", "project", "{5EEE RELEASE_NOTES.md = RELEASE_NOTES.md EndProjectSection EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "OpenTK.Tests", "tests\OpenTK.Tests\OpenTK.Tests.fsproj", "{6801C263-ADDA-4A7B-979D-649BCB5A1DF7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -76,21 +76,21 @@ Global {A625BE87-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU {A625BE87-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU {A625BE87-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU - {930A780C-A67C-422F-9EED-DB38DAA47AB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {930A780C-A67C-422F-9EED-DB38DAA47AB0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {930A780C-A67C-422F-9EED-DB38DAA47AB0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {930A780C-A67C-422F-9EED-DB38DAA47AB0}.Release|Any CPU.Build.0 = Release|Any CPU {C4DDD20F-CB4E-43F4-A75C-4A3D668E1F99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C4DDD20F-CB4E-43F4-A75C-4A3D668E1F99}.Debug|Any CPU.Build.0 = Debug|Any CPU {C4DDD20F-CB4E-43F4-A75C-4A3D668E1F99}.Release|Any CPU.ActiveCfg = Release|Any CPU {C4DDD20F-CB4E-43F4-A75C-4A3D668E1F99}.Release|Any CPU.Build.0 = Release|Any CPU + {6801C263-ADDA-4A7B-979D-649BCB5A1DF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6801C263-ADDA-4A7B-979D-649BCB5A1DF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6801C263-ADDA-4A7B-979D-649BCB5A1DF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6801C263-ADDA-4A7B-979D-649BCB5A1DF7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {930A780C-A67C-422F-9EED-DB38DAA47AB0} = {1857BB8E-1A35-4EBF-9F6D-685F11DC025B} {C4DDD20F-CB4E-43F4-A75C-4A3D668E1F99} = {1857BB8E-1A35-4EBF-9F6D-685F11DC025B} + {6801C263-ADDA-4A7B-979D-649BCB5A1DF7} = {1857BB8E-1A35-4EBF-9F6D-685F11DC025B} EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = Source\Examples\OpenTK.Examples.csproj diff --git a/build.fsx b/build.fsx index 012efed9..d6bec54e 100644 --- a/build.fsx +++ b/build.fsx @@ -86,8 +86,9 @@ let activeProjects = f -- "**/OpenTK.Android.csproj" -- "**/OpenTK.iOS.csproj" - + !! "src/**/*.??proj" + ++ "tests/**/OpenTK.Tests.fsproj" -- "**/OpenTK.GLWidget.csproj" |> xamarinFilter @@ -194,7 +195,7 @@ Target "All" DoNothing ==> "AssemblyInfo" ==> "Build" ==> "CopyBinaries" -// ==> "RunTests" + ==> "RunTests" ==> "All" "All" diff --git a/paket.dependencies b/paket.dependencies index 5cd789bb..04eab810 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -3,6 +3,7 @@ source https://nuget.org/api/v2 #Open packages nuget FSharp.Formatting +nuget FsCheck nuget FsCheck.Xunit nuget xunit.runner.console nuget xunit.assert diff --git a/src/Generator.Bind/Properties/AssemblyInfo.cs b/src/Generator.Bind/Properties/AssemblyInfo.cs index 9767ed4e..16ced826 100644 --- a/src/Generator.Bind/Properties/AssemblyInfo.cs +++ b/src/Generator.Bind/Properties/AssemblyInfo.cs @@ -11,7 +11,12 @@ using System.Reflection; [assembly: AssemblyCopyrightAttribute("Copyright (c) 2006 - 2016 Stefanos Apostolopoulos for the Open Toolkit library.")] namespace System { internal static class AssemblyVersionInformation { - internal const string Version = "3.0.0"; - internal const string InformationalVersion = "3.0.0"; + internal const System.String AssemblyTitle = "Generator.Bind"; + internal const System.String AssemblyProduct = "OpenTK"; + internal const System.String AssemblyDescription = "A set of fast, low-level C# bindings for OpenGL, OpenGL ES and OpenAL."; + internal const System.String AssemblyVersion = "3.0.0"; + internal const System.String AssemblyFileVersion = "3.0.0"; + internal const System.Boolean CLSCompliant = true; + internal const System.String AssemblyCopyright = "Copyright (c) 2006 - 2016 Stefanos Apostolopoulos for the Open Toolkit library."; } } diff --git a/src/Generator.Converter/Properties/AssemblyInfo.cs b/src/Generator.Converter/Properties/AssemblyInfo.cs index 1adfda08..462df852 100644 --- a/src/Generator.Converter/Properties/AssemblyInfo.cs +++ b/src/Generator.Converter/Properties/AssemblyInfo.cs @@ -11,7 +11,12 @@ using System.Reflection; [assembly: AssemblyCopyrightAttribute("Copyright (c) 2006 - 2016 Stefanos Apostolopoulos for the Open Toolkit library.")] namespace System { internal static class AssemblyVersionInformation { - internal const string Version = "3.0.0"; - internal const string InformationalVersion = "3.0.0"; + internal const System.String AssemblyTitle = "Generator.Convert"; + internal const System.String AssemblyProduct = "OpenTK"; + internal const System.String AssemblyDescription = "A set of fast, low-level C# bindings for OpenGL, OpenGL ES and OpenAL."; + internal const System.String AssemblyVersion = "3.0.0"; + internal const System.String AssemblyFileVersion = "3.0.0"; + internal const System.Boolean CLSCompliant = true; + internal const System.String AssemblyCopyright = "Copyright (c) 2006 - 2016 Stefanos Apostolopoulos for the Open Toolkit library."; } } diff --git a/src/Generator.Rewrite/Program.cs b/src/Generator.Rewrite/Program.cs index dc8bfcf6..4b6f2b8a 100644 --- a/src/Generator.Rewrite/Program.cs +++ b/src/Generator.Rewrite/Program.cs @@ -90,58 +90,65 @@ namespace OpenTK.Rewrite } // Load assembly and process all modules - using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(file, read_params)) + try { - var rewritten = assembly.CustomAttributes.FirstOrDefault(a => a.AttributeType.Name == "RewrittenAttribute"); - if (rewritten == null) + using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(file, read_params)) { - foreach (var module in assembly.Modules) + var rewritten = assembly.CustomAttributes.FirstOrDefault(a => a.AttributeType.Name == "RewrittenAttribute"); + if (rewritten == null) { - foreach (var reference in module.AssemblyReferences) + foreach (var module in assembly.Modules) { - try + foreach (var reference in module.AssemblyReferences) { - var resolved = module.AssemblyResolver.Resolve(reference); - if (reference.Name == "mscorlib") + try { - mscorlib = resolved; + var resolved = module.AssemblyResolver.Resolve(reference); + if (reference.Name == "mscorlib") + { + mscorlib = resolved; + } + } + catch (Exception e) + { + Console.Error.WriteLine(e.ToString()); } } - catch (Exception e) + } + + if (mscorlib == null) + { + Console.Error.WriteLine("Failed to locate mscorlib"); + return; + } + TypeMarshal = mscorlib.MainModule.GetType("System.Runtime.InteropServices.Marshal"); + TypeStringBuilder = mscorlib.MainModule.GetType("System.Text.StringBuilder"); + TypeVoid = mscorlib.MainModule.GetType("System.Void"); + TypeIntPtr = mscorlib.MainModule.GetType("System.IntPtr"); + TypeInt32 = mscorlib.MainModule.GetType("System.Int32"); + + TypeBindingsBase = assembly.Modules.Select(m => m.GetType("OpenTK.BindingsBase")).First(); + + foreach (var module in assembly.Modules) + { + foreach (var type in module.Types) { - Console.Error.WriteLine(e.ToString()); + Rewrite(type, optionsEnumerated); } } } - - if (mscorlib == null) + else { - Console.Error.WriteLine("Failed to locate mscorlib"); - return; + Console.Error.WriteLine("Error: assembly has already been rewritten"); } - TypeMarshal = mscorlib.MainModule.GetType("System.Runtime.InteropServices.Marshal"); - TypeStringBuilder = mscorlib.MainModule.GetType("System.Text.StringBuilder"); - TypeVoid = mscorlib.MainModule.GetType("System.Void"); - TypeIntPtr = mscorlib.MainModule.GetType("System.IntPtr"); - TypeInt32 = mscorlib.MainModule.GetType("System.Int32"); - TypeBindingsBase = assembly.Modules.Select(m => m.GetType("OpenTK.BindingsBase")).First(); - - foreach (var module in assembly.Modules) - { - foreach (var type in module.Types) - { - Rewrite(type, optionsEnumerated); - } - } + // Save rewritten assembly + assembly.Write(write_params); } - else - { - Console.Error.WriteLine("Error: assembly has already been rewritten"); - } - - // Save rewritten assembly - assembly.Write(write_params); + } + catch (InvalidOperationException inex) + { + Console.WriteLine("Failed to load the assembly. It may already have been rewritten, and the debug symbols no longer match."); } } diff --git a/src/Generator.Rewrite/Properties/AssemblyInfo.cs b/src/Generator.Rewrite/Properties/AssemblyInfo.cs index 63a68040..438811f0 100644 --- a/src/Generator.Rewrite/Properties/AssemblyInfo.cs +++ b/src/Generator.Rewrite/Properties/AssemblyInfo.cs @@ -11,7 +11,12 @@ using System.Reflection; [assembly: AssemblyCopyrightAttribute("Copyright (c) 2006 - 2016 Stefanos Apostolopoulos for the Open Toolkit library.")] namespace System { internal static class AssemblyVersionInformation { - internal const string Version = "3.0.0"; - internal const string InformationalVersion = "3.0.0"; + internal const System.String AssemblyTitle = "Generator.Rewrite"; + internal const System.String AssemblyProduct = "OpenTK"; + internal const System.String AssemblyDescription = "A set of fast, low-level C# bindings for OpenGL, OpenGL ES and OpenAL."; + internal const System.String AssemblyVersion = "3.0.0"; + internal const System.String AssemblyFileVersion = "3.0.0"; + internal const System.Boolean CLSCompliant = true; + internal const System.String AssemblyCopyright = "Copyright (c) 2006 - 2016 Stefanos Apostolopoulos for the Open Toolkit library."; } } diff --git a/src/OpenTK.GLControl/Properties/AssemblyInfo.cs b/src/OpenTK.GLControl/Properties/AssemblyInfo.cs index eeeb1acb..a2f2b85c 100644 --- a/src/OpenTK.GLControl/Properties/AssemblyInfo.cs +++ b/src/OpenTK.GLControl/Properties/AssemblyInfo.cs @@ -11,7 +11,12 @@ using System.Reflection; [assembly: AssemblyCopyrightAttribute("Copyright (c) 2006 - 2016 Stefanos Apostolopoulos for the Open Toolkit library.")] namespace System { internal static class AssemblyVersionInformation { - internal const string Version = "3.0.0"; - internal const string InformationalVersion = "3.0.0"; + internal const System.String AssemblyTitle = "OpenTK.GLControl"; + internal const System.String AssemblyProduct = "OpenTK"; + internal const System.String AssemblyDescription = "A set of fast, low-level C# bindings for OpenGL, OpenGL ES and OpenAL."; + internal const System.String AssemblyVersion = "3.0.0"; + internal const System.String AssemblyFileVersion = "3.0.0"; + internal const System.Boolean CLSCompliant = true; + internal const System.String AssemblyCopyright = "Copyright (c) 2006 - 2016 Stefanos Apostolopoulos for the Open Toolkit library."; } } diff --git a/src/OpenTK.GLWidget/OpenTK.GLWidget.csproj b/src/OpenTK.GLWidget/OpenTK.GLWidget.csproj index e71c63a7..91e089ba 100644 --- a/src/OpenTK.GLWidget/OpenTK.GLWidget.csproj +++ b/src/OpenTK.GLWidget/OpenTK.GLWidget.csproj @@ -113,7 +113,7 @@ - + <__paket__GtkSharp_targets>net45\GtkSharp @@ -126,7 +126,7 @@ - + ..\..\packages\GtkSharp\lib\net45\cairo-sharp.dll diff --git a/src/OpenTK.GLWidget/Properties/AssemblyInfo.cs b/src/OpenTK.GLWidget/Properties/AssemblyInfo.cs index 15d61fa4..0db3d7c1 100644 --- a/src/OpenTK.GLWidget/Properties/AssemblyInfo.cs +++ b/src/OpenTK.GLWidget/Properties/AssemblyInfo.cs @@ -11,7 +11,12 @@ using System.Reflection; [assembly: AssemblyCopyrightAttribute("Copyright (c) 2006 - 2016 Stefanos Apostolopoulos for the Open Toolkit library.")] namespace System { internal static class AssemblyVersionInformation { - internal const string Version = "3.0.0"; - internal const string InformationalVersion = "3.0.0"; + internal const System.String AssemblyTitle = "OpenTK.GLWidget"; + internal const System.String AssemblyProduct = "OpenTK"; + internal const System.String AssemblyDescription = "A set of fast, low-level C# bindings for OpenGL, OpenGL ES and OpenAL."; + internal const System.String AssemblyVersion = "3.0.0"; + internal const System.String AssemblyFileVersion = "3.0.0"; + internal const System.Boolean CLSCompliant = true; + internal const System.String AssemblyCopyright = "Copyright (c) 2006 - 2016 Stefanos Apostolopoulos for the Open Toolkit library."; } } diff --git a/src/OpenTK/Math/MathHelper.cs b/src/OpenTK/Math/MathHelper.cs index 81ad33b5..57072e12 100644 --- a/src/OpenTK/Math/MathHelper.cs +++ b/src/OpenTK/Math/MathHelper.cs @@ -3,13 +3,14 @@ * Copyright (c) 2006-2008 the OpenTK Team. * This notice may not be removed from any source distribution. * See license.txt for licensing detailed licensing details. - * + * * Contributions by Andy Gill, James Talton and Georg Wächter. */ #endregion using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Text; namespace OpenTK @@ -326,8 +327,149 @@ namespace OpenTK return Math.Max(Math.Min(n, max), min); } - #endregion + private static unsafe int FloatToInt32Bits(float f) { + return *((int*) &f); + } - #endregion - } + /// + /// Approximates floating point equality with a maximum number of different bits. + /// This is typically used in place of an epsilon comparison. + /// see: https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ + /// see: https://stackoverflow.com/questions/3874627/floating-point-comparison-functions-for-c-sharp + /// + /// the first value to compare + /// >the second value to compare + /// the number of floating point bits to check + /// + public static bool ApproximatelyEqual(float a, float b, int maxDeltaBits) { + // we use longs here, otherwise we run into a two's complement problem, causing this to fail with -2 and 2.0 + long aInt = FloatToInt32Bits(a); + if (aInt < 0) + aInt = Int32.MinValue - aInt; + + long bInt = FloatToInt32Bits(b); + if (bInt < 0) + bInt = Int32.MinValue - bInt; + + long intDiff = Math.Abs(aInt - bInt); + return intDiff <= (1 << maxDeltaBits); + } + + /// + /// Approximates double-precision floating point equality by an epsilon (maximum error) value. + /// This method is designed as a "fits-all" solution and attempts to handle as many cases as possible. + /// + /// The first float. + /// The second float. + /// The maximum error between the two. + /// true if the values are approximately equal within the error margin; otherwise, false. + [SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")] + public static bool ApproximatelyEqualEpsilon(double a, double b, double epsilon) + { + const double doubleNormal = (1L << 52) * double.Epsilon; + double absA = Math.Abs(a); + double absB = Math.Abs(b); + double diff = Math.Abs(a - b); + + if (a == b) + { + // Shortcut, handles infinities + return true; + } + + if (a == 0.0f || b == 0.0f || diff < doubleNormal) + { + // a or b is zero, or both are extremely close to it. + // relative error is less meaningful here + return diff < (epsilon * doubleNormal); + } + + // use relative error + return diff / Math.Min((absA + absB), double.MaxValue) < epsilon; + } + + /// + /// Approximates single-precision floating point equality by an epsilon (maximum error) value. + /// This method is designed as a "fits-all" solution and attempts to handle as many cases as possible. + /// + /// The first float. + /// The second float. + /// The maximum error between the two. + /// true if the values are approximately equal within the error margin; otherwise, false. + [SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")] + public static bool ApproximatelyEqualEpsilon(float a, float b, float epsilon) + { + const float floatNormal = (1 << 23) * float.Epsilon; + float absA = Math.Abs(a); + float absB = Math.Abs(b); + float diff = Math.Abs(a - b); + + if (a == b) + { + // Shortcut, handles infinities + return true; + } + + if (a == 0.0f || b == 0.0f || diff < floatNormal) + { + // a or b is zero, or both are extremely close to it. + // relative error is less meaningful here + return diff < (epsilon * floatNormal); + } + + // use relative error + float relativeError = diff / Math.Min((absA + absB), float.MaxValue); + return relativeError < epsilon; + } + + /// + /// Approximates equivalence between two single-precision floating-point numbers on a direct human scale. + /// It is important to note that this does not approximate equality - instead, it merely checks whether or not + /// two numbers could be considered equivalent to each other within a certain tolerance. The tolerance is + /// inclusive. + /// + /// The first value to compare. + /// The second value to compare· + /// The tolerance within which the two values would be considered equivalent. + /// Whether or not the values can be considered equivalent within the tolerance. + [SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")] + public static bool ApproximatelyEquivalent(float a, float b, float tolerance) + { + if (a == b) + { + // Early bailout, handles infinities + return true; + } + + float diff = Math.Abs(a - b); + return diff <= tolerance; + } + + /// + /// Approximates equivalence between two double-precision floating-point numbers on a direct human scale. + /// It is important to note that this does not approximate equality - instead, it merely checks whether or not + /// two numbers could be considered equivalent to each other within a certain tolerance. The tolerance is + /// inclusive. + /// + /// The first value to compare. + /// The second value to compare· + /// The tolerance within which the two values would be considered equivalent. + /// Whether or not the values can be considered equivalent within the tolerance. + [SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")] + public static bool ApproximatelyEquivalent(double a, double b, double tolerance) + { + if (a == b) + { + // Early bailout, handles infinities + return true; + } + + double diff = Math.Abs(a - b); + return diff <= tolerance; + } + + #endregion + + #endregion + } } diff --git a/src/OpenTK/Math/Vector2.cs b/src/OpenTK/Math/Vector2.cs index d7f81427..19287154 100644 --- a/src/OpenTK/Math/Vector2.cs +++ b/src/OpenTK/Math/Vector2.cs @@ -623,7 +623,8 @@ namespace OpenTK /// Result of the operation. public static void Divide(ref Vector2 vector, float scale, out Vector2 result) { - Multiply(ref vector, 1 / scale, out result); + result.X = vector.X / scale; + result.Y = vector.Y / scale; } /// @@ -654,7 +655,7 @@ namespace OpenTK #region ComponentMin /// - /// Calculate the component-wise minimum of two vectors + /// Returns a vector created from the smallest of the corresponding components of the given vectors. /// /// First operand /// Second operand @@ -667,7 +668,7 @@ namespace OpenTK } /// - /// Calculate the component-wise minimum of two vectors + /// Returns a vector created from the smallest of the corresponding components of the given vectors. /// /// First operand /// Second operand @@ -683,7 +684,7 @@ namespace OpenTK #region ComponentMax /// - /// Calculate the component-wise maximum of two vectors + /// Returns a vector created from the largest of the corresponding components of the given vectors. /// /// First operand /// Second operand @@ -696,7 +697,7 @@ namespace OpenTK } /// - /// Calculate the component-wise maximum of two vectors + /// Returns a vector created from the largest of the corresponding components of the given vectors. /// /// First operand /// Second operand @@ -709,6 +710,64 @@ namespace OpenTK #endregion + #region MagnitudeMin + + /// + /// Returns the Vector2 with the minimum magnitude. If the magnitudes are equal, the second vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The minimum Vector2 + public static Vector2 MagnitudeMin(Vector2 left, Vector2 right) + { + return left.LengthSquared < right.LengthSquared ? left : right; + } + + /// + /// Returns the Vector2 with the minimum magnitude. If the magnitudes are equal, the second vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The magnitude-wise minimum + /// The minimum Vector2 + public static void MagnitudeMin(ref Vector2 left, ref Vector2 right, out Vector2 result) + { + result = left.LengthSquared < right.LengthSquared ? left : right; + } + + #endregion + + #region MagnitudeMax + + /// + /// Returns the Vector2 with the maximum magnitude. If the magnitudes are equal, the first vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The maximum Vector2 + public static Vector2 MagnitudeMax(Vector2 left, Vector2 right) + { + return left.LengthSquared >= right.LengthSquared ? left : right; + } + + /// + /// Returns the Vector2 with the maximum magnitude. If the magnitudes are equal, the first vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The magnitude-wise maximum + /// The maximum Vector2 + public static void MagnitudeMax(ref Vector2 left, ref Vector2 right, out Vector2 result) + { + result = left.LengthSquared >= right.LengthSquared ? left : right; + } + + #endregion + #region Min /// @@ -717,6 +776,7 @@ namespace OpenTK /// Left operand /// Right operand /// The minimum Vector3 + [Obsolete("Use MagnitudeMin() instead.")] public static Vector2 Min(Vector2 left, Vector2 right) { return left.LengthSquared < right.LengthSquared ? left : right; @@ -732,6 +792,7 @@ namespace OpenTK /// Left operand /// Right operand /// The minimum Vector3 + [Obsolete("Use MagnitudeMax() instead.")] public static Vector2 Max(Vector2 left, Vector2 right) { return left.LengthSquared >= right.LengthSquared ? left : right; @@ -1074,7 +1135,7 @@ namespace OpenTK vec.Y *= scale.Y; return vec; } - + /// /// Divides the specified instance by a scalar. /// @@ -1083,9 +1144,8 @@ namespace OpenTK /// Result of the division. public static Vector2 operator /(Vector2 vec, float scale) { - float mult = 1.0f / scale; - vec.X *= mult; - vec.Y *= mult; + vec.X /= scale; + vec.Y /= scale; return vec; } diff --git a/src/OpenTK/Math/Vector2d.cs b/src/OpenTK/Math/Vector2d.cs index 3993aafa..712b4714 100644 --- a/src/OpenTK/Math/Vector2d.cs +++ b/src/OpenTK/Math/Vector2d.cs @@ -541,7 +541,8 @@ namespace OpenTK /// Result of the operation. public static void Divide(ref Vector2d vector, double scale, out Vector2d result) { - Multiply(ref vector, 1 / scale, out result); + result.X = vector.X / scale; + result.Y = vector.Y / scale; } /// @@ -577,6 +578,7 @@ namespace OpenTK /// First operand /// Second operand /// The component-wise minimum + [Obsolete("Use ComponentMin() instead.")] public static Vector2d Min(Vector2d a, Vector2d b) { a.X = a.X < b.X ? a.X : b.X; @@ -590,6 +592,7 @@ namespace OpenTK /// First operand /// Second operand /// The component-wise minimum + [Obsolete("Use ComponentMin() instead.")] public static void Min(ref Vector2d a, ref Vector2d b, out Vector2d result) { result.X = a.X < b.X ? a.X : b.X; @@ -606,6 +609,7 @@ namespace OpenTK /// First operand /// Second operand /// The component-wise maximum + [Obsolete("Use ComponentMax() instead.")] public static Vector2d Max(Vector2d a, Vector2d b) { a.X = a.X > b.X ? a.X : b.X; @@ -619,6 +623,7 @@ namespace OpenTK /// First operand /// Second operand /// The component-wise maximum + [Obsolete("Use ComponentMax() instead.")] public static void Max(ref Vector2d a, ref Vector2d b, out Vector2d result) { result.X = a.X > b.X ? a.X : b.X; @@ -627,6 +632,122 @@ namespace OpenTK #endregion + #region ComponentMin + + /// + /// Returns a vector created from the smallest of the corresponding components of the given vectors. + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static Vector2d ComponentMin(Vector2d a, Vector2d b) + { + a.X = a.X < b.X ? a.X : b.X; + a.Y = a.Y < b.Y ? a.Y : b.Y; + return a; + } + + /// + /// Returns a vector created from the smallest of the corresponding components of the given vectors. + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static void ComponentMin(ref Vector2d a, ref Vector2d b, out Vector2d result) + { + result.X = a.X < b.X ? a.X : b.X; + result.Y = a.Y < b.Y ? a.Y : b.Y; + } + + #endregion + + #region ComponentMax + + /// + /// Returns a vector created from the largest of the corresponding components of the given vectors. + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static Vector2d ComponentMax(Vector2d a, Vector2d b) + { + a.X = a.X > b.X ? a.X : b.X; + a.Y = a.Y > b.Y ? a.Y : b.Y; + return a; + } + + /// + /// Returns a vector created from the largest of the corresponding components of the given vectors. + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static void ComponentMax(ref Vector2d a, ref Vector2d b, out Vector2d result) + { + result.X = a.X > b.X ? a.X : b.X; + result.Y = a.Y > b.Y ? a.Y : b.Y; + } + + #endregion + + #region MagnitudeMin + + /// + /// Returns the Vector2d with the minimum magnitude. If the magnitudes are equal, the second vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The minimum Vector2d + public static Vector2d MagnitudeMin(Vector2d left, Vector2d right) + { + return left.LengthSquared < right.LengthSquared ? left : right; + } + + /// + /// Returns the Vector2d with the minimum magnitude. If the magnitudes are equal, the second vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The magnitude-wise minimum + /// The minimum Vector2d + public static void MagnitudeMin(ref Vector2d left, ref Vector2d right, out Vector2d result) + { + result = left.LengthSquared < right.LengthSquared ? left : right; + } + + #endregion + + #region MagnitudeMax + + /// + /// Returns the Vector2d with the minimum magnitude. If the magnitudes are equal, the first vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The minimum Vector2d + public static Vector2d MagnitudeMax(Vector2d left, Vector2d right) + { + return left.LengthSquared >= right.LengthSquared ? left : right; + } + + /// + /// Returns the Vector2d with the maximum magnitude. If the magnitudes are equal, the first vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The magnitude-wise maximum + /// The maximum Vector2d + public static void MagnitudeMax(ref Vector2d left, ref Vector2d right, out Vector2d result) + { + result = left.LengthSquared >= right.LengthSquared ? left : right; + } + + #endregion + #region Clamp /// @@ -936,7 +1057,7 @@ namespace OpenTK vec.Y *= scale.Y; return vec; } - + /// /// Divides an instance by a scalar. /// @@ -945,9 +1066,8 @@ namespace OpenTK /// The result of the operation. public static Vector2d operator /(Vector2d vec, double f) { - double mult = 1.0 / f; - vec.X *= mult; - vec.Y *= mult; + vec.X /= f; + vec.Y /= f; return vec; } diff --git a/src/OpenTK/Math/Vector3.cs b/src/OpenTK/Math/Vector3.cs index 000a3698..510ae63e 100644 --- a/src/OpenTK/Math/Vector3.cs +++ b/src/OpenTK/Math/Vector3.cs @@ -629,7 +629,9 @@ namespace OpenTK /// Result of the operation. public static void Divide(ref Vector3 vector, float scale, out Vector3 result) { - Multiply(ref vector, 1 / scale, out result); + result.X = vector.X / scale; + result.Y = vector.Y / scale; + result.Z = vector.Z / scale; } /// @@ -660,7 +662,7 @@ namespace OpenTK #region ComponentMin /// - /// Calculate the component-wise minimum of two vectors + /// Returns a vector created from the smallest of the corresponding components of the given vectors. /// /// First operand /// Second operand @@ -674,7 +676,7 @@ namespace OpenTK } /// - /// Calculate the component-wise minimum of two vectors + /// Returns a vector created from the smallest of the corresponding components of the given vectors. /// /// First operand /// Second operand @@ -691,7 +693,7 @@ namespace OpenTK #region ComponentMax /// - /// Calculate the component-wise maximum of two vectors + /// Returns a vector created from the largest of the corresponding components of the given vectors. /// /// First operand /// Second operand @@ -705,7 +707,7 @@ namespace OpenTK } /// - /// Calculate the component-wise maximum of two vectors + /// Returns a vector created from the largest of the corresponding components of the given vectors. /// /// First operand /// Second operand @@ -719,6 +721,64 @@ namespace OpenTK #endregion + #region MagnitudeMin + + /// + /// Returns the Vector3 with the minimum magnitude. If the magnitudes are equal, the second vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The minimum Vector3 + public static Vector3 MagnitudeMin(Vector3 left, Vector3 right) + { + return left.LengthSquared < right.LengthSquared ? left : right; + } + + /// + /// Returns the Vector3 with the minimum magnitude. If the magnitudes are equal, the second vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The magnitude-wise minimum + /// The minimum Vector3 + public static void MagnitudeMin(ref Vector3 left, ref Vector3 right, out Vector3 result) + { + result = left.LengthSquared < right.LengthSquared ? left : right; + } + + #endregion + + #region MagnitudeMax + + /// + /// Returns the Vector3 with the maximum magnitude. If the magnitudes are equal, the first vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The maximum Vector3 + public static Vector3 MagnitudeMax(Vector3 left, Vector3 right) + { + return left.LengthSquared >= right.LengthSquared ? left : right; + } + + /// + /// Returns the Vector3 with the maximum magnitude. If the magnitudes are equal, the first vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The magnitude-wise maximum + /// The maximum Vector3 + public static void MagnitudeMax(ref Vector3 left, ref Vector3 right, out Vector3 result) + { + result = left.LengthSquared >= right.LengthSquared ? left : right; + } + + #endregion + #region Min /// @@ -727,6 +787,7 @@ namespace OpenTK /// Left operand /// Right operand /// The minimum Vector3 + [Obsolete("Use MagnitudeMin() instead.")] public static Vector3 Min(Vector3 left, Vector3 right) { return left.LengthSquared < right.LengthSquared ? left : right; @@ -742,6 +803,7 @@ namespace OpenTK /// Left operand /// Right operand /// The minimum Vector3 + [Obsolete("Use MagnitudeMax() instead.")] public static Vector3 Max(Vector3 left, Vector3 right) { return left.LengthSquared >= right.LengthSquared ? left : right; @@ -1270,10 +1332,10 @@ namespace OpenTK { Vector4 result; - result.X = - vector.X * worldViewProjection.M11 + - vector.Y * worldViewProjection.M21 + - vector.Z * worldViewProjection.M31 + + result.X = + vector.X * worldViewProjection.M11 + + vector.Y * worldViewProjection.M21 + + vector.Z * worldViewProjection.M31 + worldViewProjection.M41; result.Y = @@ -1574,10 +1636,9 @@ namespace OpenTK /// The result of the calculation. public static Vector3 operator /(Vector3 vec, float scale) { - float mult = 1.0f / scale; - vec.X *= mult; - vec.Y *= mult; - vec.Z *= mult; + vec.X /= scale; + vec.Y /= scale; + vec.Z /= scale; return vec; } diff --git a/src/OpenTK/Math/Vector3d.cs b/src/OpenTK/Math/Vector3d.cs index 556b9ab9..aab85e7d 100644 --- a/src/OpenTK/Math/Vector3d.cs +++ b/src/OpenTK/Math/Vector3d.cs @@ -627,7 +627,9 @@ namespace OpenTK /// Result of the operation. public static void Divide(ref Vector3d vector, double scale, out Vector3d result) { - Multiply(ref vector, 1 / scale, out result); + result.X = vector.X / scale; + result.Y = vector.Y / scale; + result.Z = vector.Z / scale; } /// @@ -658,7 +660,7 @@ namespace OpenTK #region ComponentMin /// - /// Calculate the component-wise minimum of two vectors + /// Returns a vector created from the smallest of the corresponding components of the given vectors. /// /// First operand /// Second operand @@ -672,7 +674,7 @@ namespace OpenTK } /// - /// Calculate the component-wise minimum of two vectors + /// Returns a vector created from the smallest of the corresponding components of the given vectors. /// /// First operand /// Second operand @@ -689,7 +691,7 @@ namespace OpenTK #region ComponentMax /// - /// Calculate the component-wise maximum of two vectors + /// Returns a vector created from the largest of the corresponding components of the given vectors. /// /// First operand /// Second operand @@ -703,7 +705,7 @@ namespace OpenTK } /// - /// Calculate the component-wise maximum of two vectors + /// Returns a vector created from the largest of the corresponding components of the given vectors. /// /// First operand /// Second operand @@ -717,6 +719,60 @@ namespace OpenTK #endregion + #region MagnitudeMin + + /// + /// Returns the Vector3d with the minimum magnitude + /// + /// Left operand + /// Right operand + /// The minimum Vector3d + public static Vector3d MagnitudeMin(Vector3d left, Vector3d right) + { + return left.LengthSquared < right.LengthSquared ? left : right; + } + + /// + /// Returns the Vector3d with the minimum magnitude + /// + /// Left operand + /// Right operand + /// The magnitude-wise minimum + /// The minimum Vector3d + public static void MagnitudeMin(ref Vector3d left, ref Vector3d right, out Vector3d result) + { + result = left.LengthSquared < right.LengthSquared ? left : right; + } + + #endregion + + #region MagnitudeMax + + /// + /// Returns the Vector3d with the minimum magnitude + /// + /// Left operand + /// Right operand + /// The minimum Vector3d + public static Vector3d MagnitudeMax(Vector3d left, Vector3d right) + { + return left.LengthSquared >= right.LengthSquared ? left : right; + } + + /// + /// Returns the Vector3d with the maximum magnitude + /// + /// Left operand + /// Right operand + /// The magnitude-wise maximum + /// The maximum Vector3d + public static void MagnitudeMax(ref Vector3d left, ref Vector3d right, out Vector3d result) + { + result = left.LengthSquared >= right.LengthSquared ? left : right; + } + + #endregion + #region Min /// @@ -725,6 +781,7 @@ namespace OpenTK /// Left operand /// Right operand /// The minimum Vector3 + [Obsolete("Use MagnitudeMin() instead.")] public static Vector3d Min(Vector3d left, Vector3d right) { return left.LengthSquared < right.LengthSquared ? left : right; @@ -740,6 +797,7 @@ namespace OpenTK /// Left operand /// Right operand /// The minimum Vector3 + [Obsolete("Use MagnitudeMax() instead.")] public static Vector3d Max(Vector3d left, Vector3d right) { return left.LengthSquared >= right.LengthSquared ? left : right; @@ -1372,7 +1430,7 @@ namespace OpenTK vec.Z *= scale; return vec; } - + /// /// Component-wise multiplication between the specified instance by a scale vector. /// @@ -1386,7 +1444,7 @@ namespace OpenTK vec.Z *= scale.Z; return vec; } - + /// /// Divides an instance by a scalar. /// @@ -1395,10 +1453,9 @@ namespace OpenTK /// The result of the calculation. public static Vector3d operator /(Vector3d vec, double scale) { - double mult = 1 / scale; - vec.X *= mult; - vec.Y *= mult; - vec.Z *= mult; + vec.X /= scale; + vec.Y /= scale; + vec.Z /= scale; return vec; } diff --git a/src/OpenTK/Math/Vector4.cs b/src/OpenTK/Math/Vector4.cs index a821031e..42dc6beb 100644 --- a/src/OpenTK/Math/Vector4.cs +++ b/src/OpenTK/Math/Vector4.cs @@ -514,11 +514,10 @@ namespace OpenTK /// Result of the division public static Vector4 Div(Vector4 a, float f) { - float mult = 1.0f / f; - a.X *= mult; - a.Y *= mult; - a.Z *= mult; - a.W *= mult; + a.X /= f; + a.Y /= f; + a.Z /= f; + a.W /= f; return a; } @@ -530,11 +529,10 @@ namespace OpenTK /// Result of the division public static void Div(ref Vector4 a, float f, out Vector4 result) { - float mult = 1.0f / f; - result.X = a.X * mult; - result.Y = a.Y * mult; - result.Z = a.Z * mult; - result.W = a.W * mult; + result.X = a.X / f; + result.Y = a.Y / f; + result.Z = a.Z / f; + result.W = a.W / f; } #endregion @@ -667,7 +665,10 @@ namespace OpenTK /// Result of the operation. public static void Divide(ref Vector4 vector, float scale, out Vector4 result) { - Multiply(ref vector, 1 / scale, out result); + result.X = vector.X / scale; + result.Y = vector.Y / scale; + result.Z = vector.Z / scale; + result.W = vector.W / scale; } /// @@ -703,6 +704,7 @@ namespace OpenTK /// First operand /// Second operand /// The component-wise minimum + [Obsolete("Use ComponentMin() instead.")] public static Vector4 Min(Vector4 a, Vector4 b) { a.X = a.X < b.X ? a.X : b.X; @@ -718,6 +720,7 @@ namespace OpenTK /// First operand /// Second operand /// The component-wise minimum + [Obsolete("Use ComponentMin() instead.")] public static void Min(ref Vector4 a, ref Vector4 b, out Vector4 result) { result.X = a.X < b.X ? a.X : b.X; @@ -736,6 +739,7 @@ namespace OpenTK /// First operand /// Second operand /// The component-wise maximum + [Obsolete("Use ComponentMax() instead.")] public static Vector4 Max(Vector4 a, Vector4 b) { a.X = a.X > b.X ? a.X : b.X; @@ -751,6 +755,7 @@ namespace OpenTK /// First operand /// Second operand /// The component-wise maximum + [Obsolete("Use ComponentMax() instead.")] public static void Max(ref Vector4 a, ref Vector4 b, out Vector4 result) { result.X = a.X > b.X ? a.X : b.X; @@ -761,6 +766,130 @@ namespace OpenTK #endregion + #region ComponentMin + + /// + /// Returns a vector created from the smallest of the corresponding components of the given vectors. + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static Vector4 ComponentMin(Vector4 a, Vector4 b) + { + a.X = a.X < b.X ? a.X : b.X; + a.Y = a.Y < b.Y ? a.Y : b.Y; + a.Z = a.Z < b.Z ? a.Z : b.Z; + a.W = a.W < b.W ? a.W : b.W; + return a; + } + + /// + /// Returns a vector created from the smallest of the corresponding components of the given vectors. + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static void ComponentMin(ref Vector4 a, ref Vector4 b, out Vector4 result) + { + result.X = a.X < b.X ? a.X : b.X; + result.Y = a.Y < b.Y ? a.Y : b.Y; + result.Z = a.Z < b.Z ? a.Z : b.Z; + result.W = a.W < b.W ? a.W : b.W; + } + + #endregion + + #region ComponentMax + + /// + /// Returns a vector created from the largest of the corresponding components of the given vectors. + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static Vector4 ComponentMax(Vector4 a, Vector4 b) + { + a.X = a.X > b.X ? a.X : b.X; + a.Y = a.Y > b.Y ? a.Y : b.Y; + a.Z = a.Z > b.Z ? a.Z : b.Z; + a.W = a.W > b.W ? a.W : b.W; + return a; + } + + /// + /// Returns a vector created from the largest of the corresponding components of the given vectors. + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static void ComponentMax(ref Vector4 a, ref Vector4 b, out Vector4 result) + { + result.X = a.X > b.X ? a.X : b.X; + result.Y = a.Y > b.Y ? a.Y : b.Y; + result.Z = a.Z > b.Z ? a.Z : b.Z; + result.W = a.W > b.W ? a.W : b.W; + } + + #endregion + + #region MagnitudeMin + + /// + /// Returns the Vector4 with the minimum magnitude. If the magnitudes are equal, the second vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The minimum Vector4 + public static Vector4 MagnitudeMin(Vector4 left, Vector4 right) + { + return left.LengthSquared < right.LengthSquared ? left : right; + } + + /// + /// Returns the Vector4 with the minimum magnitude. If the magnitudes are equal, the second vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The magnitude-wise minimum + /// The minimum Vector4 + public static void MagnitudeMin(ref Vector4 left, ref Vector4 right, out Vector4 result) + { + result = left.LengthSquared < right.LengthSquared ? left : right; + } + + #endregion + + #region MagnitudeMax + + /// + /// Returns the Vector4 with the maximum magnitude. If the magnitudes are equal, the first vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The maximum Vector4 + public static Vector4 MagnitudeMax(Vector4 left, Vector4 right) + { + return left.LengthSquared >= right.LengthSquared ? left : right; + } + + /// + /// Returns the Vector4 with the maximum magnitude. If the magnitudes are equal, the first vector + /// is selected. + /// + /// Left operand + /// Right operand + /// The magnitude-wise maximum + /// The maximum Vector4 + public static void MagnitudeMax(ref Vector4 left, ref Vector4 right, out Vector4 result) + { + result = left.LengthSquared >= right.LengthSquared ? left : right; + } + + #endregion + #region Clamp /// @@ -774,8 +903,8 @@ namespace OpenTK { vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; - vec.Z = vec.X < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z; - vec.W = vec.Y < min.W ? min.W : vec.W > max.W ? max.W : vec.W; + vec.Z = vec.Z < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z; + vec.W = vec.W < min.W ? min.W : vec.W > max.W ? max.W : vec.W; return vec; } @@ -790,8 +919,8 @@ namespace OpenTK { result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; - result.Z = vec.X < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z; - result.W = vec.Y < min.W ? min.W : vec.W > max.W ? max.W : vec.W; + result.Z = vec.Z < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z; + result.W = vec.W < min.W ? min.W : vec.W > max.W ? max.W : vec.W; } #endregion @@ -1514,7 +1643,7 @@ namespace OpenTK vec.W *= scale; return vec; } - + /// /// Component-wise multiplication between the specified instance by a scale vector. /// @@ -1577,11 +1706,10 @@ namespace OpenTK /// The result of the calculation. public static Vector4 operator /(Vector4 vec, float scale) { - float mult = 1.0f / scale; - vec.X *= mult; - vec.Y *= mult; - vec.Z *= mult; - vec.W *= mult; + vec.X /= scale; + vec.Y /= scale; + vec.Z /= scale; + vec.W /= scale; return vec; } diff --git a/src/OpenTK/Math/Vector4d.cs b/src/OpenTK/Math/Vector4d.cs index facc329d..bed7aa1c 100644 --- a/src/OpenTK/Math/Vector4d.cs +++ b/src/OpenTK/Math/Vector4d.cs @@ -175,7 +175,7 @@ namespace OpenTK #endregion #region Public Members - + /// /// Gets or sets the value at the index of the Vector. /// @@ -669,7 +669,10 @@ namespace OpenTK /// Result of the operation. public static void Divide(ref Vector4d vector, double scale, out Vector4d result) { - Multiply(ref vector, 1 / scale, out result); + result.X = vector.X / scale; + result.Y = vector.Y / scale; + result.Z = vector.Z / scale; + result.W = vector.W / scale; } /// @@ -705,6 +708,7 @@ namespace OpenTK /// First operand /// Second operand /// The component-wise minimum + [Obsolete("Use ComponentMin() instead.")] public static Vector4d Min(Vector4d a, Vector4d b) { a.X = a.X < b.X ? a.X : b.X; @@ -720,6 +724,7 @@ namespace OpenTK /// First operand /// Second operand /// The component-wise minimum + [Obsolete("Use ComponentMin() instead.")] public static void Min(ref Vector4d a, ref Vector4d b, out Vector4d result) { result.X = a.X < b.X ? a.X : b.X; @@ -738,6 +743,7 @@ namespace OpenTK /// First operand /// Second operand /// The component-wise maximum + [Obsolete("Use ComponentMax() instead.")] public static Vector4d Max(Vector4d a, Vector4d b) { a.X = a.X > b.X ? a.X : b.X; @@ -753,6 +759,7 @@ namespace OpenTK /// First operand /// Second operand /// The component-wise maximum + [Obsolete("Use ComponentMax() instead.")] public static void Max(ref Vector4d a, ref Vector4d b, out Vector4d result) { result.X = a.X > b.X ? a.X : b.X; @@ -763,6 +770,126 @@ namespace OpenTK #endregion + #region ComponentMin + + /// + /// Returns a vector created from the smallest of the corresponding components of the given vectors. + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static Vector4d ComponentMin(Vector4d a, Vector4d b) + { + a.X = a.X < b.X ? a.X : b.X; + a.Y = a.Y < b.Y ? a.Y : b.Y; + a.Z = a.Z < b.Z ? a.Z : b.Z; + a.W = a.W < b.W ? a.W : b.W; + return a; + } + + /// + /// Returns a vector created from the smallest of the corresponding components of the given vectors. + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static void ComponentMin(ref Vector4d a, ref Vector4d b, out Vector4d result) + { + result.X = a.X < b.X ? a.X : b.X; + result.Y = a.Y < b.Y ? a.Y : b.Y; + result.Z = a.Z < b.Z ? a.Z : b.Z; + result.W = a.W < b.W ? a.W : b.W; + } + + #endregion + + #region ComponentMax + + /// + /// Returns a vector created from the largest of the corresponding components of the given vectors. + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static Vector4d ComponentMax(Vector4d a, Vector4d b) + { + a.X = a.X > b.X ? a.X : b.X; + a.Y = a.Y > b.Y ? a.Y : b.Y; + a.Z = a.Z > b.Z ? a.Z : b.Z; + a.W = a.W > b.W ? a.W : b.W; + return a; + } + + /// + /// Returns a vector created from the largest of the corresponding components of the given vectors. + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static void ComponentMax(ref Vector4d a, ref Vector4d b, out Vector4d result) + { + result.X = a.X > b.X ? a.X : b.X; + result.Y = a.Y > b.Y ? a.Y : b.Y; + result.Z = a.Z > b.Z ? a.Z : b.Z; + result.W = a.W > b.W ? a.W : b.W; + } + + #endregion + + #region MagnitudeMin + + /// + /// Returns the Vector4d with the minimum magnitude + /// + /// Left operand + /// Right operand + /// The minimum Vector4d + public static Vector4d MagnitudeMin(Vector4d left, Vector4d right) + { + return left.LengthSquared < right.LengthSquared ? left : right; + } + + /// + /// Returns the Vector4d with the minimum magnitude + /// + /// Left operand + /// Right operand + /// The magnitude-wise minimum + /// The minimum Vector4d + public static void MagnitudeMin(ref Vector4d left, ref Vector4d right, out Vector4d result) + { + result = left.LengthSquared < right.LengthSquared ? left : right; + } + + #endregion + + #region MagnitudeMax + + /// + /// Returns the Vector4d with the minimum magnitude + /// + /// Left operand + /// Right operand + /// The minimum Vector4d + public static Vector4d MagnitudeMax(Vector4d left, Vector4d right) + { + return left.LengthSquared >= right.LengthSquared ? left : right; + } + + /// + /// Returns the Vector4d with the maximum magnitude + /// + /// Left operand + /// Right operand + /// The magnitude-wise maximum + /// The maximum Vector4d + public static void MagnitudeMax(ref Vector4d left, ref Vector4d right, out Vector4d result) + { + result = left.LengthSquared >= right.LengthSquared ? left : right; + } + + #endregion + #region Clamp /// @@ -1493,7 +1620,7 @@ namespace OpenTK vec.W *= scale; return vec; } - + /// /// Component-wise multiplication between the specified instance by a scale vector. /// @@ -1517,11 +1644,10 @@ namespace OpenTK /// The result of the calculation. public static Vector4d operator /(Vector4d vec, double scale) { - double mult = 1 / scale; - vec.X *= mult; - vec.Y *= mult; - vec.Z *= mult; - vec.W *= mult; + vec.X /= scale; + vec.Y /= scale; + vec.Z /= scale; + vec.W /= scale; return vec; } diff --git a/src/OpenTK/Properties/AssemblyInfo.cs b/src/OpenTK/Properties/AssemblyInfo.cs index e6e2009c..f0d6b897 100644 --- a/src/OpenTK/Properties/AssemblyInfo.cs +++ b/src/OpenTK/Properties/AssemblyInfo.cs @@ -11,7 +11,12 @@ using System.Reflection; [assembly: AssemblyCopyrightAttribute("Copyright (c) 2006 - 2016 Stefanos Apostolopoulos for the Open Toolkit library.")] namespace System { internal static class AssemblyVersionInformation { - internal const string Version = "3.0.0"; - internal const string InformationalVersion = "3.0.0"; + internal const System.String AssemblyTitle = "OpenTK"; + internal const System.String AssemblyProduct = "OpenTK"; + internal const System.String AssemblyDescription = "A set of fast, low-level C# bindings for OpenGL, OpenGL ES and OpenAL."; + internal const System.String AssemblyVersion = "3.0.0"; + internal const System.String AssemblyFileVersion = "3.0.0"; + internal const System.Boolean CLSCompliant = true; + internal const System.String AssemblyCopyright = "Copyright (c) 2006 - 2016 Stefanos Apostolopoulos for the Open Toolkit library."; } } diff --git a/tests/OpenTK.Tests/App.config b/tests/OpenTK.Tests/App.config new file mode 100644 index 00000000..571e8b49 --- /dev/null +++ b/tests/OpenTK.Tests/App.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/OpenTK.Tests/AssemblyInfo.fs b/tests/OpenTK.Tests/AssemblyInfo.fs new file mode 100644 index 00000000..1d63b8ec --- /dev/null +++ b/tests/OpenTK.Tests/AssemblyInfo.fs @@ -0,0 +1,41 @@ +namespace OpenTK.Tests.AssemblyInfo + +open System.Reflection +open System.Runtime.CompilerServices +open System.Runtime.InteropServices + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[] +[] +[] +[] +[] +[] +[] +[] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [] +[] +[] + +do + () \ No newline at end of file diff --git a/tests/OpenTK.Tests/Assertions.fs b/tests/OpenTK.Tests/Assertions.fs new file mode 100644 index 00000000..0d0df594 --- /dev/null +++ b/tests/OpenTK.Tests/Assertions.fs @@ -0,0 +1,76 @@ +namespace OpenTK.Tests + +open Xunit +open FsCheck +open FsCheck.Xunit +open System +open OpenTK + +[] +module private AssertHelpers = + [] + let private BitAccuracy = 16 + + [] + let private EquivalenceTolerance = 0.00005f + + let approxEq a b = MathHelper.ApproximatelyEquivalent(a, b, EquivalenceTolerance) + + let approxEqDelta a b = MathHelper.ApproximatelyEqual(a,b,BitAccuracy) + + let approxEqSingleEpsilon a b = MathHelper.ApproximatelyEqualEpsilon(a, b, 0.00001f) + let approxEqDoubleEpsilon a b = MathHelper.ApproximatelyEqualEpsilon(a, b, 0.00001) + + let approxEqSingleEpsilonWithError (a, b, c : float32) = MathHelper.ApproximatelyEqualEpsilon(a, b, c) + let approxEqDoubleEpsilonWithError (a, b, c : float) = MathHelper.ApproximatelyEqualEpsilon(a, b, c) + + let anyZero2 (a : Vector2) = (approxEq a.X 0.0f || approxEq a.Y 0.0f) + let anyZero3 (a : Vector3) = (approxEq a.X 0.0f || approxEq a.Y 0.0f || approxEq a.Z 0.0f) + let anyZero4 (a : Vector4) = (approxEq a.X 0.0f || approxEq a.Y 0.0f || approxEq a.Z 0.0f || approxEq a.W 0.0f) + +/// We use a full type here instead of a module, as the overloading semantics are more suitable for our desired goal. +[] +type internal Assert = + + static member ApproximatelyEquivalent(a : Vector2,b : Vector2) = + if not <| approxEq a.X b.X && approxEq a.Y b.Y then raise <| new Xunit.Sdk.EqualException(a,b) + + static member ApproximatelyEquivalent(a : Vector3,b : Vector3) = + if not <| approxEq a.X b.X && approxEq a.Y b.Y && approxEq a.Z b.Z then raise <| new Xunit.Sdk.EqualException(a,b) + + static member ApproximatelyEquivalent(a : Vector4,b : Vector4) = + if not <| approxEq a.X b.X && approxEq a.Y b.Y && approxEq a.Z b.Z && approxEq a.W b.W then + raise <| new Xunit.Sdk.EqualException(a,b) + + static member ApproximatelyEquivalent(a : float32,b : float32) = + if not <| approxEq a b then raise <| new Xunit.Sdk.EqualException(a,b) + + + static member ApproximatelyEqualEpsilon(a : float32, b : float32) = + if not <| approxEqSingleEpsilon a b then raise <| new Xunit.Sdk.EqualException(a,b) + + static member ApproximatelyEqualEpsilon(a : float32, b : float32, c : float32) = + if not <| approxEqSingleEpsilonWithError(a, b, c) then raise <| new Xunit.Sdk.EqualException(a,b) + + + static member ApproximatelyEqualEpsilon(a : float, b : float) = + if not <| approxEqDoubleEpsilon a b then raise <| new Xunit.Sdk.EqualException(a,b) + + static member ApproximatelyEqualEpsilon(a : float, b : float, c : float) = + if not <| approxEqDoubleEpsilonWithError(a, b, c) then raise <| new Xunit.Sdk.EqualException(a,b) + + + static member NotApproximatelyEqualEpsilon(a : float32, b : float32) = + if approxEqSingleEpsilon a b then raise <| new Xunit.Sdk.EqualException(a,b) + + static member NotApproximatelyEqualEpsilon(a : float32, b : float32, c : float32) = + if approxEqSingleEpsilonWithError(a, b, c) then raise <| new Xunit.Sdk.EqualException(a,b) + + + static member NotApproximatelyEqualEpsilon(a : float, b : float) = + if approxEqDoubleEpsilon a b then raise <| new Xunit.Sdk.EqualException(a,b) + + static member NotApproximatelyEqualEpsilon(a : float, b : float, c : float) = + if approxEqDoubleEpsilonWithError(a, b, c) then raise <| new Xunit.Sdk.EqualException(a,b) + + static member ThrowsIndexExn(f:unit -> unit) = Assert.Throws(f) |> ignore diff --git a/tests/OpenTK.Tests/Generators.fs b/tests/OpenTK.Tests/Generators.fs new file mode 100644 index 00000000..39200f5b --- /dev/null +++ b/tests/OpenTK.Tests/Generators.fs @@ -0,0 +1,80 @@ +namespace OpenTK.Tests + +open Xunit +open FsCheck +open FsCheck.Xunit +open System +open OpenTK + +[] +module private Generators = + let private isValidFloat f = not (Single.IsNaN f || Single.IsInfinity f || Single.IsInfinity (f * f) || f = Single.MinValue || f = Single.MaxValue ) + let private isValidDouble d = not (Double.IsNaN d || Double.IsInfinity d || Double.IsInfinity (d * d)|| d = Double.MinValue || d = Double.MaxValue) + let singleArb = Arb.Default.Float32() |> Arb.toGen |> Gen.filter isValidFloat + let single = singleArb |> Arb.fromGen + + let double = + Arb.Default.Float() |> Arb.toGen + |> Gen.filter isValidDouble + |> Arb.fromGen + + let vec2 = + singleArb + |> Gen.two + |> Gen.map Vector2 + |> Gen.filter (fun v -> not <| (Single.IsNaN v.Length || Single.IsInfinity v.Length )) + |> Arb.fromGen + + let vec3 = + singleArb + |> Gen.three + |> Gen.map Vector3 + |> Gen.filter (fun v -> not <| (Single.IsNaN v.Length || Single.IsInfinity v.Length )) + |> Arb.fromGen + + let vec4 = + singleArb + |> Gen.four + |> Gen.map Vector4 + |> Gen.filter (fun v -> not <| (Single.IsNaN v.Length || Single.IsInfinity v.Length )) + |> Arb.fromGen + + let quat = + singleArb + |> Gen.three + |> Gen.map (fun (x,y,z) -> Quaternion(x,y,z,0.0f) |> Quaternion.Normalize) + |> Gen.filter (fun q -> not <| (Single.IsNaN q.Length || Single.IsInfinity q.Length )) + |> Arb.fromGen + + let mat2 = + singleArb + |> Gen.four + |> Gen.map Matrix2 + |> Arb.fromGen + + let mat3 = + vec3 + |> Arb.toGen + |> Gen.three + |> Gen.map Matrix3 + |> Arb.fromGen + + let mat4 = + vec4 + |> Arb.toGen + |> Gen.four + |> Gen.map Matrix4 + |> Arb.fromGen + +type OpenTKGen = + static member Single() = single + static member float32() = single + static member Double() = double + static member float() = double + static member Vector2() = vec2 + static member Vector3() = vec3 + static member Vector4() = vec4 + static member Quaternion() = quat + static member Matrix2() = mat2 + static member Matrix3() = mat3 + static member Matrix4() = mat4 diff --git a/tests/OpenTK.Tests/MathHelperTests.fs b/tests/OpenTK.Tests/MathHelperTests.fs new file mode 100644 index 00000000..76b96e15 --- /dev/null +++ b/tests/OpenTK.Tests/MathHelperTests.fs @@ -0,0 +1,352 @@ +namespace OpenTK.Tests + +open Xunit +open FsCheck +open FsCheck.Xunit +open System +open OpenTK + +module MathHelper = + [ |])>] + module ``ApproximatelyEqual (delta)`` = + /// This test ensures that approximately equal can never get it 'wrong' about the values. + [] + let ``ApproximatelyEqual is never incorrect`` (a : float32,b : float32,bits : int32) = + let clamped = max 0 (min bits 24) + let areApproxEqual = MathHelper.ApproximatelyEqual(a,b,clamped) + let areExactlyEqual = a = b + let isWrong = areExactlyEqual && not areApproxEqual + Assert.False(isWrong) + + [] + let ``ApproximatelyEqual can return true if some values are not exactly equal`` (a : float32,b : float32,bits : int32) = + let clamped = max 0 (min bits 24) + let areApproxEqual = MathHelper.ApproximatelyEqual(a,b,clamped) + let areExactlyEqual = a = b + let isWrong = areExactlyEqual && not areApproxEqual + let p = new PropertyAttribute() + Assert.False(isWrong) + + [] + let ``ApproximatelyEqual correctly approximates equality``() = + let a = 0.000000001f + let b = 0.0000000010000001f + Assert.NotEqual(a,b) + [ 1..24 ] |> List.iter (fun i -> Assert.True(MathHelper.ApproximatelyEqual(a,b,i))) + + [] + let ``ApproximatelyEqual reports very different values as non-equal even with high bit count``() = + let a = 2.0f + let b = 1.0f + Assert.NotEqual(a,b) + Assert.False(MathHelper.ApproximatelyEqual(a,b,10)) + + [] + let ``ApproximatelyEqual works with single zero value``() = + let a = 1.0f + let b = 0.0f + Assert.NotEqual(a,b) + Assert.False(MathHelper.ApproximatelyEqual(a,b,0)) + + [] + let ``ApproximatelyEqual works with both zero values``() = + let a = 0.0f + let b = 0.0f + Assert.Equal(a,b) + Assert.True(MathHelper.ApproximatelyEqual(a,b,0)) + + [ |])>] + module ``ApproximatelyEqual (single-precision epsilon)`` = + // + [] + let ``ApproximatelyEqual (single precision) is correct for large positive values``() = + Assert.ApproximatelyEqualEpsilon(1000000.0f, 1000001.0f); + Assert.ApproximatelyEqualEpsilon(1000001.0f, 1000000.0f); + Assert.NotApproximatelyEqualEpsilon(10000.0f, 10001.0f); + Assert.NotApproximatelyEqualEpsilon(10001.0f, 10000.0f); + + [] + let ``ApproximatelyEqual (single precision) is correct for large negative values``() = + Assert.ApproximatelyEqualEpsilon(-1000000.0f, -1000001.0f); + Assert.ApproximatelyEqualEpsilon(-1000001.0f, -1000000.0f); + Assert.NotApproximatelyEqualEpsilon(-10000.0f, -10001.0f); + Assert.NotApproximatelyEqualEpsilon(-10001.0f, -10000.0f); + + [] + let ``ApproximatelyEqual (single precision) is correct for positive values around 1``() = + Assert.ApproximatelyEqualEpsilon(1.0000001f, 1.0000002f); + Assert.ApproximatelyEqualEpsilon(1.0000002f, 1.0000001f); + Assert.NotApproximatelyEqualEpsilon(1.0002f, 1.0001f); + Assert.NotApproximatelyEqualEpsilon(1.0001f, 1.0002f); + + [] + let ``ApproximatelyEqual (single precision) is correct for negative values around -1``() = + Assert.ApproximatelyEqualEpsilon(-1.000001f, -1.000002f); + Assert.ApproximatelyEqualEpsilon(-1.000002f, -1.000001f); + Assert.NotApproximatelyEqualEpsilon(-1.0001f, -1.0002f); + Assert.NotApproximatelyEqualEpsilon(-1.0002f, -1.0001f); + + [] + let ``ApproximatelyEqual (single precision) is correct for values between 1 and 0``() = + Assert.ApproximatelyEqualEpsilon(0.000000001000001f, 0.000000001000002f); + Assert.ApproximatelyEqualEpsilon(0.000000001000002f, 0.000000001000001f); + Assert.NotApproximatelyEqualEpsilon(0.000000000001002f, 0.000000000001001f); + Assert.NotApproximatelyEqualEpsilon(0.000000000001001f, 0.000000000001002f); + + [] + let ``ApproximatelyEqual (single precision) is correct for values between -1 and 0``() = + Assert.ApproximatelyEqualEpsilon(-0.000000001000001f, -0.000000001000002f); + Assert.ApproximatelyEqualEpsilon(-0.000000001000002f, -0.000000001000001f); + Assert.NotApproximatelyEqualEpsilon(-0.000000000001002f, -0.000000000001001f); + Assert.NotApproximatelyEqualEpsilon(-0.000000000001001f, -0.000000000001002f); + + [] + let ``ApproximatelyEqual (single precision) is correct for comparisons involving 0``() = + Assert.ApproximatelyEqualEpsilon(0.0f, 0.0f); + Assert.ApproximatelyEqualEpsilon(0.0f, -0.0f); + Assert.ApproximatelyEqualEpsilon(-0.0f, -0.0f); + Assert.NotApproximatelyEqualEpsilon(0.00000001f, 0.0f); + Assert.NotApproximatelyEqualEpsilon(0.0f, 0.00000001f); + Assert.NotApproximatelyEqualEpsilon(-0.00000001f, 0.0f); + Assert.NotApproximatelyEqualEpsilon(0.0f, -0.00000001f); + + Assert.ApproximatelyEqualEpsilon(0.0f, 1e-40f, 0.01f); + Assert.ApproximatelyEqualEpsilon(1e-40f, 0.0f, 0.01f); + Assert.NotApproximatelyEqualEpsilon(1e-40f, 0.0f, 0.000001f); + Assert.NotApproximatelyEqualEpsilon(0.0f, 1e-40f, 0.000001f); + + Assert.ApproximatelyEqualEpsilon(0.0f, -1e-40f, 0.1f); + Assert.ApproximatelyEqualEpsilon(-1e-40f, 0.0f, 0.1f); + Assert.NotApproximatelyEqualEpsilon(-1e-40f, 0.0f, 0.00000001f); + Assert.NotApproximatelyEqualEpsilon(0.0f, -1e-40f, 0.00000001f); + + [] + let ``ApproximatelyEqual (single precision) is correct for extreme values with overflow potential``() = + Assert.ApproximatelyEqualEpsilon(System.Single.MaxValue, System.Single.MaxValue); + Assert.NotApproximatelyEqualEpsilon(System.Single.MaxValue, -System.Single.MaxValue); + Assert.NotApproximatelyEqualEpsilon(-System.Single.MaxValue, System.Single.MaxValue); + Assert.NotApproximatelyEqualEpsilon(System.Single.MaxValue, System.Single.MaxValue / 2.0f); + Assert.NotApproximatelyEqualEpsilon(System.Single.MaxValue, -System.Single.MaxValue / 2.0f); + Assert.NotApproximatelyEqualEpsilon(-System.Single.MaxValue, System.Single.MaxValue / 2.0f); + + [] + let ``ApproximatelyEqual (single precision) is correct for values involving infinities``() = + Assert.ApproximatelyEqualEpsilon(System.Single.PositiveInfinity, System.Single.PositiveInfinity); + Assert.ApproximatelyEqualEpsilon(System.Single.NegativeInfinity, System.Single.NegativeInfinity); + Assert.NotApproximatelyEqualEpsilon(System.Single.NegativeInfinity, System.Single.PositiveInfinity); + Assert.NotApproximatelyEqualEpsilon(System.Single.PositiveInfinity, System.Single.MaxValue); + Assert.NotApproximatelyEqualEpsilon(System.Single.NegativeInfinity, -System.Single.MaxValue); + + [] + let ``ApproximatelyEqual (single precision) is correct for values involving NaN``() = + Assert.NotApproximatelyEqualEpsilon(System.Single.NaN, System.Single.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Single.NaN, 0.0f); + Assert.NotApproximatelyEqualEpsilon(-0.0f, System.Single.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Single.NaN, -0.0f); + Assert.NotApproximatelyEqualEpsilon(0.0f, System.Single.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Single.NaN, System.Single.PositiveInfinity); + Assert.NotApproximatelyEqualEpsilon(System.Single.PositiveInfinity, System.Single.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Single.NaN, System.Single.NegativeInfinity); + Assert.NotApproximatelyEqualEpsilon(System.Single.NegativeInfinity, System.Single.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Single.NaN, System.Single.MaxValue); + Assert.NotApproximatelyEqualEpsilon(System.Single.MaxValue, System.Single.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Single.NaN, -System.Single.MaxValue); + Assert.NotApproximatelyEqualEpsilon(-System.Single.MaxValue, System.Single.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Single.NaN, System.Single.Epsilon); + Assert.NotApproximatelyEqualEpsilon(System.Single.Epsilon, System.Single.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Single.NaN, -System.Single.Epsilon); + Assert.NotApproximatelyEqualEpsilon(-System.Single.Epsilon, System.Single.NaN); + + [] + let ``ApproximatelyEqual (single precision) is correct for values on opposite sides of 0``() = + Assert.NotApproximatelyEqualEpsilon(1.000000001f, -1.0f); + Assert.NotApproximatelyEqualEpsilon(-1.0f, 1.000000001f); + Assert.NotApproximatelyEqualEpsilon(-1.000000001f, 1.0f); + Assert.NotApproximatelyEqualEpsilon(1.0f, -1.000000001f); + Assert.ApproximatelyEqualEpsilon(10.0f * System.Single.Epsilon, 10.0f * -System.Single.Epsilon); + Assert.NotApproximatelyEqualEpsilon(10000.0f * System.Single.Epsilon, 10000.0f * -System.Single.Epsilon); + + [] + let ``ApproximatelyEqual (single precision) is correct for values very close to 0``() = + Assert.ApproximatelyEqualEpsilon(System.Single.Epsilon, System.Single.Epsilon); + Assert.ApproximatelyEqualEpsilon(System.Single.Epsilon, -System.Single.Epsilon); + Assert.ApproximatelyEqualEpsilon(-System.Single.Epsilon, System.Single.Epsilon); + Assert.ApproximatelyEqualEpsilon(System.Single.Epsilon, 0.0f); + Assert.ApproximatelyEqualEpsilon(0.0f, System.Single.Epsilon); + Assert.ApproximatelyEqualEpsilon(-System.Single.Epsilon, 0.0f); + Assert.ApproximatelyEqualEpsilon(0.0f, -System.Single.Epsilon); + + Assert.NotApproximatelyEqualEpsilon(0.000000001f, -System.Single.Epsilon); + Assert.NotApproximatelyEqualEpsilon(0.000000001f, System.Single.Epsilon); + Assert.NotApproximatelyEqualEpsilon(System.Single.Epsilon, 0.000000001f); + Assert.NotApproximatelyEqualEpsilon(-System.Single.Epsilon, 0.000000001f); + + [ |])>] + module ``ApproximatelyEqual (double-precision epsilon)`` = + // + [] + let ``ApproximatelyEqual (double precision) is correct for large positive values``() = + Assert.ApproximatelyEqualEpsilon(1000000.0, 1000001.0); + Assert.ApproximatelyEqualEpsilon(1000001.0, 1000000.0); + Assert.NotApproximatelyEqualEpsilon(10000.0, 10001.0); + Assert.NotApproximatelyEqualEpsilon(10001.0, 10000.0); + + [] + let ``ApproximatelyEqual (double precision) is correct for large negative values``() = + Assert.ApproximatelyEqualEpsilon(-1000000.0, -1000001.0); + Assert.ApproximatelyEqualEpsilon(-1000001.0, -1000000.0); + Assert.NotApproximatelyEqualEpsilon(-10000.0, -10001.0); + Assert.NotApproximatelyEqualEpsilon(-10001.0, -10000.0); + + [] + let ``ApproximatelyEqual (double precision) is correct for positive values around 1``() = + Assert.ApproximatelyEqualEpsilon(1.0000001, 1.0000002); + Assert.ApproximatelyEqualEpsilon(1.0000002, 1.0000001); + Assert.NotApproximatelyEqualEpsilon(1.0002, 1.0001); + Assert.NotApproximatelyEqualEpsilon(1.0001, 1.0002); + + [] + let ``ApproximatelyEqual (double precision) is correct for negative values around -1``() = + Assert.ApproximatelyEqualEpsilon(-1.000001, -1.000002); + Assert.ApproximatelyEqualEpsilon(-1.000002, -1.000001); + Assert.NotApproximatelyEqualEpsilon(-1.0001, -1.0002); + Assert.NotApproximatelyEqualEpsilon(-1.0002, -1.0001); + + [] + let ``ApproximatelyEqual (double precision) is correct for values between 1 and 0``() = + Assert.ApproximatelyEqualEpsilon(0.000000001000001, 0.000000001000002); + Assert.ApproximatelyEqualEpsilon(0.000000001000002, 0.000000001000001); + Assert.NotApproximatelyEqualEpsilon(0.000000000001002, 0.000000000001001); + Assert.NotApproximatelyEqualEpsilon(0.000000000001001, 0.000000000001002); + + [] + let ``ApproximatelyEqual (double precision) is correct for values between -1 and 0``() = + Assert.ApproximatelyEqualEpsilon(-0.000000001000001, -0.000000001000002); + Assert.ApproximatelyEqualEpsilon(-0.000000001000002, -0.000000001000001); + Assert.NotApproximatelyEqualEpsilon(-0.000000000001002, -0.000000000001001); + Assert.NotApproximatelyEqualEpsilon(-0.000000000001001, -0.000000000001002); + + [] + let ``ApproximatelyEqual (double precision) is correct for comparisons involving 0``() = + Assert.ApproximatelyEqualEpsilon(0.0, 0.0); + Assert.ApproximatelyEqualEpsilon(0.0, -0.0); + Assert.ApproximatelyEqualEpsilon(-0.0, -0.0); + Assert.NotApproximatelyEqualEpsilon(0.00000001, 0.0); + Assert.NotApproximatelyEqualEpsilon(0.0, 0.00000001); + Assert.NotApproximatelyEqualEpsilon(-0.00000001, 0.0); + Assert.NotApproximatelyEqualEpsilon(0.0, -0.00000001); + + Assert.ApproximatelyEqualEpsilon(0.0, 1e-310, 0.01); + Assert.ApproximatelyEqualEpsilon(1e-310, 0.0, 0.01); + Assert.NotApproximatelyEqualEpsilon(1e-310, 0.0, 0.000001); + Assert.NotApproximatelyEqualEpsilon(0.0, 1e-310, 0.000001); + + Assert.ApproximatelyEqualEpsilon(0.0, -1e-310, 0.1); + Assert.ApproximatelyEqualEpsilon(-1e-310, 0.0, 0.1); + Assert.NotApproximatelyEqualEpsilon(-1e-310, 0.0, 0.00000001); + Assert.NotApproximatelyEqualEpsilon(0.0, -1e-310, 0.00000001); + + [] + let ``ApproximatelyEqual (double precision) is correct for extreme values with overflow potential``() = + Assert.ApproximatelyEqualEpsilon(System.Double.MaxValue, System.Double.MaxValue); + Assert.NotApproximatelyEqualEpsilon(System.Double.MaxValue, -System.Double.MaxValue); + Assert.NotApproximatelyEqualEpsilon(-System.Double.MaxValue, System.Double.MaxValue); + Assert.NotApproximatelyEqualEpsilon(System.Double.MaxValue, System.Double.MaxValue / 2.0); + Assert.NotApproximatelyEqualEpsilon(System.Double.MaxValue, -System.Double.MaxValue / 2.0); + Assert.NotApproximatelyEqualEpsilon(-System.Double.MaxValue, System.Double.MaxValue / 2.0); + + [] + let ``ApproximatelyEqual (double precision) is correct for values involving infinities``() = + Assert.ApproximatelyEqualEpsilon(System.Double.PositiveInfinity, System.Double.PositiveInfinity); + Assert.ApproximatelyEqualEpsilon(System.Double.NegativeInfinity, System.Double.NegativeInfinity); + Assert.NotApproximatelyEqualEpsilon(System.Double.NegativeInfinity, System.Double.PositiveInfinity); + Assert.NotApproximatelyEqualEpsilon(System.Double.PositiveInfinity, System.Double.MaxValue); + Assert.NotApproximatelyEqualEpsilon(System.Double.NegativeInfinity, -System.Double.MaxValue); + + [] + let ``ApproximatelyEqual (double precision) is correct for values involving NaN``() = + Assert.NotApproximatelyEqualEpsilon(System.Double.NaN, System.Double.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Double.NaN, 0.0); + Assert.NotApproximatelyEqualEpsilon(-0.0, System.Double.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Double.NaN, -0.0); + Assert.NotApproximatelyEqualEpsilon(0.0, System.Double.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Double.NaN, System.Double.PositiveInfinity); + Assert.NotApproximatelyEqualEpsilon(System.Double.PositiveInfinity, System.Double.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Double.NaN, System.Double.NegativeInfinity); + Assert.NotApproximatelyEqualEpsilon(System.Double.NegativeInfinity, System.Double.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Double.NaN, System.Double.MaxValue); + Assert.NotApproximatelyEqualEpsilon(System.Double.MaxValue, System.Double.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Double.NaN, -System.Double.MaxValue); + Assert.NotApproximatelyEqualEpsilon(-System.Double.MaxValue, System.Double.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Double.NaN, System.Double.Epsilon); + Assert.NotApproximatelyEqualEpsilon(System.Double.Epsilon, System.Double.NaN); + Assert.NotApproximatelyEqualEpsilon(System.Double.NaN, -System.Double.Epsilon); + Assert.NotApproximatelyEqualEpsilon(-System.Double.Epsilon, System.Double.NaN); + + [] + let ``ApproximatelyEqual (double precision) is correct for values on opposite sides of 0``() = + Assert.NotApproximatelyEqualEpsilon(1.000000001, -1.0); + Assert.NotApproximatelyEqualEpsilon(-1.0, 1.000000001); + Assert.NotApproximatelyEqualEpsilon(-1.000000001, 1.0); + Assert.NotApproximatelyEqualEpsilon(1.0, -1.000000001); + Assert.ApproximatelyEqualEpsilon(10.0 * System.Double.Epsilon, 10.0 * -System.Double.Epsilon); + Assert.NotApproximatelyEqualEpsilon(100000000000.0 * System.Double.Epsilon, 100000000000.0 * -System.Double.Epsilon); + + [] + let ``ApproximatelyEqual (double precision) is correct for values very close to 0``() = + Assert.ApproximatelyEqualEpsilon(System.Double.Epsilon, System.Double.Epsilon); + Assert.ApproximatelyEqualEpsilon(System.Double.Epsilon, -System.Double.Epsilon); + Assert.ApproximatelyEqualEpsilon(-System.Double.Epsilon, System.Double.Epsilon); + Assert.ApproximatelyEqualEpsilon(System.Double.Epsilon, 0.0); + Assert.ApproximatelyEqualEpsilon(0.0, System.Double.Epsilon); + Assert.ApproximatelyEqualEpsilon(-System.Double.Epsilon, 0.0); + Assert.ApproximatelyEqualEpsilon(0.0, -System.Double.Epsilon); + + Assert.NotApproximatelyEqualEpsilon(0.000000001, -System.Double.Epsilon); + Assert.NotApproximatelyEqualEpsilon(0.000000001, System.Double.Epsilon); + Assert.NotApproximatelyEqualEpsilon(System.Double.Epsilon, 0.000000001); + Assert.NotApproximatelyEqualEpsilon(-System.Double.Epsilon, 0.000000001); + + [ |])>] + module ``ApproximatelyEquivalent (tolerance diff)`` = + [] + let ``ApproximatelyEquivalent correctly approximates equivalence where the difference falls below the tolerance``() = + let a = 0.0001f + let b = 0.00019f + Assert.NotEqual(a,b) + Assert.True(MathHelper.ApproximatelyEquivalent(a, b, 0.0001f)) + + [] + let ``ApproximatelyEquivalent correctly approximates equivalence where the difference is the tolerance``() = + let a = 0.0001f + let b = 0.0002f + Assert.NotEqual(a,b) + Assert.True(MathHelper.ApproximatelyEquivalent(a, b, 0.0001f)) + + [] + let ``ApproximatelyEquivalent correctly approximates inequivalence where the difference exceeds the tolerance``() = + let a = 0.0001f + let b = 0.00021f + Assert.NotEqual(a,b) + Assert.False(MathHelper.ApproximatelyEquivalent(a, b, 0.0001f)) + + [] + let ``ApproximatelyEquivalent reports very different values as non-equal even with a high tolerance``() = + let a = 3.0f + let b = 1.0f + Assert.NotEqual(a,b) + Assert.False(MathHelper.ApproximatelyEquivalent(a, b, 1.0f)) + + [] + let ``ApproximatelyEquivalent works with single zero value``() = + let a = 1.0f + let b = 0.0f + Assert.NotEqual(a,b) + Assert.False(MathHelper.ApproximatelyEquivalent(a, b, 0.0001f)) + + [] + let ``ApproximatelyEquivalent works with both zero values``() = + let a = 0.0f + let b = 0.0f + Assert.Equal(a,b) + Assert.True(MathHelper.ApproximatelyEquivalent(a, b, 0.0001f)) \ No newline at end of file diff --git a/tests/OpenTK.Tests/Matrix4Test.cs b/tests/OpenTK.Tests/Matrix4Test.cs deleted file mode 100644 index 97cc8862..00000000 --- a/tests/OpenTK.Tests/Matrix4Test.cs +++ /dev/null @@ -1,289 +0,0 @@ -using System; -using NUnit.Framework; -using OpenTK; - -namespace OpenTK.Tests -{ - [TestFixture] - public class Matrix4Test - { - [Test] - public void Matrix4_SixteenValueConstructor() - { - Matrix4 A = new Matrix4( 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15); - - Assert.AreEqual(0, A.M11); - Assert.AreEqual(1, A.M12); - Assert.AreEqual(2, A.M13); - Assert.AreEqual(3, A.M14); - - Assert.AreEqual(4, A.M21); - Assert.AreEqual(5, A.M22); - Assert.AreEqual(6, A.M23); - Assert.AreEqual(7, A.M24); - - Assert.AreEqual(8, A.M31); - Assert.AreEqual(9, A.M32); - Assert.AreEqual(10, A.M33); - Assert.AreEqual(11, A.M34); - - Assert.AreEqual(12, A.M41); - Assert.AreEqual(13, A.M42); - Assert.AreEqual(14, A.M43); - Assert.AreEqual(15, A.M44); - } - - [Test] - public void Matrix4_Matrix3Constructor() - { - Matrix3 B = new Matrix3( 1, 2, 3, - 4, 5, 6, - 7, 8, 9); - - Matrix4 A = new Matrix4(B); - - Assert.AreEqual(B.M11, A.M11); - Assert.AreEqual(B.M12, A.M12); - Assert.AreEqual(B.M13, A.M13); - - Assert.AreEqual(B.M21, A.M21); - Assert.AreEqual(B.M22, A.M22); - Assert.AreEqual(B.M23, A.M23); - - Assert.AreEqual(B.M31, A.M31); - Assert.AreEqual(B.M32, A.M32); - Assert.AreEqual(B.M33, A.M33); - } - - [Test] - public void Matrix4_FourVector4Constructor() - { - Vector4 V = new Vector4(1, 2, 3, 4); - Vector4 U = new Vector4(5, 6, 7, 8); - Vector4 S = new Vector4(9, 10, 11, 12); - Vector4 T = new Vector4(13, 14, 15, 16); - - Matrix4 A = new Matrix4(V, U, S, T); - - Assert.AreEqual(V.X, A.M11); - Assert.AreEqual(V.Y, A.M12); - Assert.AreEqual(V.Z, A.M13); - Assert.AreEqual(V.W, A.M14); - - Assert.AreEqual(U.X, A.M21); - Assert.AreEqual(U.Y, A.M22); - Assert.AreEqual(U.Z, A.M23); - Assert.AreEqual(U.W, A.M24); - - Assert.AreEqual(S.X, A.M31); - Assert.AreEqual(S.Y, A.M32); - Assert.AreEqual(S.Z, A.M33); - Assert.AreEqual(S.W, A.M34); - - Assert.AreEqual(T.X, A.M41); - Assert.AreEqual(T.Y, A.M42); - Assert.AreEqual(T.Z, A.M43); - Assert.AreEqual(T.W, A.M44); - - } - - [Test] - public void Matrix4_Equal_operator() - { - Matrix4 A = new Matrix4( 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15); - - Matrix4 B = new Matrix4( 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15); - - Assert.IsTrue(A == B); - } - - [Test] - public void Matrix4_Matrix4TimesMatrix4_operator() - { - Matrix4 A = new Matrix4( 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15); - - Matrix4 B = new Matrix4( 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15); - - Matrix4 expected = new Matrix4( 56, 62, 68, 74, - 152, 174, 196, 218, - 248, 286, 324, 362, - 344, 398, 452, 506); - - Matrix4 result = A * B; - Assert.IsTrue(expected == result); - } - - [Test] - public void Matrix4_Matrix4PlusMatrix4_operator() - { - Matrix4 A = new Matrix4( 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15); - - Matrix4 B = new Matrix4( 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15); - - Matrix4 expected = new Matrix4( 0, 2, 4, 6, - 8, 10, 12, 14, - 16, 18, 20, 22, - 24, 26, 28, 30); - - Matrix4 result = A + B; - Assert.IsTrue(expected == result); - } - - [Test] - public void Matrix4_Matrix4MinusMatrix4_operator() - { - Matrix4 A = new Matrix4( 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15); - - Matrix4 B = new Matrix4( 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15); - - Matrix4 expected = new Matrix4( 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0); - - Matrix4 result = A - B; - Assert.IsTrue(expected == result); - } - - [Test] - public void Matrix4_Index_Operator() - { - Matrix4 A = new Matrix4(); - A[0, 0] = 0; - A[0, 1] = 1; - A[0, 2] = 2; - A[0, 3] = 3; - A[1, 0] = 4; - A[1, 1] = 5; - A[1, 2] = 6; - A[1, 3] = 7; - A[2, 0] = 8; - A[2, 1] = 9; - A[2, 2] = 10; - A[2, 3] = 11; - A[3, 0] = 12; - A[3, 1] = 13; - A[3, 2] = 14; - A[3, 3] = 15; - Assert.AreEqual(0, A[0, 0]); - Assert.AreEqual(1, A[0, 1]); - Assert.AreEqual(2, A[0, 2]); - Assert.AreEqual(3, A[0, 3]); - Assert.AreEqual(4, A[1, 0]); - Assert.AreEqual(5, A[1, 1]); - Assert.AreEqual(6, A[1, 2]); - Assert.AreEqual(7, A[1, 3]); - Assert.AreEqual(8, A[2, 0]); - Assert.AreEqual(9, A[2, 1]); - Assert.AreEqual(10, A[2, 2]); - Assert.AreEqual(11, A[2, 3]); - Assert.AreEqual(12, A[3, 0]); - Assert.AreEqual(13, A[3, 1]); - Assert.AreEqual(14, A[3, 2]); - Assert.AreEqual(15, A[3, 3]); - } - - [Test] - public void Matrix4_Index_NegativeIndexException() - { - Matrix4 A = new Matrix4(); - bool negativeIndexException = false; - try - { - A[-1, 2] = 0; - } - catch(Exception) - { - negativeIndexException = true; - } - Assert.IsTrue(negativeIndexException); - - negativeIndexException = false; - try - { - A[1, -2] = 0; - } - catch (Exception) - { - negativeIndexException = true; - } - Assert.IsTrue(negativeIndexException); - - negativeIndexException = false; - try - { - A[-1, -2] = 0; - } - catch (Exception) - { - negativeIndexException = true; - } - Assert.IsTrue(negativeIndexException); - } - - [Test] - public void Matrix4_Index_LargeIndexException() - { - Matrix4 A = new Matrix4(); - bool largeIndexException = false; - try - { - A[5, 2] = 0; - } - catch (Exception) - { - largeIndexException = true; - } - Assert.IsTrue(largeIndexException); - - largeIndexException = false; - try - { - A[1, 6] = 0; - } - catch (Exception) - { - largeIndexException = true; - } - Assert.IsTrue(largeIndexException); - - largeIndexException = false; - try - { - A[7, 12] = 0; - } - catch (Exception) - { - largeIndexException = true; - } - Assert.IsTrue(largeIndexException); - } - } -} diff --git a/tests/OpenTK.Tests/Matrix4Tests.fs b/tests/OpenTK.Tests/Matrix4Tests.fs new file mode 100644 index 00000000..e4ca3f5d --- /dev/null +++ b/tests/OpenTK.Tests/Matrix4Tests.fs @@ -0,0 +1,396 @@ +namespace OpenTK.Tests + +open Xunit +open FsCheck +open FsCheck.Xunit +open System +open OpenTK + +module Matrix4 = + [ |])>] + module Constructors = + // + [] + let ``Sixteen value constructor sets all components to the correct values`` (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) = + let A = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + + Assert.Equal(a, A.M11) + Assert.Equal(b, A.M12) + Assert.Equal(c, A.M13) + Assert.Equal(d, A.M14) + + Assert.Equal(e, A.M21) + Assert.Equal(f, A.M22) + Assert.Equal(g, A.M23) + Assert.Equal(h, A.M24) + + Assert.Equal(i, A.M31) + Assert.Equal(j, A.M32) + Assert.Equal(k, A.M33) + Assert.Equal(l, A.M34) + + Assert.Equal(m, A.M41) + Assert.Equal(n, A.M42) + Assert.Equal(o, A.M43) + Assert.Equal(p, A.M44) + + [] + let ``Matrix3 partial constructor sets all components to the correct values`` (a, b, c, d, e, f, g, h, i) = + let B = Matrix3(a, b, c, d, e, f, g, h, i) + let A = Matrix4(B) + + Assert.Equal(a, A.M11) + Assert.Equal(b, A.M12) + Assert.Equal(c, A.M13) + Assert.Equal(0.0f, A.M14) + + Assert.Equal(d, A.M21) + Assert.Equal(e, A.M22) + Assert.Equal(f, A.M23) + Assert.Equal(0.0f, A.M24) + + Assert.Equal(g, A.M31) + Assert.Equal(h, A.M32) + Assert.Equal(i, A.M33) + Assert.Equal(0.0f, A.M34) + + Assert.Equal(0.0f, A.M41) + Assert.Equal(0.0f, A.M42) + Assert.Equal(0.0f, A.M43) + Assert.Equal(1.0f, A.M44) + + [] + let ``Four-vector4 constructor sets all components to the correct values`` (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) = + let v1 = Vector4(a, b, c, d) + let v2 = Vector4(e, f, g, h) + let v3 = Vector4(i, j, k, l) + let v4 = Vector4(m, n, o, p) + + let A = Matrix4(v1, v2, v3, v4) + + Assert.Equal(a, A.M11) + Assert.Equal(b, A.M12) + Assert.Equal(c, A.M13) + Assert.Equal(d, A.M14) + + Assert.Equal(e, A.M21) + Assert.Equal(f, A.M22) + Assert.Equal(g, A.M23) + Assert.Equal(h, A.M24) + + Assert.Equal(i, A.M31) + Assert.Equal(j, A.M32) + Assert.Equal(k, A.M33) + Assert.Equal(l, A.M34) + + Assert.Equal(m, A.M41) + Assert.Equal(n, A.M42) + Assert.Equal(o, A.M43) + Assert.Equal(p, A.M44) + + [ |])>] + module Equality = + // + [] + let ``Two matrices with identical values are equal`` (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) = + let A = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + let B = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + let equality = A = B + + Assert.True(equality) + + [] + let ``A matrix is not equal to an object which is not a matrix`` (a : Matrix4, b : Vector3) = + Assert.False(a.Equals(b)) + + [ |])>] + module Multiplication = + // + [] + let ``Matrix multiplication is done by row/column multiplication and summation`` (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) = + let A = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + let B = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + + let R11 = a*a + b*e + c*i + d*m + let R12 = a*b + b*f + c*j + d*n + let R13 = a*c + b*g + c*k + d*o + let R14 = a*d + b*h + c*l + d*p + + let R21 = e*a + f*e + g*i + h*m + let R22 = e*b + f*f + g*j + h*n + let R23 = e*c + f*g + g*k + h*o + let R24 = e*d + f*h + g*l + h*p + + let R31 = i*a + j*e + k*i + l*m + let R32 = i*b + j*f + k*j + l*n + let R33 = i*c + j*g + k*k + l*o + let R34 = i*d + j*h + k*l + l*p + + let R41 = m*a + n*e + o*i + p*m + let R42 = m*b + n*f + o*j + p*n + let R43 = m*c + n*g + o*k + p*o + let R44 = m*d + n*h + o*l + p*p + + let AB = A*B + + Assert.Equal(R11, AB.M11) + Assert.Equal(R12, AB.M12) + Assert.Equal(R13, AB.M13) + Assert.Equal(R14, AB.M14) + + Assert.Equal(R21, AB.M21) + Assert.Equal(R22, AB.M22) + Assert.Equal(R23, AB.M23) + Assert.Equal(R24, AB.M24) + + Assert.Equal(R31, AB.M31) + Assert.Equal(R32, AB.M32) + Assert.Equal(R33, AB.M33) + Assert.Equal(R34, AB.M34) + + Assert.Equal(R41, AB.M41) + Assert.Equal(R42, AB.M42) + Assert.Equal(R43, AB.M43) + Assert.Equal(R44, AB.M44) + + [] + let ``Matrix multiplication by scalar is the same as row multiplication by scalar`` (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, scalar : float32) = + let A = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + + let R1 = Vector4(a, b, c, d) * scalar + let R2 = Vector4(e, f, g, h) * scalar + let R3 = Vector4(i, j, k, l) * scalar + let R4 = Vector4(m, n, o, p) * scalar + + let AScaled = A * scalar + + Assert.Equal(R1, AScaled.Row0) + Assert.Equal(R2, AScaled.Row1) + Assert.Equal(R3, AScaled.Row2) + Assert.Equal(R4, AScaled.Row3) + + [] + let ``Static method matrix multiplication by scalar is the same as row multiplication by scalar`` (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, scalar : float32) = + let A = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + + let R1 = Vector4(a, b, c, d) * scalar + let R2 = Vector4(e, f, g, h) * scalar + let R3 = Vector4(i, j, k, l) * scalar + let R4 = Vector4(m, n, o, p) * scalar + + let AScaled = Matrix4.Mult(A, scalar) + + Assert.Equal(R1, AScaled.Row0) + Assert.Equal(R2, AScaled.Row1) + Assert.Equal(R3, AScaled.Row2) + Assert.Equal(R4, AScaled.Row3) + + [] + let ``Static method matrix multiplication by reference by scalar is the same as row multiplication by scalar`` (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, scalar : float32) = + let A = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + + let R1 = Vector4(a, b, c, d) * scalar + let R2 = Vector4(e, f, g, h) * scalar + let R3 = Vector4(i, j, k, l) * scalar + let R4 = Vector4(m, n, o, p) * scalar + + let AScaled = Matrix4.Mult(ref A, scalar) + + Assert.Equal(R1, AScaled.Row0) + Assert.Equal(R2, AScaled.Row1) + Assert.Equal(R3, AScaled.Row2) + Assert.Equal(R4, AScaled.Row3) + + + [ |])>] + module Addition = + // + [] + let ``Matrix addition adds corresponding components`` (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) = + let A = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + let B = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + + let sum = A + B + + Assert.Equal(a + a, sum.M11) + Assert.Equal(b + b, sum.M12) + Assert.Equal(c + c, sum.M13) + Assert.Equal(d + d, sum.M14) + + Assert.Equal(e + e, sum.M21) + Assert.Equal(f + f, sum.M22) + Assert.Equal(g + g, sum.M23) + Assert.Equal(h + h, sum.M24) + + Assert.Equal(i + i, sum.M31) + Assert.Equal(j + j, sum.M32) + Assert.Equal(k + k, sum.M33) + Assert.Equal(l + l, sum.M34) + + Assert.Equal(m + m, sum.M41) + Assert.Equal(n + n, sum.M42) + Assert.Equal(o + o, sum.M43) + Assert.Equal(p + p, sum.M44) + + [ |])>] + module Subtraction = + // + [] + let ``Matrix subtraction subtracts corresponding components`` (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) = + let A = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + let B = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + + let sub = A - B + + Assert.Equal(a - a, sub.M11) + Assert.Equal(b - b, sub.M12) + Assert.Equal(c - c, sub.M13) + Assert.Equal(d - d, sub.M14) + + Assert.Equal(e - e, sub.M21) + Assert.Equal(f - f, sub.M22) + Assert.Equal(g - g, sub.M23) + Assert.Equal(h - h, sub.M24) + + Assert.Equal(i - i, sub.M31) + Assert.Equal(j - j, sub.M32) + Assert.Equal(k - k, sub.M33) + Assert.Equal(l - l, sub.M34) + + Assert.Equal(m - m, sub.M41) + Assert.Equal(n - n, sub.M42) + Assert.Equal(o - o, sub.M43) + Assert.Equal(p - p, sub.M44) + + [ |])>] + module Indexing = + // + [] + let ``Matrix set indexing sets correct components`` (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) = + let mutable A = Matrix4() + + A.[0, 0] <- a + A.[0, 1] <- b + A.[0, 2] <- c + A.[0, 3] <- d + + A.[1, 0] <- e + A.[1, 1] <- f + A.[1, 2] <- g + A.[1, 3] <- h + + A.[2, 0] <- i + A.[2, 1] <- j + A.[2, 2] <- k + A.[2, 3] <- l + + A.[3, 0] <- m + A.[3, 1] <- n + A.[3, 2] <- o + A.[3, 3] <- p + + Assert.Equal(a, A.M11) + Assert.Equal(b, A.M12) + Assert.Equal(c, A.M13) + Assert.Equal(d, A.M14) + + Assert.Equal(e, A.M21) + Assert.Equal(f, A.M22) + Assert.Equal(g, A.M23) + Assert.Equal(h, A.M24) + + Assert.Equal(i, A.M31) + Assert.Equal(j, A.M32) + Assert.Equal(k, A.M33) + Assert.Equal(l, A.M34) + + Assert.Equal(m, A.M41) + Assert.Equal(n, A.M42) + Assert.Equal(o, A.M43) + Assert.Equal(p, A.M44) + + [] + let ``Matrix get indexing accesses the correct components`` (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) = + let A = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + + Assert.Equal(a, A.[0, 0]) + Assert.Equal(b, A.[0, 1]) + Assert.Equal(c, A.[0, 2]) + Assert.Equal(d, A.[0, 3]) + + Assert.Equal(e, A.[1, 0]) + Assert.Equal(f, A.[1, 1]) + Assert.Equal(g, A.[1, 2]) + Assert.Equal(h, A.[1, 3]) + + Assert.Equal(i, A.[2, 0]) + Assert.Equal(j, A.[2, 1]) + Assert.Equal(k, A.[2, 2]) + Assert.Equal(l, A.[2, 3]) + + Assert.Equal(m, A.[3, 0]) + Assert.Equal(n, A.[3, 1]) + Assert.Equal(o, A.[3, 2]) + Assert.Equal(p, A.[3, 3]) + + + [] + let ``Indexed set operator throws exception for negative indices`` (b : Matrix4, x : float32) = + let mutable a = b + + + + (fun() -> a.[-1, 2] <- x) |> Assert.ThrowsIndexExn + (fun() -> a.[1, -2] <- x) |> Assert.ThrowsIndexExn + (fun() -> a.[-1, -2] <- x) |> Assert.ThrowsIndexExn + + [] + let ``Indexed get operator throws exception for negative indices`` (a : Matrix4) = + (fun() -> a.[-1, 2] |> ignore) |> Assert.ThrowsIndexExn + (fun() -> a.[1, -2] |> ignore) |> Assert.ThrowsIndexExn + (fun() -> a.[-1, -2] |> ignore) |> Assert.ThrowsIndexExn + + [] + let ``Indexed set operator throws exception for large indices`` (a : Matrix4, x : float32) = + let mutable b = a + (fun() -> b.[5, 2] <- x) |> Assert.ThrowsIndexExn + (fun() -> b.[1, 6] <- x) |> Assert.ThrowsIndexExn + (fun() -> b.[7, 12] <- x) |> Assert.ThrowsIndexExn + + [] + let ``Indexed get operator throws exception for large indices`` (a : Matrix4) = + (fun() -> a.[5, 2] |> ignore) |> Assert.ThrowsIndexExn + (fun() -> a.[1, 6] |> ignore) |> Assert.ThrowsIndexExn + (fun() -> a.[7, 12] |> ignore) |> Assert.ThrowsIndexExn + + [ |])>] + module ``Row and column properties`` = + // + [] + let ``Matrix row properties return the correct components`` (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) = + let A = Matrix4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) + + let R0 = A.Row0 + let R1 = A.Row1 + let R2 = A.Row2 + let R3 = A.Row3 + + Assert.Equal(a, R0.X) + Assert.Equal(b, R0.Y) + Assert.Equal(c, R0.Z) + Assert.Equal(d, R0.W) + + Assert.Equal(e, R1.X) + Assert.Equal(f, R1.Y) + Assert.Equal(g, R1.Z) + Assert.Equal(h, R1.W) + + Assert.Equal(i, R2.X) + Assert.Equal(j, R2.Y) + Assert.Equal(k, R2.Z) + Assert.Equal(l, R2.W) + + Assert.Equal(m, R3.X) + Assert.Equal(n, R3.Y) + Assert.Equal(o, R3.Z) + Assert.Equal(p, R3.W) \ No newline at end of file diff --git a/tests/OpenTK.Tests/OpenTK.Tests.csproj b/tests/OpenTK.Tests/OpenTK.Tests.csproj deleted file mode 100644 index f4d82e04..00000000 --- a/tests/OpenTK.Tests/OpenTK.Tests.csproj +++ /dev/null @@ -1,87 +0,0 @@ - - - - - Debug - AnyCPU - {930A780C-A67C-422F-9EED-DB38DAA47AB0} - Library - Properties - OpenTK.Tests - OpenTK.Tests - v4.0 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll - False - - - ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll - False - - - ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll - True - - - ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll - False - - - ..\..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll - False - - - - - - - - - - - - - - - - - - - - {a37a7e14-0000-0000-0000-000000000000} - OpenTK - - - - - - - - \ No newline at end of file diff --git a/tests/OpenTK.Tests/OpenTK.Tests.fsproj b/tests/OpenTK.Tests/OpenTK.Tests.fsproj new file mode 100644 index 00000000..d269e1c3 --- /dev/null +++ b/tests/OpenTK.Tests/OpenTK.Tests.fsproj @@ -0,0 +1,1589 @@ + + + + + Debug + AnyCPU + 2.0 + 6801c263-adda-4a7b-979d-649bcb5a1df7 + Library + OpenTK.Tests + OpenTK.Tests + v4.5.2 + 4.4.0.0 + true + OpenTK.Tests + + + true + full + false + false + bin\Debug\ + DEBUG;TRACE + 3 + bin\Debug\OpenTK.Tests.XML + + + pdbonly + true + true + bin\Release\ + TRACE + 3 + bin\Release\OpenTK.Tests.XML + + + 11 + + + + + $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets + + + + + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets + + + + + + + + + + + + + + + + + + + + + + + + OpenTK + {a37a7e14-0000-0000-0000-000000000000} + True + + + + + + + ..\..\packages\FsCheck\lib\net452\FsCheck.dll + True + True + + + + + + + ..\..\packages\FsCheck\lib\netstandard1.6\FsCheck.dll + True + True + + + + + + + ..\..\packages\FsCheck\lib\portable-net45+netcore45\FsCheck.dll + True + True + + + + + + + ..\..\packages\FsCheck\lib\portable-net45+netcore45+wp8\FsCheck.dll + True + True + + + + + + + ..\..\packages\FsCheck\lib\portable-net45+netcore45+wpa81+wp8\FsCheck.dll + True + True + + + + + + + + + ..\..\packages\FsCheck.Xunit\lib\net452\FsCheck.Xunit.dll + True + True + + + + + + + ..\..\packages\FsCheck.Xunit\lib\netstandard1.6\FsCheck.Xunit.dll + True + True + + + + + + + + + ..\..\packages\FSharp.Core\lib\net20\FSharp.Core.dll + True + True + + + + + + + ..\..\packages\FSharp.Core\lib\net40\FSharp.Core.dll + True + True + + + + + + + ..\..\packages\FSharp.Core\lib\net45\FSharp.Core.dll + True + True + + + + + + + ..\..\packages\FSharp.Core\lib\netstandard1.6\FSharp.Core.dll + True + True + + + + + + + ..\..\packages\FSharp.Core\lib\portable-net45+netcore45\FSharp.Core.dll + True + True + + + + + + + ..\..\packages\FSharp.Core\lib\portable-net45+netcore45+wp8\FSharp.Core.dll + True + True + + + + + + + + + ..\..\packages\Microsoft.Win32.Primitives\lib\net46\Microsoft.Win32.Primitives.dll + True + True + + + + + + + ..\..\packages\Microsoft.Win32.Primitives\ref\netstandard1.3\Microsoft.Win32.Primitives.dll + False + True + + + + + + + + + ..\..\packages\System.AppContext\lib\net46\System.AppContext.dll + True + True + + + + + + + ..\..\packages\System.AppContext\lib\net463\System.AppContext.dll + True + True + + + + + + + ..\..\packages\System.AppContext\ref\netstandard1.3\System.AppContext.dll + False + True + + + + + + + ..\..\packages\System.AppContext\lib\netstandard1.6\System.AppContext.dll + True + True + + + + + + + + + ..\..\packages\System.Buffers\lib\netstandard1.1\System.Buffers.dll + True + True + + + + + + + + + ..\..\packages\System.Collections\ref\netstandard1.0\System.Collections.dll + False + True + + + + + + + ..\..\packages\System.Collections\ref\netstandard1.3\System.Collections.dll + False + True + + + + + + + + + ..\..\packages\System.Collections.Concurrent\lib\netstandard1.3\System.Collections.Concurrent.dll + True + True + + + + + + + + + ..\..\packages\System.Console\lib\net46\System.Console.dll + True + True + + + + + + + ..\..\packages\System.Console\ref\netstandard1.3\System.Console.dll + False + True + + + + + + + + + ..\..\packages\System.Diagnostics.Debug\ref\netstandard1.0\System.Diagnostics.Debug.dll + False + True + + + + + + + ..\..\packages\System.Diagnostics.Debug\ref\netstandard1.3\System.Diagnostics.Debug.dll + False + True + + + + + + + + + ..\..\packages\System.Diagnostics.DiagnosticSource\lib\net46\System.Diagnostics.DiagnosticSource.dll + True + True + + + + + + + ..\..\packages\System.Diagnostics.DiagnosticSource\lib\netstandard1.1\System.Diagnostics.DiagnosticSource.dll + True + True + + + + + + + ..\..\packages\System.Diagnostics.DiagnosticSource\lib\netstandard1.3\System.Diagnostics.DiagnosticSource.dll + True + True + + + + + + + + + ..\..\packages\System.Diagnostics.Tracing\lib\net462\System.Diagnostics.Tracing.dll + True + True + + + + + + + ..\..\packages\System.Diagnostics.Tracing\ref\netstandard1.1\System.Diagnostics.Tracing.dll + False + True + + + + + + + ..\..\packages\System.Diagnostics.Tracing\ref\netstandard1.2\System.Diagnostics.Tracing.dll + False + True + + + + + + + ..\..\packages\System.Diagnostics.Tracing\ref\netstandard1.3\System.Diagnostics.Tracing.dll + False + True + + + + + + + ..\..\packages\System.Diagnostics.Tracing\ref\netstandard1.5\System.Diagnostics.Tracing.dll + False + True + + + + + + + + + ..\..\packages\System.Globalization\ref\netstandard1.0\System.Globalization.dll + False + True + + + + + + + ..\..\packages\System.Globalization\ref\netstandard1.3\System.Globalization.dll + False + True + + + + + + + + + ..\..\packages\System.Globalization.Calendars\lib\net46\System.Globalization.Calendars.dll + True + True + + + + + + + ..\..\packages\System.Globalization.Calendars\ref\netstandard1.3\System.Globalization.Calendars.dll + False + True + + + + + + + + + ..\..\packages\System.Globalization.Extensions\lib\net46\System.Globalization.Extensions.dll + True + True + + + + + + + ..\..\packages\System.Globalization.Extensions\ref\netstandard1.3\System.Globalization.Extensions.dll + False + True + + + + + + + + + ..\..\packages\System.IO\lib\net462\System.IO.dll + True + True + + + + + + + ..\..\packages\System.IO\ref\netstandard1.0\System.IO.dll + False + True + + + + + + + ..\..\packages\System.IO\ref\netstandard1.3\System.IO.dll + False + True + + + + + + + ..\..\packages\System.IO\ref\netstandard1.5\System.IO.dll + False + True + + + + + + + + + True + + + + + + + ..\..\packages\System.IO.Compression\lib\net46\System.IO.Compression.dll + True + True + + + + + + + ..\..\packages\System.IO.Compression\ref\netstandard1.1\System.IO.Compression.dll + False + True + + + + + + + ..\..\packages\System.IO.Compression\ref\netstandard1.3\System.IO.Compression.dll + False + True + + + + + + + + + True + + + ..\..\packages\System.IO.Compression.ZipFile\lib\net46\System.IO.Compression.ZipFile.dll + True + True + + + + + + + ..\..\packages\System.IO.Compression.ZipFile\lib\netstandard1.3\System.IO.Compression.ZipFile.dll + True + True + + + + + + + + + ..\..\packages\System.IO.FileSystem\lib\net46\System.IO.FileSystem.dll + True + True + + + + + + + ..\..\packages\System.IO.FileSystem\ref\netstandard1.3\System.IO.FileSystem.dll + False + True + + + + + + + + + ..\..\packages\System.IO.FileSystem.Primitives\lib\net46\System.IO.FileSystem.Primitives.dll + True + True + + + + + + + ..\..\packages\System.IO.FileSystem.Primitives\lib\netstandard1.3\System.IO.FileSystem.Primitives.dll + True + True + + + + + + + + + ..\..\packages\System.Linq\lib\net463\System.Linq.dll + True + True + + + + + + + ..\..\packages\System.Linq\lib\netstandard1.6\System.Linq.dll + True + True + + + + + + + + + ..\..\packages\System.Linq.Expressions\lib\net463\System.Linq.Expressions.dll + True + True + + + + + + + ..\..\packages\System.Linq.Expressions\ref\netstandard1.0\System.Linq.Expressions.dll + False + True + + + + + + + ..\..\packages\System.Linq.Expressions\ref\netstandard1.3\System.Linq.Expressions.dll + False + True + + + + + + + ..\..\packages\System.Linq.Expressions\lib\netstandard1.6\System.Linq.Expressions.dll + True + True + + + + + + + + + ..\..\packages\System.Linq.Queryable\lib\netstandard1.3\System.Linq.Queryable.dll + True + True + + + + + + + + + True + + + + + + + ..\..\packages\System.Net.Http\lib\net46\System.Net.Http.dll + True + True + + + + + + + ..\..\packages\System.Net.Http\ref\netstandard1.1\System.Net.Http.dll + False + True + + + + + + + ..\..\packages\System.Net.Http\ref\netstandard1.3\System.Net.Http.dll + False + True + + + + + + + + + ..\..\packages\System.Net.Primitives\ref\netstandard1.1\System.Net.Primitives.dll + False + True + + + + + + + ..\..\packages\System.Net.Primitives\ref\netstandard1.3\System.Net.Primitives.dll + False + True + + + + + + + + + ..\..\packages\System.Net.Sockets\lib\net46\System.Net.Sockets.dll + True + True + + + + + + + ..\..\packages\System.Net.Sockets\ref\netstandard1.3\System.Net.Sockets.dll + False + True + + + + + + + + + ..\..\packages\System.Net.WebHeaderCollection\lib\netstandard1.3\System.Net.WebHeaderCollection.dll + True + True + + + + + + + + + ..\..\packages\System.ObjectModel\lib\netstandard1.3\System.ObjectModel.dll + True + True + + + + + + + + + ..\..\packages\System.Reflection\lib\net462\System.Reflection.dll + True + True + + + + + + + ..\..\packages\System.Reflection\ref\netstandard1.0\System.Reflection.dll + False + True + + + + + + + ..\..\packages\System.Reflection\ref\netstandard1.3\System.Reflection.dll + False + True + + + + + + + ..\..\packages\System.Reflection\ref\netstandard1.5\System.Reflection.dll + False + True + + + + + + + + + ..\..\packages\System.Reflection.Emit\lib\netstandard1.3\System.Reflection.Emit.dll + True + True + + + + + + + + + ..\..\packages\System.Reflection.Emit.ILGeneration\lib\netstandard1.3\System.Reflection.Emit.ILGeneration.dll + True + True + + + + + + + + + ..\..\packages\System.Reflection.Emit.Lightweight\lib\netstandard1.3\System.Reflection.Emit.Lightweight.dll + True + True + + + + + + + + + ..\..\packages\System.Reflection.TypeExtensions\lib\net46\System.Reflection.TypeExtensions.dll + True + True + + + + + + + ..\..\packages\System.Reflection.TypeExtensions\lib\net462\System.Reflection.TypeExtensions.dll + True + True + + + + + + + ..\..\packages\System.Reflection.TypeExtensions\lib\netstandard1.5\System.Reflection.TypeExtensions.dll + True + True + + + + + + + + + True + + + + + + + True + + + ..\..\packages\System.Runtime\lib\net462\System.Runtime.dll + True + True + + + + + + + ..\..\packages\System.Runtime\ref\netstandard1.0\System.Runtime.dll + False + True + + + + + + + ..\..\packages\System.Runtime\ref\netstandard1.2\System.Runtime.dll + False + True + + + + + + + ..\..\packages\System.Runtime\ref\netstandard1.3\System.Runtime.dll + False + True + + + + + + + ..\..\packages\System.Runtime\ref\netstandard1.5\System.Runtime.dll + False + True + + + + + + + + + ..\..\packages\System.Runtime.Extensions\lib\net462\System.Runtime.Extensions.dll + True + True + + + + + + + ..\..\packages\System.Runtime.Extensions\ref\netstandard1.0\System.Runtime.Extensions.dll + False + True + + + + + + + ..\..\packages\System.Runtime.Extensions\ref\netstandard1.3\System.Runtime.Extensions.dll + False + True + + + + + + + ..\..\packages\System.Runtime.Extensions\ref\netstandard1.5\System.Runtime.Extensions.dll + False + True + + + + + + + + + ..\..\packages\System.Runtime.Handles\ref\netstandard1.3\System.Runtime.Handles.dll + False + True + + + + + + + + + ..\..\packages\System.Runtime.InteropServices\lib\net462\System.Runtime.InteropServices.dll + True + True + + + + + + + ..\..\packages\System.Runtime.InteropServices\lib\net463\System.Runtime.InteropServices.dll + True + True + + + + + + + ..\..\packages\System.Runtime.InteropServices\ref\netstandard1.1\System.Runtime.InteropServices.dll + False + True + + + + + + + ..\..\packages\System.Runtime.InteropServices\ref\netstandard1.2\System.Runtime.InteropServices.dll + False + True + + + + + + + ..\..\packages\System.Runtime.InteropServices\ref\netstandard1.3\System.Runtime.InteropServices.dll + False + True + + + + + + + ..\..\packages\System.Runtime.InteropServices\ref\netstandard1.5\System.Runtime.InteropServices.dll + False + True + + + + + + + + + ..\..\packages\System.Runtime.InteropServices.RuntimeInformation\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + True + + + + + + + ..\..\packages\System.Runtime.InteropServices.RuntimeInformation\lib\netstandard1.1\System.Runtime.InteropServices.RuntimeInformation.dll + True + True + + + + + + + ..\..\packages\System.Runtime.InteropServices.RuntimeInformation\ref\netstandard1.1\System.Runtime.InteropServices.RuntimeInformation.dll + False + True + + + + + + + ..\..\packages\System.Runtime.InteropServices.RuntimeInformation\lib\wpa81\System.Runtime.InteropServices.RuntimeInformation.dll + True + True + + + + + + + + + ..\..\packages\System.Runtime.Numerics\ref\netstandard1.1\System.Runtime.Numerics.dll + False + True + + + + + + + ..\..\packages\System.Runtime.Numerics\lib\netstandard1.3\System.Runtime.Numerics.dll + True + True + + + + + + + + + ..\..\packages\System.Security.Cryptography.Algorithms\lib\net46\System.Security.Cryptography.Algorithms.dll + True + True + + + + + + + ..\..\packages\System.Security.Cryptography.Algorithms\lib\net461\System.Security.Cryptography.Algorithms.dll + True + True + + + + + + + ..\..\packages\System.Security.Cryptography.Algorithms\lib\net463\System.Security.Cryptography.Algorithms.dll + True + True + + + + + + + ..\..\packages\System.Security.Cryptography.Algorithms\ref\netstandard1.3\System.Security.Cryptography.Algorithms.dll + False + True + + + + + + + ..\..\packages\System.Security.Cryptography.Algorithms\ref\netstandard1.4\System.Security.Cryptography.Algorithms.dll + False + True + + + + + + + ..\..\packages\System.Security.Cryptography.Algorithms\ref\netstandard1.6\System.Security.Cryptography.Algorithms.dll + False + True + + + + + + + + + ..\..\packages\System.Security.Cryptography.Cng\lib\net46\System.Security.Cryptography.Cng.dll + True + True + + + + + + + ..\..\packages\System.Security.Cryptography.Cng\lib\net461\System.Security.Cryptography.Cng.dll + True + True + + + + + + + ..\..\packages\System.Security.Cryptography.Cng\lib\net463\System.Security.Cryptography.Cng.dll + True + True + + + + + + + ..\..\packages\System.Security.Cryptography.Cng\ref\netstandard1.6\System.Security.Cryptography.Cng.dll + False + True + + + + + + + + + ..\..\packages\System.Security.Cryptography.Csp\lib\net46\System.Security.Cryptography.Csp.dll + True + True + + + + + + + ..\..\packages\System.Security.Cryptography.Csp\ref\netstandard1.3\System.Security.Cryptography.Csp.dll + False + True + + + + + + + + + ..\..\packages\System.Security.Cryptography.Encoding\lib\net46\System.Security.Cryptography.Encoding.dll + True + True + + + + + + + ..\..\packages\System.Security.Cryptography.Encoding\ref\netstandard1.3\System.Security.Cryptography.Encoding.dll + False + True + + + + + + + + + ..\..\packages\System.Security.Cryptography.OpenSsl\lib\netstandard1.6\System.Security.Cryptography.OpenSsl.dll + True + True + + + + + + + + + ..\..\packages\System.Security.Cryptography.Primitives\lib\net46\System.Security.Cryptography.Primitives.dll + True + True + + + + + + + ..\..\packages\System.Security.Cryptography.Primitives\lib\netstandard1.3\System.Security.Cryptography.Primitives.dll + True + True + + + + + + + + + ..\..\packages\System.Security.Cryptography.X509Certificates\lib\net46\System.Security.Cryptography.X509Certificates.dll + True + True + + + + + + + ..\..\packages\System.Security.Cryptography.X509Certificates\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + True + + + + + + + ..\..\packages\System.Security.Cryptography.X509Certificates\ref\netstandard1.3\System.Security.Cryptography.X509Certificates.dll + False + True + + + + + + + ..\..\packages\System.Security.Cryptography.X509Certificates\ref\netstandard1.4\System.Security.Cryptography.X509Certificates.dll + False + True + + + + + + + + + ..\..\packages\System.Text.Encoding\ref\netstandard1.0\System.Text.Encoding.dll + False + True + + + + + + + ..\..\packages\System.Text.Encoding\ref\netstandard1.3\System.Text.Encoding.dll + False + True + + + + + + + + + ..\..\packages\System.Text.Encoding.Extensions\ref\netstandard1.0\System.Text.Encoding.Extensions.dll + False + True + + + + + + + ..\..\packages\System.Text.Encoding.Extensions\ref\netstandard1.3\System.Text.Encoding.Extensions.dll + False + True + + + + + + + + + ..\..\packages\System.Text.RegularExpressions\lib\net463\System.Text.RegularExpressions.dll + True + True + + + + + + + ..\..\packages\System.Text.RegularExpressions\ref\netstandard1.0\System.Text.RegularExpressions.dll + False + True + + + + + + + ..\..\packages\System.Text.RegularExpressions\ref\netstandard1.3\System.Text.RegularExpressions.dll + False + True + + + + + + + ..\..\packages\System.Text.RegularExpressions\lib\netstandard1.6\System.Text.RegularExpressions.dll + True + True + + + + + + + + + ..\..\packages\System.Threading\lib\netstandard1.3\System.Threading.dll + True + True + + + + + + + + + ..\..\packages\System.Threading.Tasks\ref\netstandard1.0\System.Threading.Tasks.dll + False + True + + + + + + + ..\..\packages\System.Threading.Tasks\ref\netstandard1.3\System.Threading.Tasks.dll + False + True + + + + + + + + + ..\..\packages\System.Threading.Tasks.Extensions\lib\netstandard1.0\System.Threading.Tasks.Extensions.dll + True + True + + + + + + + + + ..\..\packages\System.Threading.Tasks.Parallel\lib\netstandard1.3\System.Threading.Tasks.Parallel.dll + True + True + + + + + + + + + ..\..\packages\System.Threading.Thread\lib\net46\System.Threading.Thread.dll + True + True + + + + + + + ..\..\packages\System.Threading.Thread\lib\netstandard1.3\System.Threading.Thread.dll + True + True + + + + + + + + + ..\..\packages\System.Threading.ThreadPool\lib\net46\System.Threading.ThreadPool.dll + True + True + + + + + + + ..\..\packages\System.Threading.ThreadPool\lib\netstandard1.3\System.Threading.ThreadPool.dll + True + True + + + + + + + + + True + + + + + + + True + + + ..\..\packages\System.Xml.ReaderWriter\lib\net46\System.Xml.ReaderWriter.dll + True + True + + + + + + + ..\..\packages\System.Xml.ReaderWriter\lib\netstandard1.3\System.Xml.ReaderWriter.dll + True + True + + + + + + + + + True + + + + + + + ..\..\packages\System.Xml.XDocument\lib\netstandard1.3\System.Xml.XDocument.dll + True + True + + + + + + + + + ..\..\packages\xunit.abstractions\lib\net35\xunit.abstractions.dll + True + True + + + + + + + ..\..\packages\xunit.abstractions\lib\netstandard1.0\xunit.abstractions.dll + True + True + + + + + + + + + ..\..\packages\xunit.assert\lib\netstandard1.1\xunit.assert.dll + True + True + + + + + + + + + ..\..\packages\xunit.extensibility.core\lib\netstandard1.1\xunit.core.dll + True + True + + + + + + + + + ..\..\packages\xunit.extensibility.execution\lib\net452\xunit.execution.desktop.dll + True + True + + + + + + + ..\..\packages\xunit.extensibility.execution\lib\netstandard1.1\xunit.execution.dotnet.dll + True + True + + + + + \ No newline at end of file diff --git a/tests/OpenTK.Tests/Properties/AssemblyInfo.cs b/tests/OpenTK.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index fac1b001..00000000 --- a/tests/OpenTK.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenTK.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("OpenTK.Tests")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("8a03c40d-007c-4a15-ab0c-2111969ea6df")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/OpenTK.Tests/Vector2Tests.fs b/tests/OpenTK.Tests/Vector2Tests.fs new file mode 100644 index 00000000..e44d8de6 --- /dev/null +++ b/tests/OpenTK.Tests/Vector2Tests.fs @@ -0,0 +1,603 @@ +namespace OpenTK.Tests + +open Xunit +open FsCheck +open FsCheck.Xunit +open System +open System.Runtime.InteropServices +open OpenTK + +module Vector2 = + [ |])>] + module Constructors = + // + [] + let ``Single value constructor sets all components to the same value`` (f : float32) = + let v = Vector2(f) + Assert.Equal(f,v.X) + Assert.Equal(f,v.Y) + + [] + let ``Two value constructor sets all components correctly`` (x,y) = + let v = Vector2(x,y) + Assert.Equal(x,v.X) + Assert.Equal(y,v.Y) + + [ |])>] + module Clamping = + // + [] + let ``Clamping one vector between two other vectors clamps all components between corresponding components`` (a : Vector2, b : Vector2, w : Vector2) = + let res = Vector2.Clamp(w, a, b) + + let expX = if w.X < a.X then a.X else if w.X > b.X then b.X else w.X + let expY = if w.Y < a.Y then a.Y else if w.Y > b.Y then b.Y else w.Y + + Assert.Equal(expX, res.X) + Assert.Equal(expY, res.Y) + + [] + let ``Clamping one vector between two other vectors by reference clamps all components`` (a : Vector2, b : Vector2, w : Vector2) = + let res = Vector2.Clamp(ref w, ref a, ref b) + + let expX = if w.X < a.X then a.X else if w.X > b.X then b.X else w.X + let expY = if w.Y < a.Y then a.Y else if w.Y > b.Y then b.Y else w.Y + + Assert.Equal(expX, res.X) + Assert.Equal(expY, res.Y) + + [ |])>] + module Length = + // + [] + let ``Length is always >= 0`` (a : Vector2) = + // + Assert.True(a.Length >= 0.0f) + + [] + let ``Length follows the pythagorean theorem`` (a, b) = + let v = Vector2(a, b) + let l = System.Math.Sqrt((float)(a * a + b * b)) + + Assert.Equal((float32)l, v.Length) + + [] + let ``Fast length method works`` (a, b) = + let v = Vector2(a, b) + let l = 1.0f / MathHelper.InverseSqrtFast(a * a + b * b) + + Assert.Equal(l, v.LengthFast) + + [] + let ``Length squared method works`` (a, b) = + let v = Vector2(a, b) + let lsq = a * a + b * b + + Assert.Equal(lsq, v.LengthSquared) + + [ |])>] + module ``Unit vectors and perpendicularity`` = + // + [] + let ``Perpendicular vector to the right is correct`` (a, b) = + let v = Vector2(a, b) + let perp = Vector2(b, -a) + + Assert.Equal(perp, v.PerpendicularRight) + + [] + let ``Perpendicular vector to the left is correct`` (a, b) = + let v = Vector2(a, b) + let perp = Vector2(-b, a) + + Assert.Equal(perp, v.PerpendicularLeft) + + [ |])>] + module Indexing = + // + [] + let ``Index operator accesses the correct components`` (x, y) = + let v = Vector2(x, y) + + Assert.Equal(x, v.[0]) + Assert.Equal(y, v.[1]) + + [] + let ``Indexed set operator throws exception for negative indices`` (x, y) = + let mutable v = Vector2(x, y) + + (fun() -> v.[-1] <- x) |> Assert.ThrowsIndexExn + + [] + let ``Indexed get operator throws exception for negative indices`` (x, y) = + let mutable v = Vector2(x, y) + + (fun() -> v.[-1] |> ignore) |> Assert.ThrowsIndexExn + + [] + let ``Indexed set operator throws exception for large indices`` (x, y) = + let mutable v = Vector2(x, y) + + (fun() -> v.[2] <- x) |> Assert.ThrowsIndexExn + + [] + let ``Indexed get operator throws exception for large indices`` (x, y) = + let mutable v = Vector2(x, y) + + (fun() -> v.[2] |> ignore) |> Assert.ThrowsIndexExn + + [ |])>] + module ``Simple Properties`` = + // + [] + let ``Vector equality is by component`` (a : Vector2,b : Vector2) = + // + Assert.Equal((a.X = b.X && a.Y = b.Y),(a = b)) + + [] + let ``Vector length is always >= 0`` (a : Vector2) = + // + Assert.True(a.Length >= 0.0f) + + [ |])>] + module Addition = + // + [] + let ``Vector addition is the same as component addition`` (a : Vector2,b : Vector2) = + let c = a + b + Assert.ApproximatelyEquivalent(a.X + b.X,c.X) + Assert.ApproximatelyEquivalent(a.Y + b.Y,c.Y) + + [] + let ``Vector addition is commutative`` (a : Vector2,b : Vector2) = + let c = a + b + let c2 = b + a + Assert.ApproximatelyEquivalent(c,c2) + + [] + let ``Vector addition is associative`` (a : Vector2,b : Vector2,c : Vector2) = + let r1 = (a + b) + c + let r2 = a + (b + c) + Assert.ApproximatelyEquivalent(r1,r2) + + [] + let ``Static Vector2 addition method is the same as component addition`` (a : Vector2, b : Vector2) = + + let v1 = Vector2(a.X + b.X, a.Y + b.Y) + let sum = Vector2.Add(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector2 addition method by reference is the same as component addition`` (a : Vector2, b : Vector2) = + + let v1 = Vector2(a.X + b.X, a.Y + b.Y) + let sum = Vector2.Add(ref a, ref b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [ |])>] + module Multiplication = + // + [] + let ``Vector2 multiplication is the same as component multiplication`` (a : Vector2, b : Vector2) = + let c = a * b + Assert.Equal(a.X * b.X,c.X) + Assert.Equal(a.Y * b.Y,c.Y) + + [] + let ``Vector2 multiplication is commutative`` (a : Vector2, b : Vector2) = + let r1 = a * b + let r2 = b * a + Assert.Equal(r1,r2) + + [] + let ``Left-handed Vector2-scalar multiplication is the same as component-scalar multiplication`` (a : Vector2, f : float32) = + let r = a * f + + Assert.Equal(a.X * f,r.X) + Assert.Equal(a.Y * f,r.Y) + + [] + let ``Right-handed Vector2-scalar multiplication is the same as component-scalar multiplication`` (a : Vector2, f : float32) = + let r = f * a + Assert.Equal(a.X * f,r.X) + Assert.Equal(a.Y * f,r.Y) + + [] + let ``Static Vector2 multiplication method is the same as component multiplication`` (a : Vector2, b : Vector2) = + + let v1 = Vector2(a.X * b.X, a.Y * b.Y) + let sum = Vector2.Multiply(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector2 multiplication method by reference is the same as component multiplication`` (a : Vector2, b : Vector2) = + + let v1 = Vector2(a.X * b.X, a.Y * b.Y) + let sum = Vector2.Multiply(ref a, ref b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static method Vector2-scalar multiplication is the same as component-scalar multiplication`` (a : Vector2, f : float32) = + let r = Vector2.Multiply(a, f) + + Assert.Equal(a.X * f,r.X) + Assert.Equal(a.Y * f,r.Y) + + [ |])>] + module Subtraction = + // + [] + let ``Vector2 subtraction is the same as component subtraction`` (a : Vector2, b : Vector2) = + let c = a - b + Assert.Equal(a.X - b.X,c.X) + Assert.Equal(a.Y - b.Y,c.Y) + + [] + let ``Static Vector2 subtraction method is the same as component addition`` (a : Vector2, b : Vector2) = + + let v1 = Vector2(a.X - b.X, a.Y - b.Y) + let sum = Vector2.Subtract(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector2 subtraction method by reference is the same as component addition`` (a : Vector2, b : Vector2) = + + let v1 = Vector2(a.X - b.X, a.Y - b.Y) + let sum = Vector2.Subtract(ref a, ref b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [ |])>] + module Division = + // + [] + let ``Vector2-float division is the same as component-float division`` (a : Vector2, f : float32) = + if not (approxEq f 0.0f) then + let r = a / f + + Assert.ApproximatelyEquivalent(a.X / f,r.X) + Assert.ApproximatelyEquivalent(a.Y / f,r.Y) + + [] + let ``Static Vector2-Vector2 division method is the same as component division`` (a : Vector2, b : Vector2) = + if not (anyZero2 a || anyZero2 b) then + let v1 = Vector2(a.X / b.X, a.Y / b.Y) + let sum = Vector2.Divide(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector2-Vector2 divison method by reference `` (a : Vector2, b : Vector2) = + if not (anyZero2 a || anyZero2 b) then + let v1 = Vector2(a.X / b.X, a.Y / b.Y) + let sum = Vector2.Divide(ref a, ref b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector2-scalar division method is the same as component division`` (a : Vector2, b : float32) = + if not (approxEq b 0.0f) then + let v1 = Vector2(a.X / b, a.Y / b) + let sum = Vector2.Divide(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector2-scalar divison method by reference is the same as component division`` (a : Vector2, b : float32) = + if not (approxEq b 0.0f) then + let v1 = Vector2(a.X / b, a.Y / b) + let sum = Vector2.Divide(ref a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [ |])>] + module Negation = + // + [] + let ``Vector negation operator negates all components`` (x, y) = + let v = Vector2(x, y) + let vNeg = -v + Assert.Equal(-x, vNeg.X) + Assert.Equal(-y, vNeg.Y) + + [ |])>] + module Equality = + // + [] + let ``Vector equality operator is by component`` (x, y) = + let v1 = Vector2(x, y) + let v2 = Vector2(x, y) + let equality = v1 = v2 + + Assert.True(equality) + + [] + let ``Vector inequality operator is by component`` (x, y) = + let v1 = Vector2(x, y) + let v2 = Vector2(x + 1.0f , y + 1.0f) + let inequality = v1 <> v2 + + Assert.True(inequality) + + [] + let ``Vector equality method is by component`` (x, y) = + let v1 = Vector2(x, y) + let v2 = Vector2(x, y) + let notVector = Matrix2() + + let equality = v1.Equals(v2) + let inequalityByOtherType = v1.Equals(notVector) + + Assert.True(equality) + Assert.False(inequalityByOtherType) + + [ |])>] + module Swizzling = + // + [] + let ``Vector swizzling returns the correct composites`` (x, y) = + let v1 = Vector2(x, y) + let v2 = Vector2(y, x) + + let v1yx = v1.Yx; + Assert.Equal(v2, v1yx); + + [ |])>] + module Interpolation = + // + [] + let ``Linear interpolation is by component`` (a : Vector2, b : Vector2, q) = + + let blend = q + + let rX = blend * (b.X - a.X) + a.X + let rY = blend * (b.Y - a.Y) + a.Y + let vExp = Vector2(rX, rY) + + Assert.Equal(vExp, Vector2.Lerp(a, b, q)) + + let vRes = Vector2.Lerp(ref a, ref b, q) + Assert.Equal(vExp, vRes) + + [] + let ``Barycentric interpolation follows the barycentric formula`` (a : Vector2, b : Vector2, c : Vector2, u, v) = + + let r = a + u * (b - a) + v * (c - a) + + Assert.Equal(r, Vector2.BaryCentric(a, b, c, u, v)) + + let vRes = Vector2.BaryCentric(ref a, ref b, ref c, u, v) + Assert.Equal(r, vRes) + + [ |])>] + module ``Vector products`` = + // + [] + let ``Dot product follows the dot product formula`` (a : Vector2, b : Vector2) = + let dot = a.X * b.X + a.Y * b.Y + + Assert.Equal(dot, Vector2.Dot(a, b)); + + let vRes = Vector2.Dot(ref a, ref b) + Assert.Equal(dot, vRes) + + [] + let ``Perpendicular dot product follows the perpendicular dot product formula`` (a : Vector2, b : Vector2) = + let perpDot = a.X * b.Y - a.Y * b.X + + Assert.Equal(perpDot, Vector2.PerpDot(a, b)); + + let vRes = Vector2.PerpDot(ref a, ref b) + Assert.Equal(perpDot, vRes) + + [ |])>] + module Normalization = + // + [] + let ``Normalization creates a new unit length vector with the correct components`` (a, b) = + let v = Vector2(a, b) + let l = v.Length + + // Dividing by zero is not supported + if not (approxEq l 0.0f) then + let norm = v.Normalized() + + Assert.ApproximatelyEquivalent(v.X / l, norm.X) + Assert.ApproximatelyEquivalent(v.Y / l, norm.Y) + + [] + let ``Normalization of instance transforms the instance into a unit length vector with the correct components`` (a, b) = + let v = Vector2(a, b) + let l = v.Length + + if not (approxEq l 0.0f) then + let norm = Vector2(a, b) + norm.Normalize() + + Assert.ApproximatelyEquivalent(v.X / l, norm.X) + Assert.ApproximatelyEquivalent(v.Y / l, norm.Y) + + [] + let ``Fast approximate normalization of instance transforms the instance into a unit length vector with the correct components`` (a, b) = + let v = Vector2(a, b) + let norm = Vector2(a, b) + norm.NormalizeFast() + + let scale = MathHelper.InverseSqrtFast(a * a + b * b) + + Assert.ApproximatelyEquivalent(v.X * scale, norm.X) + Assert.ApproximatelyEquivalent(v.Y * scale, norm.Y) + + [] + let ``Normalization by reference is the same as division by magnitude`` (a : Vector2) = + // Zero-length vectors can't be normalized + if not (approxEq a.Length 0.0f) then + let norm = a / a.Length + let vRes = Vector2.Normalize(ref a) + + Assert.ApproximatelyEquivalent(norm, vRes) + + [] + let ``Normalization is the same as division by magnitude`` (a : Vector2) = + // Zero-length vectors can't be normalized + if not (approxEq a.Length 0.0f) then + let norm = a / a.Length + + Assert.ApproximatelyEquivalent(norm, Vector2.Normalize(a)); + + [] + let ``Fast approximate normalization by reference is the same as multiplication by the fast inverse square`` (a : Vector2) = + let scale = MathHelper.InverseSqrtFast(a.X * a.X + a.Y * a.Y) + + let norm = a * scale + let vRes = Vector2.NormalizeFast(ref a) + + Assert.ApproximatelyEquivalent(norm, vRes) + + [] + let ``Fast approximate normalization is the same as multiplication by the fast inverse square`` (a : Vector2) = + let scale = MathHelper.InverseSqrtFast(a.X * a.X + a.Y * a.Y) + + let norm = a * scale + + Assert.ApproximatelyEquivalent(norm, Vector2.NormalizeFast(a)); + + [ |])>] + module ``Magnitude min and max`` = + // + [] + let ``MagnitudeMin selects the vector with equal or lesser magnitude given two vectors`` (v1 : Vector2, v2: Vector2) = + // Results do not matter for equal vectors + if not (v1 = v2) then + let l1 = v1.LengthSquared + let l2 = v2.LengthSquared + + let vMin = Vector2.MagnitudeMin(v1, v2) + + if vMin = v1 then + let v1ShorterThanv2 = l1 < l2 + Assert.True(v1ShorterThanv2) + else + let v2ShorterThanOrEqualTov1 = l2 <= l1 + Assert.True(v2ShorterThanOrEqualTov1) + + [] + let ``MagnitudeMax selects the vector with equal or greater magnitude given two vectors`` (v1 : Vector2, v2: Vector2) = + // Results do not matter for equal vectors + if not (v1 = v2) then + let l1 = v1.LengthSquared + let l2 = v2.LengthSquared + + let vMin = Vector2.MagnitudeMax(v1, v2) + + if vMin = v1 then + let v1LongerThanOrEqualTov2 = l1 >= l2 + Assert.True(v1LongerThanOrEqualTov2) + else + let v2LongerThanv1 = l2 > l1 + Assert.True(v2LongerThanv1) + + [] + let ``MagnitudeMin by reference selects the vector with equal or lesser magnitude given two vectors`` (v1 : Vector2, v2: Vector2) = + // Results do not matter for equal vectors + if not (v1 = v2) then + let l1 = v1.LengthSquared + let l2 = v2.LengthSquared + + let vMin = Vector2.MagnitudeMin(ref v1, ref v2) + + if vMin = v1 then + let v1ShorterThanv2 = l1 < l2 + Assert.True(v1ShorterThanv2) + else + let v2ShorterThanOrEqualTov1 = l2 <= l1 + Assert.True(v2ShorterThanOrEqualTov1) + + [] + let ``MagnitudeMax by reference selects the vector with equal greater magnitude given two vectors`` (v1 : Vector2, v2: Vector2) = + // Results do not matter for equal vectors + if not (v1 = v2) then + let l1 = v1.LengthSquared + let l2 = v2.LengthSquared + + let vMin = Vector2.MagnitudeMax(ref v1, ref v2) + + if vMin = v1 then + let v1LongerThanOrEqualTov2 = l1 >= l2 + Assert.True(v1LongerThanOrEqualTov2) + else + let v2LongerThanv1 = l2 > l1 + Assert.True(v2LongerThanv1) + + [ |])>] + module ``Component min and max`` = + // + [] + let ``ComponentMin creates a new vector from the smallest components of given vectors`` (v1 : Vector2, v2: Vector2) = + let vMin = Vector2.ComponentMin(v1, v2) + let isComponentSmallest smallComp comp1 comp2 = smallComp <= comp1 && smallComp <= comp2 + + Assert.True(isComponentSmallest vMin.X v1.X v2.X) + Assert.True(isComponentSmallest vMin.Y v1.Y v2.Y) + + [] + let ``ComponentMax creates a new vector from the greatest components of given vectors`` (v1 : Vector2, v2: Vector2) = + let vMax = Vector2.ComponentMax(v1, v2) + let isComponentLargest largeComp comp1 comp2 = largeComp >= comp1 && largeComp >= comp2 + + Assert.True(isComponentLargest vMax.X v1.X v2.X) + Assert.True(isComponentLargest vMax.Y v1.Y v2.Y) + + [] + let ``ComponentMin by reference creates a new vector from the smallest components of given vectors`` (v1 : Vector2, v2: Vector2) = + let vMin = Vector2.ComponentMin(ref v1, ref v2) + let isComponentSmallest smallComp comp1 comp2 = smallComp <= comp1 && smallComp <= comp2 + + Assert.True(isComponentSmallest vMin.X v1.X v2.X) + Assert.True(isComponentSmallest vMin.Y v1.Y v2.Y) + + [] + let ``ComponentMax by reference creates a new vector from the greatest components of given vectors`` (v1 : Vector2, v2: Vector2) = + let vMax = Vector2.ComponentMax(ref v1, ref v2) + let isComponentLargest largeComp comp1 comp2 = largeComp >= comp1 && largeComp >= comp2 + + Assert.True(isComponentLargest vMax.X v1.X v2.X) + Assert.True(isComponentLargest vMax.Y v1.Y v2.Y) + + [ |])>] + module Transformation = + // + [] + let ``Transformation by quaternion is the same as multiplication by quaternion and its conjugate`` (v : Vector2, q : Quaternion) = + let vectorQuat = Quaternion(v.X, v.Y, 0.0f, 0.0f) + let inverse = Quaternion.Invert(q) + + let transformedQuat = q * vectorQuat * inverse + let transformedVector = Vector2(transformedQuat.X, transformedQuat.Y) + + Assert.ApproximatelyEquivalent(transformedVector, Vector2.Transform(v, q)) + + [] + let ``Transformation by quaternion by reference is the same as multiplication by quaternion and its conjugate`` (v : Vector2, q : Quaternion) = + let vectorQuat = Quaternion(v.X, v.Y, 0.0f, 0.0f) + let inverse = Quaternion.Invert(q) + + let transformedQuat = q * vectorQuat * inverse + let transformedVector = Vector2(transformedQuat.X, transformedQuat.Y) + + Assert.ApproximatelyEquivalent(transformedVector, Vector2.Transform(ref v, ref q)) + + [ |])>] + module Serialization = + // + [] + let ``The absolute size of a Vector2 is always the size of its components`` (v : Vector2) = + let expectedSize = sizeof * 2 + + Assert.Equal(expectedSize, Vector2.SizeInBytes) + Assert.Equal(expectedSize, Marshal.SizeOf(Vector2())) \ No newline at end of file diff --git a/tests/OpenTK.Tests/Vector3Tests.cs b/tests/OpenTK.Tests/Vector3Tests.cs deleted file mode 100644 index 16db4735..00000000 --- a/tests/OpenTK.Tests/Vector3Tests.cs +++ /dev/null @@ -1,439 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using NUnit.Framework; -using OpenTK; - -namespace OpenTK.Tests -{ - [TestFixture] - public class Vector3Tests - { - [Test] - public void Vector3_SingleValueConstructor() - { - Vector3 V = new Vector3(1); - Assert.AreEqual(1, V.X); - Assert.AreEqual(1, V.Y); - Assert.AreEqual(1, V.Z); - } - - [Test] - public void Vector3_ThreeValueConstructor() - { - Vector3 V = new Vector3(1,2,3); - Assert.AreEqual(1, V.X); - Assert.AreEqual(2, V.Y); - Assert.AreEqual(3, V.Z); - } - - [Test] - public void Vector3_Vector2Constructor() - { - Vector2 T = new Vector2(1, 2); - Vector3 V = new Vector3(T); - Assert.AreEqual(T.X, V.X); - Assert.AreEqual(T.Y, V.Y); - Assert.AreEqual(0, V.Z); - } - - [Test] - public void Vector3_Vector3Constructor() - { - Vector3 U = new Vector3(1, 2, 3); - Vector3 V = new Vector3(U); - Assert.IsTrue(U == V); - } - - [Test] - public void Vector3_Vector4Constructor() - { - Vector4 T = new Vector4(1, 2, 3, 0); - Vector3 V = new Vector3(T); - Assert.AreEqual(T.X, V.X); - Assert.AreEqual(T.Y, V.Y); - Assert.AreEqual(T.Z, V.Z); - } - - [Test] - public void Vector3_Index_operator() - { - Vector3 V = new Vector3(); - V[0] = 1; V[1] = 2; V[2] = 3; - Assert.AreEqual(1, V[0]); - Assert.AreEqual(2, V[1]); - Assert.AreEqual(3, V[2]); - } - - [Test] - public void Vector3_Index_NegativeExceptin() - { - //the syntax for an expected exception changes from - //NUnit 2.6.4 / Microsoft Unit Test to NUnit 3+ - //but a try-catch block is always guaranteed to work - Vector3 V = new Vector3(); - bool negativeIndexExceptionFound = false; - try - { - V[-1] = 5; - } - catch (Exception) - { - negativeIndexExceptionFound = true; - } - Assert.IsTrue(negativeIndexExceptionFound); - } - - [Test] - public void Vector3_Index_LargeIndexExceptin() - { - //the syntax for an expected exception changes from - //NUnit 2.6.4 / Microsoft Unit Test to NUnit 3+ - //but a try-catch block is always guaranteed to work - Vector3 V = new Vector3(); - bool largeIndexExceptionFound = false; - try - { - V[3] = 6; - } - catch (Exception) - { - largeIndexExceptionFound = true; - } - Assert.IsTrue(largeIndexExceptionFound); - } - - [Test] - public void Vector3_Length() - { - float X = 1, Y = 2, Z = 2; - Vector3 U = new Vector3(X, Y, Z); - Assert.AreEqual((float)System.Math.Sqrt(X * X + Y * Y + Z * Z), U.Length); - } - - [Test] - public void Vector3_LengthFast() - { - float X = 1, Y = 2, Z = 2; - Vector3 U = new Vector3(X, Y, Z); - Assert.AreEqual(1.0f / MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z), U.LengthFast); - } - - [Test] - public void Vector3_Normalized() - { - float X = 2, Y = 4, Z = 16; - Vector3 U = new Vector3(X, Y, Z); - float length = U.Length; - Vector3 V = U.Normalized(); - Assert.AreEqual(U.X / length, V.X); - Assert.AreEqual(U.Y / length, V.Y); - Assert.AreEqual(U.Z / length, V.Z); - } - - [Test] - public void Vector3_NormalizeFast_Instance() - { - float X = 2, Y = 4, Z = 16; - Vector3 U = new Vector3(X, Y, Z); - Vector3 V = U; - V.NormalizeFast(); - float scale = MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z); - Assert.AreEqual(U.X * scale, V.X); - Assert.AreEqual(U.Y * scale, V.Y); - Assert.AreEqual(U.Z * scale, V.Z); - } - - [Test] - public void Vector3_Add() - { - Vector3 T = new Vector3(7, 8, 9); - Vector3 U = new Vector3(23, 89, -34); - Vector3 V = Vector3.Add(T, U); - Assert.AreEqual(T.X + U.X, V.X); - Assert.AreEqual(T.Y + U.Y, V.Y); - Assert.AreEqual(T.Z + U.Z, V.Z); - } - - [Test] - public void Vector3_Subtract() - { - Vector3 T = new Vector3(7, 8, 9); - Vector3 U = new Vector3(23, 89, -34); - Vector3 V = Vector3.Subtract(T, U); - Assert.AreEqual(T.X - U.X, V.X); - Assert.AreEqual(T.Y - U.Y, V.Y); - Assert.AreEqual(T.Z - U.Z, V.Z); - } - - [Test] - public void Vector3_Multiply_Scalar() - { - float scalar = 5.5f; - Vector3 U = new Vector3(23, 89, -34); - Vector3 V = Vector3.Multiply(U, scalar); - Assert.AreEqual(U.X * scalar, V.X); - Assert.AreEqual(U.Y * scalar, V.Y); - Assert.AreEqual(U.Z * scalar, V.Z); - } - - [Test] - public void Vector3_Multiply_Componentwise() - { - Vector3 T = new Vector3(7, 8, 0.5f); - Vector3 U = new Vector3(23, 89, -34); - Vector3 V = Vector3.Multiply(T, U); - Assert.AreEqual(T.X * U.X, V.X); - Assert.AreEqual(T.Y * U.Y, V.Y); - Assert.AreEqual(T.Z * U.Z, V.Z); - } - - [Test] - public void Vector3_Divide_Scalar() - { - float scalar = 5.5f; - Vector3 U = new Vector3(23, 89, -34); - Vector3 V = Vector3.Divide(U, scalar); - //we have to account for a small amount of round off error - //in this division test - Assert.IsTrue(Math.Abs((U.X / scalar) - V.X) < 1e-5); - Assert.IsTrue(Math.Abs((U.Y / scalar) - V.Y) < 1e-5); - Assert.IsTrue(Math.Abs((U.Z / scalar) - V.Z) < 1e-5); - } - - [Test] - public void Vector3_ComponentMin() - { - Vector3 T = new Vector3(1, 55, -100); - Vector3 U = new Vector3(24, 3, 1); - Vector3 V = Vector3.ComponentMin(T, U); - Assert.AreEqual(1, V.X); - Assert.AreEqual(3, V.Y); - Assert.AreEqual(-100, V.Z); - } - - [Test] - public void Vector3_ComponentMinOut() - { - Vector3 T = new Vector3(1, 55, -100); - Vector3 U = new Vector3(24, 3, 1); - Vector3 V; - Vector3.ComponentMin(ref T, ref U, out V); - Assert.AreEqual(1, V.X); - Assert.AreEqual(3, V.Y); - Assert.AreEqual(-100, V.Z); - } - - [Test] - public void Vector3_ComponentMax() - { - Vector3 T = new Vector3(1, 55, -100); - Vector3 U = new Vector3(24, 3, 1); - Vector3 V = Vector3.ComponentMax(T, U); - Assert.AreEqual(24, V.X); - Assert.AreEqual(55, V.Y); - Assert.AreEqual(1, V.Z); - } - - [Test] - public void Vector3_ComponentMaxOut() - { - Vector3 T = new Vector3(1, 55, -100); - Vector3 U = new Vector3(24, 3, 1); - Vector3 V; - Vector3.ComponentMax(ref T, ref U, out V); - Assert.AreEqual(24, V.X); - Assert.AreEqual(55, V.Y); - Assert.AreEqual(1, V.Z); - } - - [Test] - public void Vector3_Min() - { - Vector3 T = new Vector3(1, 2, 3); - Vector3 U = new Vector3(24, 300, 88); - Vector3 result = Vector3.Min(T, U); - Assert.IsTrue(result == T); - } - - [Test] - public void Vector3_Max() - { - Vector3 T = new Vector3(1, 2, 3); - Vector3 U = new Vector3(24, 300, 88); - Vector3 result = Vector3.Max(T, U); - Assert.IsTrue(result == U); - } - - [Test] - public void Vector3_Clamp() - { - Vector3 V = new Vector3(-6, 302, -22); - Vector3 min = new Vector3(-5, -10, -20); - Vector3 max = new Vector3(24, 300, 55); - Vector3 result = Vector3.Clamp(V, min, max); - Assert.AreEqual(result.X, -5); - Assert.AreEqual(result.Y, 300); - Assert.AreEqual(result.Z, -20); - } - - [Test] - public void Vector3_ClampOut() - { - Vector3 V = new Vector3(-6, 302, -22); - Vector3 min = new Vector3(-5, -10, -20); - Vector3 max = new Vector3(24, 300, 55); - Vector3 result; - Vector3.Clamp(ref V, ref min, ref max, out result); - Assert.AreEqual(result.X, -5); - Assert.AreEqual(result.Y, 300); - Assert.AreEqual(result.Z, -20); - } - - [Test] - public void Vector3_Normalize() - { - float X = 64, Y = 144, Z = 16; - Vector3 U = new Vector3(X, Y, Z); - Vector3 V = Vector3.Normalize(U); - float length = U.Length; - Assert.IsTrue(Math.Abs((U.X / length) - V.X) < 1e-5); - Assert.IsTrue(Math.Abs((U.Y / length) - V.Y) < 1e-5); - Assert.IsTrue(Math.Abs((U.Z / length) - V.Z) < 1e-5); - } - - [Test] - public void Vector3_NormalizeOut() - { - float X = 64, Y = 144, Z = 16; - Vector3 U = new Vector3(X, Y, Z); - Vector3 V; - Vector3.Normalize(ref U, out V); - float length = U.Length; - Assert.IsTrue(Math.Abs((U.X / length) - V.X) < 1e-5); - Assert.IsTrue(Math.Abs((U.Y / length) - V.Y) < 1e-5); - Assert.IsTrue(Math.Abs((U.Z / length) - V.Z) < 1e-5); - } - - [Test] - public void Vector3_NormalizeFast_Static() - { - float X = 64, Y = 144, Z = 16; - Vector3 U = new Vector3(X, Y, Z); - Vector3 V = Vector3.NormalizeFast(U); - float scale = MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z); - Assert.AreEqual(U.X * scale, V.X); - Assert.AreEqual(U.Y * scale, V.Y); - Assert.AreEqual(U.Z * scale, V.Z); - } - - [Test] - public void Vector3_NormalizeFast() - { - float X = 64, Y = 144, Z = 16; - Vector3 U = new Vector3(X, Y, Z); - Vector3 V; - Vector3.NormalizeFast(ref U, out V); - float scale = MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z); - Assert.AreEqual(U.X * scale, V.X); - Assert.AreEqual(U.Y * scale, V.Y); - Assert.AreEqual(U.Z * scale, V.Z); - } - - [Test] - public void Vector3_Dot() - { - Vector3 T = new Vector3(7, 8, 9); - Vector3 U = new Vector3(23, 89, -34); - float dot = Vector3.Dot(T, U); - float expected = T.X * U.X + T.Y * U.Y + T.Z * U.Z; - Assert.AreEqual(expected, dot); - } - - [Test] - public void Vector3_Cross() - { - Vector3 T = new Vector3(7, 8, 9); - Vector3 U = new Vector3(23, 89, -34); - Vector3 expected = new Vector3(-1073, 445, 439); - Vector3 result = Vector3.Cross(T, U); - Assert.IsTrue(expected == result); - } - - [Test] - public void Vector3_Lerp() - { - Vector3 T = new Vector3(7, 8, 9); - Vector3 U = new Vector3(23, 89, -34); - float blend = 0.25f; - Vector3 expected = blend * (U - T) + T; - Vector3 result = Vector3.Lerp(T, U, blend); - Assert.IsTrue(expected == result); - } - - [Test] - public void Vector3_LerpOut() - { - Vector3 T = new Vector3(7, 8, 9); - Vector3 U = new Vector3(23, 89, -34); - float blend = 0.25f; - Vector3 expected = blend * (U - T) + T; - Vector3 result; - Vector3.Lerp(ref T, ref U, blend, out result); - Assert.IsTrue(expected == result); - } - - [Test] - public void Vector3_BaryCentric() - { - Vector3 a = new Vector3(7, 8, 9); - Vector3 b = new Vector3(23, 89, -34); - Vector3 c = new Vector3(88, -42, 39); - float u = 0.25f; - float v = 0.75f; - Vector3 expected = a + u * (b - a) + v * (c - a); - Vector3 result = Vector3.BaryCentric(a, b, c, u, v); - Assert.IsTrue(expected == result); - } - - [Test] - public void Vector3_BaryCentricOut() - { - Vector3 a = new Vector3(7, 8, 9); - Vector3 b = new Vector3(23, 89, -34); - Vector3 c = new Vector3(88, -42, 39); - float u = 0.25f; - float v = 0.75f; - Vector3 expected = a + u * (b - a) + v * (c - a); - Vector3 result; - Vector3.BaryCentric(ref a, ref b, ref c, u, v, out result); - Assert.IsTrue(expected == result); - } - - [Test] - public void Vector3_Matrix3TimesVector3_operator() - { - Matrix3 A = new Matrix3(); - A[0, 0] = 16; A[0, 1] = 15; A[0, 2] = 14; - A[1, 0] = 12; A[1, 1] = 11; A[1, 2] = 10; - A[2, 0] = 8; A[2, 1] = 7; A[2, 2] = 6; - - Vector3 input = new Vector3(1, 5, 9); - Vector3 result = A * input; - OpenTK.Vector3 expected = new OpenTK.Vector3(217, 157, 97); - Assert.IsTrue(expected == result); - } - - [Test] - public void Vector3_Equal_operator() - { - Vector3 V = new Vector3(1, 2, 3); - Vector3 U = new Vector3(1, 2, 3); - Assert.IsTrue(U == V); - } - - - } -} diff --git a/tests/OpenTK.Tests/Vector3Tests.fs b/tests/OpenTK.Tests/Vector3Tests.fs new file mode 100644 index 00000000..c12c0f18 --- /dev/null +++ b/tests/OpenTK.Tests/Vector3Tests.fs @@ -0,0 +1,754 @@ +namespace OpenTK.Tests + +open Xunit +open FsCheck +open FsCheck.Xunit +open System +open System.Runtime.InteropServices +open OpenTK + +module Vector3 = + [ |])>] + module Constructors = + // + [] + let ``Triple value constructor sets all components to the correct values`` (a, b, c) = + let v = Vector3(a, b, c) + + Assert.Equal(a, v.X) + Assert.Equal(b, v.Y) + Assert.Equal(c, v.Z) + + [] + let ``Single value constructor sets all components to the correct values`` (a : float32) = + let v = Vector3(a) + + Assert.Equal(a, v.X) + Assert.Equal(a, v.Y) + Assert.Equal(a, v.Z) + + [] + let ``Vector2 value constructor sets all components to the correct values`` (a, b) = + let v1 = Vector2(a, b) + let v2 = Vector3(v1) + + Assert.Equal(v1.X, v2.X) + Assert.Equal(v1.Y, v2.Y) + + Assert.Equal(a, v2.X) + Assert.Equal(b, v2.Y) + Assert.Equal(0.0f, v2.Z) + + [] + let ``Vector3 value constructor sets all components to the correct values`` (a, b, c) = + let v1 = Vector3(a, b, c) + let v2 = Vector3(v1) + + Assert.Equal(v1.X, v2.X) + Assert.Equal(v1.Y, v2.Y) + Assert.Equal(v1.Z, v2.Z) + + Assert.Equal(a, v2.X) + Assert.Equal(b, v2.Y) + Assert.Equal(c, v2.Z) + + [] + let ``Vector4 value constructor sets all components to the correct values`` (a, b, c, d) = + let v1 = Vector4(a, b, c, d) + let v2 = Vector3(v1) + + Assert.Equal(v1.X, v2.X) + Assert.Equal(v1.Y, v2.Y) + Assert.Equal(v1.Z, v2.Z) + + Assert.Equal(a, v2.X) + Assert.Equal(b, v2.Y) + Assert.Equal(c, v2.Z) + + [ |])>] + module Indexing = + // + [] + let ``Index operator accesses the correct components`` (x, y, z) = + let v = Vector3(x, y, z) + + Assert.Equal(x, v.[0]) + Assert.Equal(y, v.[1]) + Assert.Equal(z, v.[2]) + + [] + let ``Indexed set operator throws exception for negative indices`` (x, y, z) = + let mutable v = Vector3(x, y, z) + + (fun() -> v.[-1] <- x) |> Assert.ThrowsIndexExn + + [] + let ``Indexed get operator throws exception for negative indices`` (x, y, z) = + let mutable v = Vector3(x, y, z) + + (fun() -> v.[-1] |> ignore) |> Assert.ThrowsIndexExn + + [] + let ``Indexed set operator throws exception for large indices`` (x, y, z) = + let mutable v = Vector3(x, y, z) + + (fun() -> v.[4] <- x) |> Assert.ThrowsIndexExn + + [] + let ``Indexed get operator throws exception for large indices`` (x, y, z) = + let mutable v = Vector3(x, y, z) + + (fun() -> v.[4] |> ignore) |> Assert.ThrowsIndexExn + + [ |])>] + module Length = + // + [] + let ``Length method follows the pythagorean theorem`` (a, b, c) = + let v = Vector3(a, b, c) + let l = System.Math.Sqrt((float)(a * a + b * b + c * c)) + + Assert.Equal((float32)l, v.Length) + + [] + let ``Fast length method is the same as one divided by the fast inverse square`` (a, b, c) = + let v = Vector3(a, b, c) + let l = 1.0f / MathHelper.InverseSqrtFast(a * a + b * b + c * c) + + Assert.Equal(l, v.LengthFast) + + [] + let ``Length squared method returns each component squared and summed`` (a, b, c) = + let v = Vector3(a, b, c) + let lsq = a * a + b * b + c * c + + Assert.Equal(lsq, v.LengthSquared) + + [ |])>] + module Normalization = + // + [] + let ``Normalization creates a new unit length vector with the correct components`` (a, b, c) = + let v = Vector3(a, b, c) + let l = v.Length + + // Dividing by zero is not supported + if not (approxEq l 0.0f) then + let norm = v.Normalized() + + Assert.ApproximatelyEquivalent(v.X / l, norm.X) + Assert.ApproximatelyEquivalent(v.Y / l, norm.Y) + Assert.ApproximatelyEquivalent(v.Z / l, norm.Z) + + [] + let ``Normalization of instance transforms the instance into a unit length vector with the correct components`` (a, b, c) = + let v = Vector3(a, b, c) + let l = v.Length + + if not (approxEq l 0.0f) then + let norm = Vector3(a, b, c) + norm.Normalize() + + Assert.ApproximatelyEquivalent(v.X / l, norm.X) + Assert.ApproximatelyEquivalent(v.Y / l, norm.Y) + Assert.ApproximatelyEquivalent(v.Z / l, norm.Z) + + [] + let ``Fast approximate normalization of instance transforms the instance into a unit length vector with the correct components`` (a, b, c) = + let v = Vector3(a, b, c) + let norm = Vector3(a, b, c) + norm.NormalizeFast() + + let scale = MathHelper.InverseSqrtFast(a * a + b * b + c * c) + + Assert.ApproximatelyEquivalent(v.X * scale, norm.X) + Assert.ApproximatelyEquivalent(v.Y * scale, norm.Y) + Assert.ApproximatelyEquivalent(v.Z * scale, norm.Z) + + [] + let ``Normalization by reference is the same as division by magnitude`` (a : Vector3) = + // Zero-length vectors can't be normalized + if not (approxEq a.Length 0.0f) then + let norm = a / a.Length + let vRes = Vector3.Normalize(ref a) + + Assert.ApproximatelyEquivalent(norm, vRes) + + [] + let ``Normalization is the same as division by magnitude`` (a : Vector3) = + // Zero-length vectors can't be normalized + if not (approxEq a.Length 0.0f) then + let norm = a / a.Length + + Assert.ApproximatelyEquivalent(norm, Vector3.Normalize(a)); + + [] + let ``Fast approximate normalization by reference is the same as multiplication by the fast inverse square`` (a : Vector3) = + let scale = MathHelper.InverseSqrtFast(a.X * a.X + a.Y * a.Y + a.Z * a.Z) + + let norm = a * scale + let vRes = Vector3.NormalizeFast(ref a) + + Assert.ApproximatelyEquivalent(norm, vRes) + + [] + let ``Fast approximate normalization is the same as multiplication by fast inverse square`` (a : Vector3) = + let scale = MathHelper.InverseSqrtFast(a.X * a.X + a.Y * a.Y + a.Z * a.Z) + + let norm = a * scale + + Assert.ApproximatelyEquivalent(norm, Vector3.NormalizeFast(a)); + + [ |])>] + module Addition = + // + [] + let ``Vector3 addition is the same as component addition`` (a : Vector3, b : Vector3) = + let c = a + b + + Assert.ApproximatelyEquivalent(a.X + b.X,c.X) + Assert.ApproximatelyEquivalent(a.Y + b.Y,c.Y) + Assert.ApproximatelyEquivalent(a.Z + b.Z,c.Z) + + [] + let ``Vector3 addition is commutative`` (a : Vector3, b : Vector3) = + let c = a + b + let c2 = b + a + + Assert.ApproximatelyEquivalent(c, c2) + + [] + let ``Vector3 addition is associative`` (a : Vector3, b : Vector3, c : Vector3) = + let r1 = (a + b) + c + let r2 = a + (b + c) + + Assert.ApproximatelyEquivalent(r1, r2) + + [] + let ``Static Vector3 addition method is the same as component addition`` (a : Vector3, b : Vector3) = + + let v1 = Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z) + let sum = Vector3.Add(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector3 addition method by reference is the same as component addition`` (a : Vector3, b : Vector3) = + + let v1 = Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z) + let sum = Vector3.Add(ref a, ref b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [ |])>] + module Subtraction = + // + [] + let ``Vector3 subtraction is the same as component subtraction`` (a : Vector3, b : Vector3) = + let c = a - b + + Assert.Equal(a.X - b.X,c.X) + Assert.Equal(a.Y - b.Y,c.Y) + Assert.Equal(a.Z - b.Z,c.Z) + + [] + let ``Static Vector3 subtraction method is the same as component addition`` (a : Vector3, b : Vector3) = + + let v1 = Vector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z) + let sum = Vector3.Subtract(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector3 subtraction method by reference is the same as component addition`` (a : Vector3, b : Vector3) = + + let v1 = Vector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z) + let sum = Vector3.Subtract(ref a, ref b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [ |])>] + module Multiplication = + // + [] + let ``Vector3 multiplication is the same as component multiplication`` (a : Vector3, b : Vector3) = + let c = a * b + + Assert.Equal(a.X * b.X,c.X) + Assert.Equal(a.Y * b.Y,c.Y) + Assert.Equal(a.Z * b.Z,c.Z) + + [] + let ``Vector3 multiplication is commutative`` (a : Vector3, b : Vector3) = + let r1 = a * b + let r2 = b * a + + Assert.Equal(r1, r2) + + [] + let ``Left-handed Vector3-scalar multiplication is the same as component-scalar multiplication`` (a : Vector3, f : float32) = + let r = a * f + + Assert.Equal(a.X * f,r.X) + Assert.Equal(a.Y * f,r.Y) + Assert.Equal(a.Z * f,r.Z) + + [] + let ``Right-handed Vector3-scalar multiplication is the same as component-scalar multiplication`` (a : Vector3, f : float32) = + let r = f * a + Assert.Equal(a.X * f,r.X) + Assert.Equal(a.Y * f,r.Y) + Assert.Equal(a.Z * f,r.Z) + + [] + let ``Static method Vector3-scalar multiplication is the same as component-scalar multiplication`` (a : Vector3, f : float32) = + let r = Vector3.Multiply(a, f) + + Assert.Equal(a.X * f,r.X) + Assert.Equal(a.Y * f,r.Y) + Assert.Equal(a.Z * f,r.Z) + + [] + let ``Vector3-Matrix3 multiplication using right-handed notation is the same as vector/row multiplication and summation`` (a : Matrix3, b : Vector3) = + let res = a*b + + let c1 = b.X * a.M11 + b.Y * a.M12 + b.Z * a.M13 + let c2 = b.X * a.M21 + b.Y * a.M22 + b.Z * a.M23 + let c3 = b.X * a.M31 + b.Y * a.M32 + b.Z * a.M33 + + let exp = Vector3(c1, c2, c3) + + Assert.Equal(exp, res) + + [] + let ``Vector3-Matrix3 multiplication using left-handed notation is the same as vector/column multiplication and summation`` (a : Matrix3, b : Vector3) = + let res = b*a + + let c1 = b.X * a.M11 + b.Y * a.M21 + b.Z * a.M31 + let c2 = b.X * a.M12 + b.Y * a.M22 + b.Z * a.M32 + let c3 = b.X * a.M13 + b.Y * a.M23 + b.Z * a.M33 + + let exp = Vector3(c1, c2, c3) + + Assert.Equal(exp, res) + + [] + let ``Static Vector3 multiplication method is the same as component multiplication`` (a : Vector3, b : Vector3) = + + let v1 = Vector3(a.X * b.X, a.Y * b.Y, a.Z * b.Z) + let sum = Vector3.Multiply(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector3 multiplication method by reference is the same as component multiplication`` (a : Vector3, b : Vector3) = + + let v1 = Vector3(a.X * b.X, a.Y * b.Y, a.Z * b.Z) + let sum = Vector3.Multiply(ref a, ref b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [ |])>] + module Division = + // + [] + let ``Vector3-float division is the same as component-float division`` (a : Vector3, f : float32) = + if not (approxEq f 0.0f) then // we don't support diving by zero. + let r = a / f + + Assert.ApproximatelyEquivalent(a.X / f,r.X) + Assert.ApproximatelyEquivalent(a.Y / f,r.Y) + Assert.ApproximatelyEquivalent(a.Z / f,r.Z) + + [] + let ``Static Vector3-Vector3 division method is the same as component division`` (a : Vector3, b : Vector3) = + if not (anyZero3 a || anyZero3 b) then + let v1 = Vector3(a.X / b.X, a.Y / b.Y, a.Z / b.Z) + let sum = Vector3.Divide(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector3-Vector3 divison method by reference is the same as component division`` (a : Vector3, b : Vector3) = + if not (anyZero3 a || anyZero3 b) then + let v1 = Vector3(a.X / b.X, a.Y / b.Y, a.Z / b.Z) + let sum = Vector3.Divide(ref a, ref b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector3-scalar division method is the same as component division`` (a : Vector3, b : float32) = + if not (approxEq b 0.0f) then // we don't support diving by zero. + let v1 = Vector3(a.X / b, a.Y / b, a.Z / b) + let sum = Vector3.Divide(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector3-scalar divison method by reference is the same as component division`` (a : Vector3, b : float32) = + if not (approxEq b 0.0f) then // we don't support diving by zero. + let v1 = Vector3(a.X / b, a.Y / b, a.Z / b) + let sum = Vector3.Divide(ref a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [ |])>] + module Negation = + // + [] + let ``Vector negation operator negates all components`` (x, y, z) = + let v = Vector3(x, y, z) + let vNeg = -v + Assert.Equal(-x, vNeg.X) + Assert.Equal(-y, vNeg.Y) + Assert.Equal(-z, vNeg.Z) + + [ |])>] + module Equality = + // + [] + let ``Vector equality operator is by component`` (x, y, z) = + let v1 = Vector3(x, y, z) + let v2 = Vector3(x, y, z) + let equality = v1 = v2 + + Assert.True(equality) + + [] + let ``Vector inequality operator is by component`` (x, y, z) = + let v1 = Vector3(x, y, z) + let v2 = Vector3(x + 1.0f , y + 1.0f, z + 1.0f) + let inequality = v1 <> v2 + + Assert.True(inequality) + + [] + let ``Vector equality method is by component`` (x, y, z) = + let v1 = Vector3(x, y, z) + let v2 = Vector3(x, y, z) + let notVector = Matrix2() + + let equality = v1.Equals(v2) + let inequalityByOtherType = v1.Equals(notVector) + + Assert.True(equality) + Assert.False(inequalityByOtherType) + + [ |])>] + module Swizzling = + // + [] + let ``Vector swizzling returns the correct composite for X-primary components`` (x, y, z) = + let v = Vector3(x, y, z) + + let xyz = Vector3(x, y, z) + let xzy = Vector3(x, z, y) + let xy = Vector2(x, y) + let xz = Vector2(x, z) + + Assert.Equal(xyz, v); + Assert.Equal(xzy, v.Xzy); + Assert.Equal(xy, v.Xy); + Assert.Equal(xz, v.Xz); + + [] + let ``Vector swizzling returns the correct composite for Y-primary components`` (x, y, z) = + let v = Vector3(x, y, z) + + let yxz = Vector3(y, x, z) + let yzx = Vector3(y, z, x) + let yx = Vector2(y, x) + let yz = Vector2(y, z) + + Assert.Equal(yxz, v.Yxz); + Assert.Equal(yzx, v.Yzx); + Assert.Equal(yx, v.Yx); + Assert.Equal(yz, v.Yz); + + [] + let ``Vector swizzling returns the correct composite for Z-primary components`` (x, y, z) = + let v = Vector3(x, y, z) + + let zxy = Vector3(z, x, y) + let zyx = Vector3(z, y, x) + let zx = Vector2(z, x) + let zy = Vector2(z, y); + + Assert.Equal(zxy, v.Zxy); + Assert.Equal(zyx, v.Zyx); + Assert.Equal(zx, v.Zx); + Assert.Equal(zy, v.Zy); + + [ |])>] + module Interpolation = + // + [] + let ``Linear interpolation is by component`` (a : Vector3, b : Vector3, q) = + + let blend = q + + let rX = blend * (b.X - a.X) + a.X + let rY = blend * (b.Y - a.Y) + a.Y + let rZ = blend * (b.Z - a.Z) + a.Z + let vExp = Vector3(rX, rY, rZ) + + Assert.Equal(vExp, Vector3.Lerp(a, b, q)) + + let vRes = Vector3.Lerp(ref a, ref b, q) + Assert.Equal(vExp, vRes) + + [] + let ``Barycentric interpolation follows the barycentric formula`` (a : Vector3, b : Vector3, c : Vector3, u, v) = + + let r = a + u * (b - a) + v * (c - a) + + Assert.Equal(r, Vector3.BaryCentric(a, b, c, u, v)) + + let vRes = Vector3.BaryCentric(ref a, ref b, ref c, u, v) + Assert.Equal(r, vRes) + + [ |])>] + module ``Vector products`` = + // + [] + let ``Dot product follows the dot product formula`` (a : Vector3, b : Vector3) = + let dot = a.X * b.X + a.Y * b.Y + a.Z * b.Z + + Assert.Equal(dot, Vector3.Dot(a, b)); + + let vRes = Vector3.Dot(ref a, ref b) + Assert.Equal(dot, vRes) + + [] + let ``Cross product follows the cross product formula`` (a : Vector3, b : Vector3) = + let crossX = a.Y * b.Z - a.Z * b.Y + let crossY = a.Z * b.X - a.X * b.Z + let crossZ = a.X * b.Y - a.Y * b.X + let cross = Vector3(crossX, crossY, crossZ) + + Assert.Equal(cross, Vector3.Cross(a, b)); + + let vRes = Vector3.Cross(ref a, ref b) + Assert.Equal(cross, vRes) + + [ |])>] + module ``Magnitude min and max`` = + // + [] + let ``MagnitudeMin selects the vector with equal or lesser magnitude given two vectors`` (v1 : Vector3, v2: Vector3) = + // Results do not matter for equal vectors + if not (v1 = v2) then + let l1 = v1.LengthSquared + let l2 = v2.LengthSquared + + let vMin = Vector3.MagnitudeMin(v1, v2) + + if vMin = v1 then + let v1ShorterThanv2 = l1 < l2 + Assert.True(v1ShorterThanv2) + else + let v2ShorterThanOrEqualTov1 = l2 <= l1 + Assert.True(v2ShorterThanOrEqualTov1) + + [] + let ``MagnitudeMax selects the vector with equal or greater magnitude given two vectors`` (v1 : Vector3, v2: Vector3) = + // Results do not matter for equal vectors + if not (v1 = v2) then + let l1 = v1.LengthSquared + let l2 = v2.LengthSquared + + let vMin = Vector3.MagnitudeMax(v1, v2) + + if vMin = v1 then + let v1LongerThanOrEqualTov2 = l1 >= l2 + Assert.True(v1LongerThanOrEqualTov2) + else + let v2LongerThanv1 = l2 > l1 + Assert.True(v2LongerThanv1) + + [] + let ``MagnitudeMin by reference selects the vector with equal or lesser magnitude given two vectors`` (v1 : Vector3, v2: Vector3) = + // Results do not matter for equal vectors + if not (v1 = v2) then + let l1 = v1.LengthSquared + let l2 = v2.LengthSquared + + let vMin = Vector3.MagnitudeMin(ref v1, ref v2) + + if vMin = v1 then + let v1ShorterThanv2 = l1 < l2 + Assert.True(v1ShorterThanv2) + else + let v2ShorterThanOrEqualTov1 = l2 <= l1 + Assert.True(v2ShorterThanOrEqualTov1) + + [] + let ``MagnitudeMax by reference selects the vector with equal or greater magnitude given two vectors`` (v1 : Vector3, v2: Vector3) = + // Results do not matter for equal vectors + if not (v1 = v2) then + let l1 = v1.LengthSquared + let l2 = v2.LengthSquared + + let vMin = Vector3.MagnitudeMax(ref v1, ref v2) + + if vMin = v1 then + let v1LongerThanOrEqualTov2 = l1 >= l2 + Assert.True(v1LongerThanOrEqualTov2) + else + let v2LongerThanv1 = l2 > l1 + Assert.True(v2LongerThanv1) + + [ |])>] + module ``Component min and max`` = + // + [] + let ``ComponentMin creates a new vector from the smallest components of given vectors`` (v1 : Vector3, v2: Vector3) = + let vMin = Vector3.ComponentMin(v1, v2) + let isComponentSmallest smallComp comp1 comp2 = smallComp <= comp1 && smallComp <= comp2 + + Assert.True(isComponentSmallest vMin.X v1.X v2.X) + Assert.True(isComponentSmallest vMin.Y v1.Y v2.Y) + Assert.True(isComponentSmallest vMin.Z v1.Z v2.Z) + + [] + let ``ComponentMax creates a new vector from the greatest components of given vectors`` (v1 : Vector3, v2: Vector3) = + let vMax = Vector3.ComponentMax(v1, v2) + let isComponentLargest largeComp comp1 comp2 = largeComp >= comp1 && largeComp >= comp2 + + Assert.True(isComponentLargest vMax.X v1.X v2.X) + Assert.True(isComponentLargest vMax.Y v1.Y v2.Y) + Assert.True(isComponentLargest vMax.Z v1.Z v2.Z) + + [] + let ``ComponentMin by reference creates a new vector from the smallest components of given vectors`` (v1 : Vector3, v2: Vector3) = + let vMin = Vector3.ComponentMin(ref v1, ref v2) + let isComponentSmallest smallComp comp1 comp2 = smallComp <= comp1 && smallComp <= comp2 + + Assert.True(isComponentSmallest vMin.X v1.X v2.X) + Assert.True(isComponentSmallest vMin.Y v1.Y v2.Y) + Assert.True(isComponentSmallest vMin.Z v1.Z v2.Z) + + [] + let ``ComponentMax by reference creates a new vector from the greatest components of given vectors`` (v1 : Vector3, v2: Vector3) = + let vMax = Vector3.ComponentMax(ref v1, ref v2) + let isComponentLargest largeComp comp1 comp2 = largeComp >= comp1 && largeComp >= comp2 + + Assert.True(isComponentLargest vMax.X v1.X v2.X) + Assert.True(isComponentLargest vMax.Y v1.Y v2.Y) + Assert.True(isComponentLargest vMax.Z v1.Z v2.Z) + + [ |])>] + module Clamping = + // + [] + let ``Clamping one vector between two other vectors clamps all components between corresponding components`` (a : Vector3, b : Vector3, w : Vector3) = + let res = Vector3.Clamp(w, a, b) + + let expX = if w.X < a.X then a.X else if w.X > b.X then b.X else w.X + let expY = if w.Y < a.Y then a.Y else if w.Y > b.Y then b.Y else w.Y + let expZ = if w.Z < a.Z then a.Z else if w.Z > b.Z then b.Z else w.Z + + Assert.Equal(expX, res.X) + Assert.Equal(expY, res.Y) + Assert.Equal(expZ, res.Z) + + [] + let ``Clamping one vector between two other vectors by reference clamps all components between corresponding components`` (a : Vector3, b : Vector3, w : Vector3) = + let res = Vector3.Clamp(ref w, ref a, ref b) + + let expX = if w.X < a.X then a.X else if w.X > b.X then b.X else w.X + let expY = if w.Y < a.Y then a.Y else if w.Y > b.Y then b.Y else w.Y + let expZ = if w.Z < a.Z then a.Z else if w.Z > b.Z then b.Z else w.Z + + Assert.Equal(expX, res.X) + Assert.Equal(expY, res.Y) + Assert.Equal(expZ, res.Z) + + [ |])>] + module ``Unit vectors``= + // + [] + let ``Unit X is correct`` = + let unitX = Vector3(1.0f, 0.0f, 0.0f) + + Assert.Equal(Vector3.UnitX, unitX) + + [] + let ``Unit Y is correct`` = + let unitY = Vector3(0.0f, 1.0f, 0.0f) + + Assert.Equal(Vector3.UnitY, unitY) + + [] + let ``Unit Z is correct`` = + let unitZ = Vector3(0.0f, 0.0f, 1.0f) + + Assert.Equal(Vector3.UnitZ, unitZ) + + [] + let ``Unit zero is correct`` = + let unitZero = Vector3(0.0f, 0.0f, 0.0f) + + Assert.Equal(Vector3.Zero, unitZero) + + [] + let ``Unit one is correct`` = + let unitOne = Vector3(1.0f, 1.0f, 1.0f) + + Assert.Equal(Vector3.One, unitOne) + + [ |])>] + module Serialization = + // + [] + let ``The absolute size of a Vector3 is always the size of its components`` (v : Vector3) = + let expectedSize = sizeof * 3 + + Assert.Equal(expectedSize, Vector3.SizeInBytes) + Assert.Equal(expectedSize, Marshal.SizeOf(Vector3())) + + [ |])>] + module Transformation = + // + [] + let ``Transformation by quaternion is the same as multiplication by quaternion and its conjugate`` (v : Vector3, q : Quaternion) = + let vectorQuat = Quaternion(v.X, v.Y, v.Z, 0.0f) + let inverse = Quaternion.Invert(q) + + let transformedQuat = q * vectorQuat * inverse + let transformedVector = transformedQuat.Xyz + + Assert.ApproximatelyEquivalent(transformedVector, Vector3.Transform(v, q)) + + [] + let ``Transformation by quaternion by reference is the same as multiplication by quaternion and its conjugate`` (v : Vector3, q : Quaternion) = + let vectorQuat = Quaternion(v.X, v.Y, v.Z, 0.0f) + let inverse = Quaternion.Invert(q) + + let transformedQuat = q * vectorQuat * inverse + let transformedVector = transformedQuat.Xyz + + Assert.ApproximatelyEquivalent(transformedVector, Vector3.Transform(ref v, ref q)) + + [] + let ``Transformation by quaternion by multiplication using right-handed notation is the same as multiplication by quaternion and its conjugate`` (v : Vector3, q : Quaternion) = + let vectorQuat = Quaternion(v.X, v.Y, v.Z, 0.0f) + let inverse = Quaternion.Invert(q) + + let transformedQuat = q * vectorQuat * inverse + let transformedVector = transformedQuat.Xyz + + Assert.ApproximatelyEquivalent(transformedVector, q * v) + + [] + let ``Transformation by identity quaternion does not alter vector`` (v : Vector3) = + let q = Quaternion.Identity + let vectorQuat = Quaternion(v.X, v.Y, v.Z, 0.0f) + let inverse = Quaternion.Invert(q) + + let transformedQuat = q * vectorQuat * inverse + let transformedVector = transformedQuat.Xyz + + Assert.ApproximatelyEquivalent(v, transformedVector) + Assert.ApproximatelyEquivalent(v, Vector3.Transform(v, q)) + Assert.ApproximatelyEquivalent(transformedVector, Vector3.Transform(v, q)) \ No newline at end of file diff --git a/tests/OpenTK.Tests/Vector4Tests.fs b/tests/OpenTK.Tests/Vector4Tests.fs new file mode 100644 index 00000000..a7fce208 --- /dev/null +++ b/tests/OpenTK.Tests/Vector4Tests.fs @@ -0,0 +1,923 @@ +namespace OpenTK.Tests + +open Xunit +open FsCheck +open FsCheck.Xunit +open System +open System.Runtime.InteropServices +open OpenTK + +module Vector4 = + [ |])>] + module Constructors = + // + [] + let ``Triple value constructor sets all components to the correct values`` (x, y, z, w) = + let v = Vector4(x, y, z, w) + + Assert.Equal(x, v.X) + Assert.Equal(y, v.Y) + Assert.Equal(z, v.Z) + Assert.Equal(w, v.W) + + [] + let ``Single value constructor sets all components to the correct values`` (a : float32) = + let v = Vector4(a) + + Assert.Equal(a, v.X) + Assert.Equal(a, v.Y) + Assert.Equal(a, v.Z) + Assert.Equal(a, v.W) + + [] + let ``Vector2 value constructor sets all components to the correct values`` (x, y) = + let v1 = Vector2(x, y) + let v2 = Vector4(v1) + + Assert.Equal(v1.X, v2.X) + Assert.Equal(v1.Y, v2.Y) + + Assert.Equal(x, v2.X) + Assert.Equal(y, v2.Y) + Assert.Equal(0.0f, v2.Z) + Assert.Equal(0.0f, v2.W) + + [] + let ``Vector3 value constructor sets all components to the correct values`` (x, y, z) = + let v1 = Vector3(x, y, z) + let v2 = Vector4(v1) + + Assert.Equal(v1.X, v2.X) + Assert.Equal(v1.Y, v2.Y) + Assert.Equal(v1.Z, v2.Z) + + Assert.Equal(x, v2.X) + Assert.Equal(y, v2.Y) + Assert.Equal(z, v2.Z) + Assert.Equal(0.0f, v2.W) + + [] + let ``Vector3 value and scalar constructor sets all components to the correct values`` (x, y, z, w) = + let v1 = Vector3(x, y, z) + let v2 = Vector4(v1, w) + + Assert.Equal(v1.X, v2.X) + Assert.Equal(v1.Y, v2.Y) + Assert.Equal(v1.Z, v2.Z) + + Assert.Equal(x, v2.X) + Assert.Equal(y, v2.Y) + Assert.Equal(z, v2.Z) + Assert.Equal(w, v2.W) + + [] + let ``Vector4 value constructor sets all components to the correct values`` (x, y, z, w) = + let v1 = Vector4(x, y, z, w) + let v2 = Vector4(v1) + + Assert.Equal(v1.X, v2.X) + Assert.Equal(v1.Y, v2.Y) + Assert.Equal(v1.Z, v2.Z) + Assert.Equal(v1.W, v2.W) + + Assert.Equal(x, v2.X) + Assert.Equal(y, v2.Y) + Assert.Equal(z, v2.Z) + Assert.Equal(w, v2.W) + + [ |])>] + module Indexing = + // + [] + let ``Index operator accesses the correct components`` (x, y, z, w) = + let v = Vector4(x, y, z, w) + + Assert.Equal(x, v.[0]) + Assert.Equal(y, v.[1]) + Assert.Equal(z, v.[2]) + Assert.Equal(w, v.[3]) + + [] + let ``Indexed set operator throws exception for negative indices`` (x, y, z, w) = + let mutable v = Vector4(x, y, z, w) + + (fun() -> v.[-1] <- x) |> Assert.ThrowsIndexExn + + [] + let ``Indexed get operator throws exception for negative indices`` (x, y, z, w) = + let mutable v = Vector4(x, y, z, w) + + (fun() -> v.[-1] |> ignore) |> Assert.ThrowsIndexExn + + [] + let ``Indexed set operator throws exception for large indices`` (x, y, z, w) = + let mutable v = Vector4(x, y, z, w) + + (fun() -> v.[4] <- x) |> Assert.ThrowsIndexExn + + [] + let ``Indexed get operator throws exception for large indices`` (x, y, z, w) = + let mutable v = Vector4(x, y, z, w) + + (fun() -> v.[4] |> ignore) |> Assert.ThrowsIndexExn + + [ |])>] + module Length = + // + [] + let ``Length method follows the pythagorean theorem`` (x, y, z, w) = + let v = Vector4(x, y, z, w) + let l = System.Math.Sqrt((float)(x * x + y * y + z * z + w * w)) + + Assert.Equal((float32)l, v.Length) + + [] + let ``Fast length method is the same as one divided by the fast inverse square`` (x, y, z, w) = + let v = Vector4(x, y, z, w) + let l = 1.0f / MathHelper.InverseSqrtFast(x * x + y * y + z * z + w * w) + + Assert.Equal(l, v.LengthFast) + + [] + let ``Length squared method returns each component squared and summed`` (x, y, z, w) = + let v = Vector4(x, y, z, w) + let lsq = x * x + y * y + z * z + w * w + + Assert.Equal(lsq, v.LengthSquared) + + [ |])>] + module Normalization = + // + [] + let ``Normalization creates a new unit length vector with the correct components`` (x, y, z, w) = + let v = Vector4(x, y, z, w) + let l = v.Length + + // Zero-length vectors can't be normalized + if not (approxEq l 0.0f) then + let norm = v.Normalized() + + Assert.ApproximatelyEquivalent(v.X / l, norm.X) + Assert.ApproximatelyEquivalent(v.Y / l, norm.Y) + Assert.ApproximatelyEquivalent(v.Z / l, norm.Z) + Assert.ApproximatelyEquivalent(v.W / l, norm.W) + + [] + let ``Normalization of instance transforms the instance into a unit length vector with the correct components`` (x, y, z, w) = + let v = Vector4(x, y, z, w) + let l = v.Length + + // Zero-length vectors can't be normalized + if not (approxEq l 0.0f) then + let norm = Vector4(x, y, z, w) + norm.Normalize() + + Assert.ApproximatelyEquivalent(v.X / l, norm.X) + Assert.ApproximatelyEquivalent(v.Y / l, norm.Y) + Assert.ApproximatelyEquivalent(v.Z / l, norm.Z) + Assert.ApproximatelyEquivalent(v.W / l, norm.W) + + [] + let ``Fast approximate normalization of instance transforms the instance into a unit length vector with the correct components`` (x, y, z, w) = + let v = Vector4(x, y, z, w) + let norm = Vector4(x, y, z, w) + norm.NormalizeFast() + + let scale = MathHelper.InverseSqrtFast(x * x + y * y + z * z + w * w) + + Assert.ApproximatelyEquivalent(v.X * scale, norm.X) + Assert.ApproximatelyEquivalent(v.Y * scale, norm.Y) + Assert.ApproximatelyEquivalent(v.Z * scale, norm.Z) + Assert.ApproximatelyEquivalent(v.W * scale, norm.W) + + [] + let ``Normalization by reference is the same as division by magnitude`` (a : Vector4) = + // Zero-length vectors can't be normalized + if not (approxEq a.Length 0.0f) then + let norm = a / a.Length + let vRes = Vector4.Normalize(ref a) + + Assert.ApproximatelyEquivalent(norm, vRes) + + [] + let ``Normalization is the same as division by magnitude`` (a : Vector4) = + // Zero-length vectors can't be normalized + if not (approxEq a.Length 0.0f) then + let norm = a / a.Length + + Assert.ApproximatelyEquivalent(norm, Vector4.Normalize(a)); + + [] + let ``Fast approximate normalization by reference is the same as multiplication by the fast inverse square`` (a : Vector4) = + let scale = MathHelper.InverseSqrtFast(a.X * a.X + a.Y * a.Y + a.Z * a.Z + a.W * a.W) + + let norm = a * scale + let vRes = Vector4.NormalizeFast(ref a) + + Assert.ApproximatelyEquivalent(norm, vRes) + + [] + let ``Fast approximate normalization is the same as multiplication by the fast inverse square`` (a : Vector4) = + let scale = MathHelper.InverseSqrtFast(a.X * a.X + a.Y * a.Y + a.Z * a.Z + a.W * a.W) + let norm = a * scale + + Assert.ApproximatelyEquivalent(norm, Vector4.NormalizeFast(a)); + + [ |])>] + module Addition = + // + [] + let ``Vector4 addition is the same as component addition`` (a : Vector4, b : Vector4) = + let c = a + b + + Assert.ApproximatelyEquivalent(a.X + b.X,c.X) + Assert.ApproximatelyEquivalent(a.Y + b.Y,c.Y) + Assert.ApproximatelyEquivalent(a.Z + b.Z,c.Z) + Assert.ApproximatelyEquivalent(a.W + b.W,c.W) + + [] + let ``Vector4 addition is commutative`` (a : Vector4, b : Vector4) = + let c = a + b + let c2 = b + a + + Assert.ApproximatelyEquivalent(c, c2) + + [] + let ``Vector4 addition is associative`` (a : Vector4, b : Vector4, c : Vector4) = + let r1 = (a + b) + c + let r2 = a + (b + c) + + Assert.ApproximatelyEquivalent(r1, r2) + + [] + let ``Static Vector4 addition method is the same as component addition`` (a : Vector4, b : Vector4) = + + let v1 = Vector4(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W) + let sum = Vector4.Add(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector4 addition method by reference is the same as component addition`` (a : Vector4, b : Vector4) = + + let v1 = Vector4(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W) + let sum = Vector4.Add(ref a, ref b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [ |])>] + module Subtraction = + // + [] + let ``Vector4 subtraction is the same as component subtraction`` (a : Vector4, b : Vector4) = + let c = a - b + + Assert.Equal(a.X - b.X,c.X) + Assert.Equal(a.Y - b.Y,c.Y) + Assert.Equal(a.Z - b.Z,c.Z) + Assert.Equal(a.W - b.W,c.W) + + [] + let ``Static Vector4 subtraction method is the same as component addition`` (a : Vector4, b : Vector4) = + + let v1 = Vector4(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W) + let sum = Vector4.Subtract(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector4 subtraction method by reference is the same as component addition`` (a : Vector4, b : Vector4) = + + let v1 = Vector4(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W) + let sum = Vector4.Subtract(ref a, ref b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [ |])>] + module Multiplication = + // + [] + let ``Vector4 multiplication is the same as component multiplication`` (a : Vector4, b : Vector4) = + let c = a * b + + Assert.Equal(a.X * b.X,c.X) + Assert.Equal(a.Y * b.Y,c.Y) + Assert.Equal(a.Z * b.Z,c.Z) + Assert.Equal(a.W * b.W,c.W) + + + [] + let ``Vector4 multiplication is commutative`` (a : Vector4, b : Vector4) = + let r1 = a * b + let r2 = b * a + + Assert.Equal(r1, r2) + + [] + let ``Left-handed Vector4-scalar multiplication is the same as component-scalar multiplication`` (a : Vector4, f : float32) = + let r = a * f + + Assert.Equal(a.X * f,r.X) + Assert.Equal(a.Y * f,r.Y) + Assert.Equal(a.Z * f,r.Z) + Assert.Equal(a.W * f,r.W) + + [] + let ``Right-handed Vector4-scalar multiplication is the same as component-scalar multiplication`` (a : Vector4, f : float32) = + let r = f * a + Assert.Equal(a.X * f,r.X) + Assert.Equal(a.Y * f,r.Y) + Assert.Equal(a.Z * f,r.Z) + Assert.Equal(a.W * f,r.W) + + [] + let ``Static method Vector4-scalar multiplication is the same as component-scalar multiplication`` (a : Vector4, f : float32) = + let r = Vector4.Multiply(a, f) + + Assert.Equal(a.X * f,r.X) + Assert.Equal(a.Y * f,r.Y) + Assert.Equal(a.Z * f,r.Z) + Assert.Equal(a.W * f,r.W) + + [] + let ``Vector4-Matrix4 multiplication using right-handed notation is the same as vector/row multiplication and summation`` (a : Matrix4, b : Vector4) = + let res = a*b + + let c1 = b.X * a.M11 + b.Y * a.M12 + b.Z * a.M13 + b.W * a.M14 + let c2 = b.X * a.M21 + b.Y * a.M22 + b.Z * a.M23 + b.W * a.M24 + let c3 = b.X * a.M31 + b.Y * a.M32 + b.Z * a.M33 + b.W * a.M34 + let c4 = b.X * a.M41 + b.Y * a.M42 + b.Z * a.M43 + b.W * a.M44 + + let exp = Vector4(c1, c2, c3, c4) + + Assert.Equal(exp, res) + + [] + let ``Vector4-Matrix4 multiplication using left-handed notation is the same as vector/column multiplication and summation`` (a : Matrix4, b : Vector4) = + let res = b*a + + let c1 = b.X * a.M11 + b.Y * a.M21 + b.Z * a.M31 + b.W * a.M41 + let c2 = b.X * a.M12 + b.Y * a.M22 + b.Z * a.M32 + b.W * a.M42 + let c3 = b.X * a.M13 + b.Y * a.M23 + b.Z * a.M33 + b.W * a.M43 + let c4 = b.X * a.M14 + b.Y * a.M24 + b.Z * a.M34 + b.W * a.M44 + + let exp = Vector4(c1, c2, c3, c4) + + Assert.Equal(exp, res) + + [] + let ``Static Vector4 multiplication method is the same as component multiplication`` (a : Vector4, b : Vector4) = + + let v1 = Vector4(a.X * b.X, a.Y * b.Y, a.Z * b.Z, a.W * b.W) + let sum = Vector4.Multiply(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector4 multiplication method by reference is the same as component multiplication`` (a : Vector4, b : Vector4) = + + let v1 = Vector4(a.X * b.X, a.Y * b.Y, a.Z * b.Z, a.W * b.W) + let sum = Vector4.Multiply(ref a, ref b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [ |])>] + module Division = + // + [] + let ``Vector4-float division is the same as component-float division`` (a : Vector4, f : float32) = + if not (approxEq f 0.0f) then // we don't support diving by zero. + let r = a / f + + Assert.ApproximatelyEquivalent(a.X / f, r.X) + Assert.ApproximatelyEquivalent(a.Y / f, r.Y) + Assert.ApproximatelyEquivalent(a.Z / f, r.Z) + Assert.ApproximatelyEquivalent(a.W / f, r.W) + + [] + let ``Static Vector4-Vector4 division method is the same as component division`` (a : Vector4, b : Vector4) = + if not (anyZero4 a || anyZero4 b) then + let v1 = Vector4(a.X / b.X, a.Y / b.Y, a.Z / b.Z, a.W / b.W) + let sum = Vector4.Divide(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector4-Vector4 divison method by reference is the same as component division`` (a : Vector4, b : Vector4) = + if not (anyZero4 a || anyZero4 b) then + let v1 = Vector4(a.X / b.X, a.Y / b.Y, a.Z / b.Z, a.W / b.W) + let sum = Vector4.Divide(ref a, ref b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector4-scalar division method is the same as component division`` (a : Vector4, b : float32) = + if not (approxEq b 0.0f) then // we don't support diving by zero. + let v1 = Vector4(a.X / b, a.Y / b, a.Z / b, a.W / b) + let sum = Vector4.Divide(a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [] + let ``Static Vector4-scalar divison method by reference is the same as component division`` (a : Vector4, b : float32) = + if not (approxEq b 0.0f) then // we don't support diving by zero. + let v1 = Vector4(a.X / b, a.Y / b, a.Z / b, a.W / b) + let sum = Vector4.Divide(ref a, b) + + Assert.ApproximatelyEquivalent(v1, sum) + + [ |])>] + module Negation = + // + [] + let ``Vector negation operator negates all components`` (x, y, z, w) = + let v = Vector4(x, y, z, w) + let vNeg = -v + Assert.Equal(-x, vNeg.X) + Assert.Equal(-y, vNeg.Y) + Assert.Equal(-z, vNeg.Z) + Assert.Equal(-w, vNeg.W) + + [ |])>] + module Equality = + // + [] + let ``Vector equality operator is by component`` (x, y, z, w) = + let v1 = Vector4(x, y, z, w) + let v2 = Vector4(x, y, z, w) + let equality = v1 = v2 + + Assert.True(equality) + + [] + let ``Vector inequality operator is by component`` (x, y, z, w) = + let v1 = Vector4(x, y, z, w) + let v2 = Vector4(x + 1.0f , y + 1.0f, z + 1.0f, w + 1.0f) + let inequality = v1 <> v2 + + Assert.True(inequality) + + [] + let ``Vector equality method is by component`` (x, y, z, w) = + let v1 = Vector4(x, y, z, w) + let v2 = Vector4(x, y, z, w) + let notVector = Matrix2() + + let equality = v1.Equals(v2) + let inequalityByOtherType = v1.Equals(notVector) + + Assert.True(equality) + Assert.False(inequalityByOtherType) + + [] + let ``Vector equality method returns false for other classes`` (x, y, z, w) = + let v1 = Vector4(x, y, z, w) + let notVector = Matrix2() + + let inequalityByOtherType = v1.Equals(notVector) + + Assert.False(inequalityByOtherType) + + [ |])>] + module Swizzling = + // + [] + let ``Vector swizzling returns the correct composite for X-primary components`` (x, y, z, w) = + + let v = Vector4(x, y, z, w) + + let xyzw = v + let xywz = Vector4(x, y, w, z) + let xzyw = Vector4(x, z, y, w) + let xzwy = Vector4(x, z, w, y) + let xwyz = Vector4(x, w, y, z) + let xwzy = Vector4(x, w, z, y) + + let xyz = Vector3(x, y, z) + let xyw = Vector3(x, y, w) + let xzy = Vector3(x, z, y) + let xzw = Vector3(x, z, w) + let xwy = Vector3(x, w, y) + let xwz = Vector3(x, w, z) + + let xy = Vector2(x, y) + let xz = Vector2(x, z) + let xw = Vector2(x, w) + + // X primary + Assert.Equal(xyzw, v) + Assert.Equal(xywz, v.Xywz) + Assert.Equal(xzyw, v.Xzyw) + Assert.Equal(xzwy, v.Xzwy) + Assert.Equal(xwyz, v.Xwyz) + Assert.Equal(xwzy, v.Xwzy) + + Assert.Equal(xyz, v.Xyz) + Assert.Equal(xyw, v.Xyw) + Assert.Equal(xzy, v.Xzy) + Assert.Equal(xzw, v.Xzw) + Assert.Equal(xwy, v.Xwy) + Assert.Equal(xwz, v.Xwz) + + Assert.Equal(xy, v.Xy) + Assert.Equal(xz, v.Xz) + Assert.Equal(xw, v.Xw) + + [] + let ``Vector swizzling returns the correct composite for Y-primary components`` (x, y, z, w) = + + let v = Vector4(x, y, z, w) + + let yxzw = Vector4(y, x, z, w) + let yxwz = Vector4(y, x, w, z) + let yyzw = Vector4(y, y, z, w) + let yywz = Vector4(y, y, w, z) + let yzxw = Vector4(y, z, x, w) + let yzwx = Vector4(y, z, w, x) + let ywxz = Vector4(y, w, x, z) + let ywzx = Vector4(y, w, z, x) + + let yxz = Vector3(y, x, z) + let yxw = Vector3(y, x, w) + let yzx = Vector3(y, z, x) + let yzw = Vector3(y, z, w) + let ywx = Vector3(y, w, x) + let ywz = Vector3(y, w, z) + + let yx = Vector2(y, x) + let yz = Vector2(y, z) + let yw = Vector2(y, w) + + // Y primary + Assert.Equal(yxzw, v.Yxzw) + Assert.Equal(yxwz, v.Yxwz) + Assert.Equal(yyzw, v.Yyzw) + Assert.Equal(yywz, v.Yywz) + Assert.Equal(yzxw, v.Yzxw) + Assert.Equal(yzwx, v.Yzwx) + Assert.Equal(ywxz, v.Ywxz) + Assert.Equal(ywzx, v.Ywzx) + + Assert.Equal(yxz, v.Yxz) + Assert.Equal(yxw, v.Yxw) + Assert.Equal(yzx, v.Yzx) + Assert.Equal(yzw, v.Yzw) + Assert.Equal(ywx, v.Ywx) + Assert.Equal(ywz, v.Ywz) + + Assert.Equal(yx, v.Yx) + Assert.Equal(yz, v.Yz) + Assert.Equal(yw, v.Yw) + + [] + let ``Vector swizzling returns the correct composite for Z-primary components`` (x, y, z, w) = + + let v = Vector4(x, y, z, w) + + let zxyw = Vector4(z, x, y, w) + let zxwy = Vector4(z, x, w, y) + let zyxw = Vector4(z, y, x, w) + let zywx = Vector4(z, y, w, x) + let zwxy = Vector4(z, w, x, y) + let zwyx = Vector4(z, w, y, x) + let zwzy = Vector4(z, w, z, y) + + let zxy = Vector3(z, x, y) + let zxw = Vector3(z, x, w) + let zyx = Vector3(z, y, x) + let zyw = Vector3(z, y, w) + let zwx = Vector3(z, w, x) + let zwy = Vector3(z, w, y) + + let zx = Vector2(z, x) + let zy = Vector2(z, y) + let zw = Vector2(z, w) + + // Z primary + Assert.Equal(zxyw, v.Zxyw) + Assert.Equal(zxwy, v.Zxwy) + Assert.Equal(zyxw, v.Zyxw) + Assert.Equal(zywx, v.Zywx) + Assert.Equal(zwxy, v.Zwxy) + Assert.Equal(zwyx, v.Zwyx) + Assert.Equal(zwzy, v.Zwzy) + + Assert.Equal(zxy, v.Zxy) + Assert.Equal(zxw, v.Zxw) + Assert.Equal(zyx, v.Zyx) + Assert.Equal(zyw, v.Zyw) + Assert.Equal(zwx, v.Zwx) + Assert.Equal(zwy, v.Zwy) + + Assert.Equal(zx, v.Zx) + Assert.Equal(zy, v.Zy) + Assert.Equal(zw, v.Zw) + + [] + let ``Vector swizzling returns the correct composite for W-primary components`` (x, y, z, w) = + + let v = Vector4(x, y, z, w) + + let wxyz = Vector4(w, x, y, z) + let wxzy = Vector4(w, x, z, y) + let wyxz = Vector4(w, y, x, z) + let wyzx = Vector4(w, y, z, x) + let wzxy = Vector4(w, z, x, y) + let wzyx = Vector4(w, z, y, x) + let wzyw = Vector4(w, z, y, w) + + let wxy = Vector3(w, x, y) + let wxz = Vector3(w, x, z) + let wyx = Vector3(w, y, x) + let wyz = Vector3(w, y, z) + let wzx = Vector3(w, z, x) + let wzy = Vector3(w, z, y) + + let wx = Vector2(w, x) + let wy = Vector2(w, y) + let wz = Vector2(w, z) + + // W primary + Assert.Equal(wxyz, v.Wxyz) + Assert.Equal(wxzy, v.Wxzy) + Assert.Equal(wyxz, v.Wyxz) + Assert.Equal(wyzx, v.Wyzx) + Assert.Equal(wzxy, v.Wzxy) + Assert.Equal(wzyx, v.Wzyx) + Assert.Equal(wzyw, v.Wzyw) + + Assert.Equal(wxy, v.Wxy) + Assert.Equal(wxz, v.Wxz) + Assert.Equal(wyx, v.Wyx) + Assert.Equal(wyz, v.Wyz) + Assert.Equal(wzx, v.Wzx) + Assert.Equal(wzy, v.Wzy) + + Assert.Equal(wx, v.Wx) + Assert.Equal(wy, v.Wy) + Assert.Equal(wz, v.Wz) + + [ |])>] + module Interpolation = + // + [] + let ``Linear interpolation is by component`` (a : Vector4, b : Vector4, q) = + + let blend = q + + let rX = blend * (b.X - a.X) + a.X + let rY = blend * (b.Y - a.Y) + a.Y + let rZ = blend * (b.Z - a.Z) + a.Z + let rW = blend * (b.W - a.W) + a.W + let vExp = Vector4(rX, rY, rZ, rW) + + Assert.Equal(vExp, Vector4.Lerp(a, b, q)) + + let vRes = Vector4.Lerp(ref a, ref b, q) + Assert.Equal(vExp, vRes) + + [] + let ``Barycentric interpolation follows the barycentric formula`` (a : Vector4, b : Vector4, c : Vector4, u, v) = + + let r = a + u * (b - a) + v * (c - a) + + Assert.Equal(r, Vector4.BaryCentric(a, b, c, u, v)) + + let vRes = Vector4.BaryCentric(ref a, ref b, ref c, u, v) + Assert.Equal(r, vRes) + + [ |])>] + module ``Vector products`` = + // + [] + let ``Dot product method follows the dot product formula`` (a : Vector4, b : Vector4) = + let dot = a.X * b.X + a.Y * b.Y + a.Z * b.Z + a.W * b.W + + Assert.Equal(dot, Vector4.Dot(a, b)); + + let vRes = Vector4.Dot(ref a, ref b) + Assert.Equal(dot, vRes) + + [ |])>] + module ``Magnitude min and max`` = + // + [] + let ``MagnitudeMin selects the vector with equal or lesser magnitude given two vectors`` (v1 : Vector4, v2: Vector4) = + // Results do not matter for equal vectors + if not (v1 = v2) then + let l1 = v1.LengthSquared + let l2 = v2.LengthSquared + + let vMin = Vector4.MagnitudeMin(v1, v2) + + if vMin = v1 then + let v1ShorterThanv2 = l1 < l2 + Assert.True(v1ShorterThanv2) + else + let v2ShorterThanOrEqualTov1 = l2 <= l1 + Assert.True(v2ShorterThanOrEqualTov1) + + [] + let ``MagnitudeMax selects the vector with equal or greater magnitude given two vectors`` (v1 : Vector4, v2: Vector4) = + // Results do not matter for equal vectors + if not (v1 = v2) then + let l1 = v1.LengthSquared + let l2 = v2.LengthSquared + + let vMin = Vector4.MagnitudeMax(v1, v2) + + if vMin = v1 then + let v1LongerThanOrEqualTov2 = l1 >= l2 + Assert.True(v1LongerThanOrEqualTov2) + else + let v2LongerThanv1 = l2 > l1 + Assert.True(v2LongerThanv1) + + [] + let ``MagnitudeMin by reference selects the vector with equal or lesser magnitude given two vectors`` (v1 : Vector4, v2: Vector4) = + // Results do not matter for equal vectors + if not (v1 = v2) then + let l1 = v1.LengthSquared + let l2 = v2.LengthSquared + + let vMin = Vector4.MagnitudeMin(ref v1, ref v2) + + if vMin = v1 then + let v1ShorterThanv2 = l1 < l2 + Assert.True(v1ShorterThanv2) + else + let v2ShorterThanOrEqualTov1 = l2 <= l1 + Assert.True(v2ShorterThanOrEqualTov1) + + [] + let ``MagnitudeMax by reference selects the vector with equal or greater magnitude given two vectors`` (v1 : Vector4, v2: Vector4) = + // Results do not matter for equal vectors + if not (v1 = v2) then + let l1 = v1.LengthSquared + let l2 = v2.LengthSquared + + let vMin = Vector4.MagnitudeMax(ref v1, ref v2) + + if vMin = v1 then + let v1LongerThanOrEqualTov2 = l1 >= l2 + Assert.True(v1LongerThanOrEqualTov2) + else + let v2LongerThanv1 = l2 > l1 + Assert.True(v2LongerThanv1) + + [ |])>] + module ``Component min and max`` = + // + [] + let ``ComponentMin creates a new vector from the smallest components of given vectors`` (v1 : Vector4, v2: Vector4) = + let vMin = Vector4.ComponentMin(v1, v2) + let isComponentSmallest smallComp comp1 comp2 = smallComp <= comp1 && smallComp <= comp2 + + Assert.True(isComponentSmallest vMin.X v1.X v2.X) + Assert.True(isComponentSmallest vMin.Y v1.Y v2.Y) + Assert.True(isComponentSmallest vMin.Z v1.Z v2.Z) + Assert.True(isComponentSmallest vMin.W v1.W v2.W) + + [] + let ``ComponentMax creates a new vector from the greatest components of given vectors`` (v1 : Vector4, v2: Vector4) = + let vMax = Vector4.ComponentMax(v1, v2) + let isComponentLargest largeComp comp1 comp2 = largeComp >= comp1 && largeComp >= comp2 + + Assert.True(isComponentLargest vMax.X v1.X v2.X) + Assert.True(isComponentLargest vMax.Y v1.Y v2.Y) + Assert.True(isComponentLargest vMax.Z v1.Z v2.Z) + Assert.True(isComponentLargest vMax.W v1.W v2.W) + + [] + let ``ComponentMin by reference creates a new vector from the smallest components of given vectors`` (v1 : Vector4, v2: Vector4) = + let vMin = Vector4.ComponentMin(ref v1, ref v2) + let isComponentSmallest smallComp comp1 comp2 = smallComp <= comp1 && smallComp <= comp2 + + Assert.True(isComponentSmallest vMin.X v1.X v2.X) + Assert.True(isComponentSmallest vMin.Y v1.Y v2.Y) + Assert.True(isComponentSmallest vMin.Z v1.Z v2.Z) + Assert.True(isComponentSmallest vMin.W v1.W v2.W) + + [] + let ``ComponentMax by reference creates a new vector from the greatest components of given vectors`` (v1 : Vector4, v2: Vector4) = + let vMax = Vector4.ComponentMax(ref v1, ref v2) + let isComponentLargest largeComp comp1 comp2 = largeComp >= comp1 && largeComp >= comp2 + + Assert.True(isComponentLargest vMax.X v1.X v2.X) + Assert.True(isComponentLargest vMax.Y v1.Y v2.Y) + Assert.True(isComponentLargest vMax.Z v1.Z v2.Z) + Assert.True(isComponentLargest vMax.W v1.W v2.W) + + + [ |])>] + module Clamping = + // + [] + let ``Clamping one vector between two other vectors clamps all components between corresponding components`` (a : Vector4, b : Vector4, w : Vector4) = + let expX = if w.X < a.X then a.X else if w.X > b.X then b.X else w.X + let expY = if w.Y < a.Y then a.Y else if w.Y > b.Y then b.Y else w.Y + let expZ = if w.Z < a.Z then a.Z else if w.Z > b.Z then b.Z else w.Z + let expW = if w.W < a.W then a.W else if w.W > b.W then b.W else w.W + + let res = Vector4.Clamp(w, a, b) + + Assert.Equal(expX, res.X) + Assert.Equal(expY, res.Y) + Assert.Equal(expZ, res.Z) + Assert.Equal(expW, res.W) + + [] + let ``Clamping one vector between two other vectors by reference clamps all components between corresponding components`` (a : Vector4, b : Vector4, w : Vector4) = + let expX = if w.X < a.X then a.X else if w.X > b.X then b.X else w.X + let expY = if w.Y < a.Y then a.Y else if w.Y > b.Y then b.Y else w.Y + let expZ = if w.Z < a.Z then a.Z else if w.Z > b.Z then b.Z else w.Z + let expW = if w.W < a.W then a.W else if w.W > b.W then b.W else w.W + + let res = Vector4.Clamp(ref w, ref a, ref b) + + Assert.Equal(expX, res.X) + Assert.Equal(expY, res.Y) + Assert.Equal(expZ, res.Z) + Assert.Equal(expW, res.W) + + [ |])>] + module ``Unit vectors``= + // + [] + let ``Unit X is correct`` = + let unitX = Vector4(1.0f, 0.0f, 0.0f, 0.0f) + + Assert.Equal(Vector4.UnitX, unitX) + + [] + let ``Unit Y is correct`` = + let unitY = Vector4(0.0f, 1.0f, 0.0f, 0.0f) + + Assert.Equal(Vector4.UnitY, unitY) + + [] + let ``Unit Z is correct`` = + let unitZ = Vector4(0.0f, 0.0f, 1.0f, 0.0f) + + Assert.Equal(Vector4.UnitZ, unitZ) + + [] + let ``Unit W is correct`` = + let unitW = Vector4(0.0f, 0.0f, 0.0f, 1.0f) + + Assert.Equal(Vector4.UnitW, unitW) + + [] + let ``Unit zero is correct`` = + let unitZero = Vector4(0.0f, 0.0f, 0.0f, 0.0f) + + Assert.Equal(Vector4.Zero, unitZero) + + [] + let ``Unit one is correct`` = + let unitOne = Vector4(1.0f, 1.0f, 1.0f, 1.0f) + + Assert.Equal(Vector4.One, unitOne) + + [ |])>] + module Serialization = + // + [] + let ``The absolute size of a Vector4 is always the size of its components`` (v : Vector4) = + let expectedSize = sizeof * 4 + + Assert.Equal(expectedSize, Vector4.SizeInBytes) + Assert.Equal(expectedSize, Marshal.SizeOf(Vector4())) + + [ |])>] + module Transformation = + // + [] + let ``Transformation by quaternion with static method is the same as multiplication by quaternion and its conjugate`` (v : Vector4, q : Quaternion) = + let vectorQuat = Quaternion(v.X, v.Y, v.Z, v.W) + let inverse = Quaternion.Invert(q) + + let transformedQuat = q * vectorQuat * inverse + let transformedVector = Vector4(transformedQuat.X, transformedQuat.Y, transformedQuat.Z, transformedQuat.W) + + Assert.ApproximatelyEquivalent(transformedVector, Vector4.Transform(v, q)) + + [] + let ``Transformation by quaternion with static method by reference is the same as multiplication by quaternion and its conjugate`` (v : Vector4, q : Quaternion) = + let vectorQuat = Quaternion(v.X, v.Y, v.Z, v.W) + let inverse = Quaternion.Invert(q) + + let transformedQuat = q * vectorQuat * inverse + let transformedVector = Vector4(transformedQuat.X, transformedQuat.Y,transformedQuat.Z, transformedQuat.W) + + Assert.ApproximatelyEquivalent(transformedVector, Vector4.Transform(ref v, ref q)) + + [] + let ``Transformation by quaternion by multiplication using right-handed notation is the same as multiplication by quaternion and its conjugate`` (v : Vector4, q : Quaternion) = + let vectorQuat = Quaternion(v.X, v.Y, v.Z, v.W) + let inverse = Quaternion.Invert(q) + + let transformedQuat = q * vectorQuat * inverse + let transformedVector = Vector4(transformedQuat.X, transformedQuat.Y, transformedQuat.Z, transformedQuat.W) + + Assert.ApproximatelyEquivalent(transformedVector, q * v) \ No newline at end of file diff --git a/tests/OpenTK.Tests/packages.config b/tests/OpenTK.Tests/packages.config deleted file mode 100644 index 1f8800b2..00000000 --- a/tests/OpenTK.Tests/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/tests/OpenTK.Tests/paket.references b/tests/OpenTK.Tests/paket.references new file mode 100644 index 00000000..ecbc089e --- /dev/null +++ b/tests/OpenTK.Tests/paket.references @@ -0,0 +1,2 @@ +FsCheck.Xunit +xunit.assert