From 16d53b92eb5ca5521c272d00071a43e1792e2294 Mon Sep 17 00:00:00 2001 From: notgiven688 <37874600+notgiven688@users.noreply.github.com> Date: Sun, 24 Nov 2024 16:12:36 +0100 Subject: [PATCH] Enable conditional compilation for double precision support (#205) Co-authored-by: notgiven688 Co-authored-by: Wulferis --- .github/workflows/jitter-tests.yml | 52 ++- .github/workflows/publish.yml | 114 ++--- src/.gitignore | 1 + .../CollisionFilter/INarrowPhaseFilter.cs | 2 +- .../TriangleEdgeCollisionFilter.cs | 36 +- src/Jitter2/Collision/CollisionHelper.cs | 28 +- src/Jitter2/Collision/DynamicTree.RayCast.cs | 18 +- src/Jitter2/Collision/DynamicTree.cs | 32 +- .../Collision/NarrowPhase/ConvexPolytope.cs | 76 ++-- .../Collision/NarrowPhase/NarrowPhase.cs | 170 ++++---- .../Collision/NarrowPhase/SimplexSolver.cs | 66 +-- .../Collision/NarrowPhase/SimplexSolverAB.cs | 82 ++-- src/Jitter2/Collision/Shapes/BoxShape.cs | 62 +-- src/Jitter2/Collision/Shapes/CapsuleShape.cs | 42 +- src/Jitter2/Collision/Shapes/ConeShape.cs | 60 +-- .../Collision/Shapes/ConvexHullShape.cs | 30 +- src/Jitter2/Collision/Shapes/CylinderShape.cs | 58 +-- .../Collision/Shapes/FatTriangleShape.cs | 14 +- .../Collision/Shapes/PointCloudShape.cs | 12 +- .../Collision/Shapes/RigidBodyShape.cs | 8 +- src/Jitter2/Collision/Shapes/Shape.cs | 20 +- src/Jitter2/Collision/Shapes/ShapeHelper.cs | 22 +- src/Jitter2/Collision/Shapes/SphereShape.cs | 40 +- .../Collision/Shapes/TransformedShape.cs | 2 +- src/Jitter2/Collision/Shapes/TriangleMesh.cs | 2 +- src/Jitter2/Collision/Shapes/TriangleShape.cs | 12 +- .../Dynamics/Constraints/AngularMotor.cs | 32 +- .../Dynamics/Constraints/BallSocket.cs | 22 +- src/Jitter2/Dynamics/Constraints/ConeLimit.cs | 60 +-- .../Dynamics/Constraints/Constraint.cs | 16 +- .../Dynamics/Constraints/DistanceLimit.cs | 65 +-- .../Dynamics/Constraints/FixedAngle.cs | 30 +- .../Dynamics/Constraints/HingeAngle.cs | 68 +-- .../Dynamics/Constraints/Internal/QMatrix.cs | 52 +-- src/Jitter2/Dynamics/Constraints/Limit.cs | 20 +- .../Dynamics/Constraints/LinearMotor.cs | 34 +- .../Dynamics/Constraints/PointOnLine.cs | 46 +- .../Dynamics/Constraints/PointOnPlane.cs | 52 +-- .../Dynamics/Constraints/TwistAngle.cs | 68 +-- src/Jitter2/Dynamics/Contact.cs | 406 +++++++++--------- src/Jitter2/Dynamics/RigidBody.cs | 88 ++-- src/Jitter2/Jitter2.csproj | 88 ++-- src/Jitter2/LinearMath/JAngle.cs | 30 +- src/Jitter2/LinearMath/JBBox.cs | 56 +-- src/Jitter2/LinearMath/JMatrix.cs | 174 ++++---- src/Jitter2/LinearMath/JQuaternion.cs | 124 +++--- src/Jitter2/LinearMath/JVector.cs | 126 +++--- src/Jitter2/LinearMath/MathHelper.cs | 72 ++-- src/Jitter2/Precision.cs | 62 +++ .../SoftBodies/BroadPhaseCollisionFilter.cs | 6 +- src/Jitter2/SoftBodies/SoftBody.cs | 2 +- src/Jitter2/SoftBodies/SoftBodyShape.cs | 2 +- src/Jitter2/SoftBodies/SoftBodyTetrahedron.cs | 16 +- src/Jitter2/SoftBodies/SoftBodyTriangle.cs | 26 +- src/Jitter2/SoftBodies/SpringConstraint.cs | 46 +- src/Jitter2/UnmanagedMemory/MemoryHelper.cs | 69 ++- .../UnmanagedMemory/UnmanagedActiveList.cs | 2 +- src/Jitter2/World.Detect.cs | 44 +- src/Jitter2/World.Step.cs | 36 +- src/Jitter2/World.cs | 16 +- src/JitterTests/AddRemoveTests.cs | 20 +- src/JitterTests/BoundingBoxTests.cs | 6 +- src/JitterTests/CollisionTests.cs | 148 +++---- src/JitterTests/Helper.cs | 18 +- src/JitterTests/InertiaTests.cs | 52 +-- src/JitterTests/JitterTests.csproj | 6 + src/JitterTests/MathTests.cs | 48 +-- src/JitterTests/StackingTests.cs | 26 +- 68 files changed, 1783 insertions(+), 1658 deletions(-) create mode 100644 src/Jitter2/Precision.cs diff --git a/.github/workflows/jitter-tests.yml b/.github/workflows/jitter-tests.yml index ab69f315..66399320 100644 --- a/.github/workflows/jitter-tests.yml +++ b/.github/workflows/jitter-tests.yml @@ -4,7 +4,6 @@ on: push: branches: [ main ] pull_request: - types: [opened, reopened, edited] permissions: id-token: write @@ -12,8 +11,12 @@ permissions: checks: write actions: write +env: + CONFIGURATION: Release + TEST_RESULTS_DIR: ./TestResults + jobs: - build: + build-and-test: runs-on: ubuntu-latest @@ -22,23 +25,28 @@ jobs: working-directory: ./src/JitterTests steps: - - uses: actions/checkout@v4 - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 9.0.x - - name: Restore dependencies - run: dotnet restore - - name: Build - run: dotnet build --no-restore - - name: Test - run: dotnet test -c Release --no-restore --test-adapter-path:. --logger "trx;LogFileName=test-results.trx" - #run: dotnet test -c Release --no-restore --test-adapter-path:. --logger:"junit;LogFilePath=test-result.xml;MethodFormat=Class;FailureBodyFormat=Verbose" - - - name: TestReport - uses: dorny/test-reporter@v1 - if: success() || failure() # run this step even if previous step failed - with: - name: JitterTests # Name of the check run which will be created - path: ./src/JitterTests/TestResults/test-results.trx # Path to test results - reporter: dotnet-trx # Format of test results + - uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0.x + + - name: Restore dependencies + run: dotnet restore + + - name: Build + run: dotnet build --configuration ${{ env.CONFIGURATION }} --no-restore + + - name: Run Tests + run: | + mkdir -p ${{ env.TEST_RESULTS_DIR }} + + # Run Single Precision Tests + dotnet test --configuration ${{ env.CONFIGURATION }} --no-restore \ + --test-adapter-path:. --logger "trx;LogFileName=single-precision.trx" + + # Run Double Precision Tests + dotnet test --configuration ${{ env.CONFIGURATION }} -p:DefineConstants="USE_DOUBLE_PRECISION" --no-restore \ + --test-adapter-path:. --logger "trx;LogFileName=double-precision.trx" + if: always() \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2089c377..0aed3bcc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -16,14 +16,13 @@ on: env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 DOTNET_NOLOGO: true - NuGetDirectory: ${{ github.workspace}}/nuget + NuGetDirectory: ${{ github.workspace }}/nuget defaults: run: shell: pwsh jobs: - create_nuget: runs-on: ubuntu-latest @@ -33,59 +32,63 @@ jobs: working-directory: ./src/Jitter2 steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Get all history to allow automatic versioning using MinVer + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Get all history to allow automatic versioning using MinVer - # Install the .NET SDK indicated in the global.json file - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 9.0.x + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0.x - - run: dotnet add package MinVer + - name: Add MinVer and Reproducible Builds + run: | + dotnet add package MinVer + dotnet add package DotNet.ReproducibleBuilds - - run: dotnet add package DotNet.ReproducibleBuilds + # Pack single-precision version + - name: Pack Single Precision + run: dotnet pack --configuration Release --output ${{ env.NuGetDirectory }} - # Create the NuGet package in the folder from the environment variable NuGetDirectory - - run: dotnet pack --configuration Release --output ${{ env.NuGetDirectory }} + # Pack double-precision version + - name: Pack Double Precision + run: dotnet pack --configuration Release -p:DoublePrecision=true --output ${{ env.NuGetDirectory }} - # Publish the NuGet package as an artifact, so they can be used in the following jobs - - uses: actions/upload-artifact@v4 - with: - name: nuget - if-no-files-found: error - retention-days: 7 - path: ${{ env.NuGetDirectory }}/* + # Upload artifacts + - uses: actions/upload-artifact@v4 + with: + name: nuget + if-no-files-found: error + retention-days: 7 + path: ${{ env.NuGetDirectory }}/* validate_nuget: - runs-on: ubuntu-latest - needs: [ create_nuget ] + runs-on: ubuntu-latest + needs: [create_nuget] steps: - # Install the .NET SDK indicated in the global.json file - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: 9.0.x - # Download the NuGet package created in the previous job - - uses: actions/download-artifact@v4 + - name: Download NuGet Packages + uses: actions/download-artifact@v4 with: name: nuget path: ${{ env.NuGetDirectory }} - - name: Install nuget validator + - name: Install NuGet Validator run: dotnet tool update Meziantou.Framework.NuGetPackageValidation.Tool --global - # Validate metadata and content of the NuGet package - # https://www.nuget.org/packages/Meziantou.Framework.NuGetPackageValidation.Tool#readme-body-tab - # If some rules are not applicable, you can disable them - # using the --excluded-rules or --excluded-rule-ids option - - name: Validate package - run: meziantou.validate-nuget-package (Get-ChildItem "${{ env.NuGetDirectory }}/*.nupkg") + - name: Validate NuGet Packages + run: | + foreach ($file in Get-ChildItem "${{ env.NuGetDirectory }}" -Recurse -Include *.nupkg) { + meziantou.validate-nuget-package $file + } run_test: + runs-on: ubuntu-latest defaults: @@ -93,43 +96,40 @@ jobs: working-directory: ./src/Jitter2 steps: - - uses: actions/checkout@v4 - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 9.0.x + - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0.x + + - name: Run Tests - Single Precision + run: dotnet test --configuration Release - - name: Run tests - run: dotnet test --configuration Release + - name: Run Tests - Double Precision + run: dotnet test --configuration Release -p:DoublePrecision=true deploy: - # Publish only when creating a GitHub Release - # https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository - # You can update this logic if you want to manage releases differently + if: github.event_name == 'release' runs-on: ubuntu-latest - needs: [ validate_nuget, run_test ] + needs: [validate_nuget, run_test] steps: - # Download the NuGet package created in the previous job - - uses: actions/download-artifact@v4 - with: - name: nuget - path: ${{ env.NuGetDirectory }} - - # Install the .NET SDK indicated in the global.json file - - name: Setup .NET Core + - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: 9.0.x - # Publish all NuGet packages to NuGet.org - # Use --skip-duplicate to prevent errors if a package with the same version already exists. - # If you retry a failed workflow, already published packages will be skipped without error. - - name: Publish NuGet package + - name: Download NuGet Packages + uses: actions/download-artifact@v4 + with: + name: nuget + path: ${{ env.NuGetDirectory }} + + - name: Publish NuGet Packages run: | dotnet nuget add source --username notgiven688 --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/notgiven688/index.json" - foreach($file in (Get-ChildItem "${{ env.NuGetDirectory }}" -Recurse -Include *.nupkg)) { + foreach ($file in Get-ChildItem "${{ env.NuGetDirectory }}" -Recurse -Include *.nupkg) { dotnet nuget push $file --api-key "${{ secrets.NUGET_APIKEY }}" --source https://api.nuget.org/v3/index.json --skip-duplicate dotnet nuget push $file --source "github" --skip-duplicate } diff --git a/src/.gitignore b/src/.gitignore index 558b013d..d3949636 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,4 +1,5 @@ .vscode +.vs imgui.ini [Bb]in/ [Oo]bj/ diff --git a/src/Jitter2/Collision/CollisionFilter/INarrowPhaseFilter.cs b/src/Jitter2/Collision/CollisionFilter/INarrowPhaseFilter.cs index 8a7102bb..2b5ea587 100644 --- a/src/Jitter2/Collision/CollisionFilter/INarrowPhaseFilter.cs +++ b/src/Jitter2/Collision/CollisionFilter/INarrowPhaseFilter.cs @@ -39,5 +39,5 @@ public interface INarrowPhaseFilter /// False if the collision should be filtered out, true otherwise. bool Filter(RigidBodyShape shapeA, RigidBodyShape shapeB, ref JVector pointA, ref JVector pointB, - ref JVector normal, ref float penetration); + ref JVector normal, ref Real penetration); } \ No newline at end of file diff --git a/src/Jitter2/Collision/CollisionFilter/TriangleEdgeCollisionFilter.cs b/src/Jitter2/Collision/CollisionFilter/TriangleEdgeCollisionFilter.cs index 931cb356..caa31db5 100644 --- a/src/Jitter2/Collision/CollisionFilter/TriangleEdgeCollisionFilter.cs +++ b/src/Jitter2/Collision/CollisionFilter/TriangleEdgeCollisionFilter.cs @@ -41,14 +41,14 @@ public class TriangleEdgeCollisionFilter : INarrowPhaseFilter /// A tweakable parameter. Collision points that are closer than this value to a triangle edge /// are considered as edge collisions and might be modified or discarded entirely. /// - public float EdgeThreshold { get; set; } = 0.05f; + public Real EdgeThreshold { get; set; } = (Real)0.05; - private float cosAT = 0.99f; + private Real cosAT = (Real)0.99; /// /// A tweakable parameter. /// - public float ProjectionThreshold { get; set; } = 0.5f; + public Real ProjectionThreshold { get; set; } = (Real)0.5; /// /// A tweakable parameter that defines the threshold to determine when two normals @@ -56,13 +56,13 @@ public class TriangleEdgeCollisionFilter : INarrowPhaseFilter /// public JAngle AngleThreshold { - get => JAngle.FromRadiant(MathF.Acos(cosAT)); - set => cosAT = MathF.Cos(value.Radiant); + get => JAngle.FromRadiant(MathR.Acos(cosAT)); + set => cosAT = MathR.Cos(value.Radiant); } /// public bool Filter(RigidBodyShape shapeA, RigidBodyShape shapeB, - ref JVector pointA, ref JVector pointB, ref JVector normal, ref float penetration) + ref JVector pointA, ref JVector pointB, ref JVector normal, ref Real penetration) { TriangleShape? ts1 = shapeA as TriangleShape; TriangleShape? ts2 = shapeB as TriangleShape; @@ -100,22 +100,22 @@ public bool Filter(RigidBodyShape shapeA, RigidBodyShape shapeB, tshape.GetWorldVertices(out JVector a, out JVector b, out JVector c); JVector n, pma; - float d0, d1, d2; + Real d0, d1, d2; // TODO: this can be optimized n = b - a; pma = collP - a; - d0 = (pma - JVector.Dot(pma, n) * n * (1.0f / n.LengthSquared())).LengthSquared(); + d0 = (pma - JVector.Dot(pma, n) * n * ((Real)1.0 / n.LengthSquared())).LengthSquared(); n = c - a; pma = collP - a; - d1 = (pma - JVector.Dot(pma, n) * n * (1.0f / n.LengthSquared())).LengthSquared(); + d1 = (pma - JVector.Dot(pma, n) * n * ((Real)1.0 / n.LengthSquared())).LengthSquared(); n = c - b; pma = collP - b; - d2 = (pma - JVector.Dot(pma, n) * n * (1.0f / n.LengthSquared())).LengthSquared(); + d2 = (pma - JVector.Dot(pma, n) * n * ((Real)1.0 / n.LengthSquared())).LengthSquared(); - if (MathF.Min(MathF.Min(d0, d1), d2) > EdgeThreshold) return true; + if (MathR.Min(MathR.Min(d0, d1), d2) > EdgeThreshold) return true; JVector nnormal; @@ -153,8 +153,8 @@ public bool Filter(RigidBodyShape shapeA, RigidBodyShape shapeB, { // tnormal and nnormal are the same // -------------------------------- - float f5 = JVector.Dot(normal, nnormal); - float f6 = JVector.Dot(normal, tnormal); + Real f5 = JVector.Dot(normal, nnormal); + Real f6 = JVector.Dot(normal, tnormal); if (f5 > f6) { @@ -211,16 +211,16 @@ public bool Filter(RigidBodyShape shapeA, RigidBodyShape shapeB, // \ // \ // \ tnormal - float f1 = proj % nnormal * cross; - float f2 = proj % tnormal * cross; + Real f1 = proj % nnormal * cross; + Real f2 = proj % tnormal * cross; - bool between = f1 * f2 <= 0.0f; + bool between = f1 * f2 <= (Real)0.0; if (!between) { // not in-between, snap normal - float f3 = JVector.Dot(normal, nnormal); - float f4 = JVector.Dot(normal, tnormal); + Real f3 = JVector.Dot(normal, nnormal); + Real f4 = JVector.Dot(normal, tnormal); if (f3 > f4) { diff --git a/src/Jitter2/Collision/CollisionHelper.cs b/src/Jitter2/Collision/CollisionHelper.cs index 8eacea83..a830a906 100644 --- a/src/Jitter2/Collision/CollisionHelper.cs +++ b/src/Jitter2/Collision/CollisionHelper.cs @@ -47,17 +47,17 @@ public static bool ProjectedPointOnTriangle(in JVector a, in JVector b, in JVect JVector v = a - c; JVector normal = u % v; - float t = normal.LengthSquared(); + Real t = normal.LengthSquared(); JVector at = a - point; JVector.Cross(u, at, out JVector tmp); - float gamma = JVector.Dot(tmp, normal) / t; + Real gamma = JVector.Dot(tmp, normal) / t; JVector.Cross(at, v, out tmp); - float beta = JVector.Dot(tmp, normal) / t; - float alpha = 1.0f - gamma - beta; + Real beta = JVector.Dot(tmp, normal) / t; + Real alpha = (Real)1.0 - gamma - beta; - return alpha > 0.0f && beta > 0.0f && gamma > 0.0f; + return alpha > (Real)0.0 && beta > (Real)0.0 && gamma > (Real)0.0; } /// @@ -73,20 +73,20 @@ public static bool ProjectedPointOnTriangle(in JVector a, in JVector b, in JVect /// Returns true if the ray intersects with the triangle, otherwise returns false. public static bool RayTriangle(in JVector a, in JVector b, in JVector c, in JVector rayStart, in JVector rayDir, - out float lambda, out JVector normal) + out Real lambda, out JVector normal) { JVector u = b - a; JVector v = c - a; normal = v % u; - float t = normal.LengthSquared(); + Real t = normal.LengthSquared(); // triangle is expected to span an area - Debug.Assert(t > 1e-06f); + Debug.Assert(t > (Real)1e-06); - float denom = JVector.Dot(rayDir, normal); + Real denom = JVector.Dot(rayDir, normal); - if (Math.Abs(denom) < 1e-06f) + if (Math.Abs(denom) < 1e-06) { // triangle and ray are parallel lambda = 0; @@ -95,7 +95,7 @@ public static bool RayTriangle(in JVector a, in JVector b, in JVector c, } lambda = JVector.Dot(a - rayStart, normal); - if (lambda > 0.0f) return false; + if (lambda > (Real)0.0) return false; lambda /= denom; // point where the ray intersects the plane of the triangle. @@ -103,10 +103,10 @@ public static bool RayTriangle(in JVector a, in JVector b, in JVector c, JVector at = a - hitPoint; JVector.Cross(u, at, out JVector tmp); - float gamma = JVector.Dot(tmp, normal) / t; + Real gamma = JVector.Dot(tmp, normal) / t; JVector.Cross(at, v, out tmp); - float beta = JVector.Dot(tmp, normal) / t; - float alpha = 1.0f - gamma - beta; + Real beta = JVector.Dot(tmp, normal) / t; + Real alpha = (Real)1.0 - gamma - beta; return alpha > 0 && beta > 0 && gamma > 0; } diff --git a/src/Jitter2/Collision/DynamicTree.RayCast.cs b/src/Jitter2/Collision/DynamicTree.RayCast.cs index 42629cbe..40aad593 100644 --- a/src/Jitter2/Collision/DynamicTree.RayCast.cs +++ b/src/Jitter2/Collision/DynamicTree.RayCast.cs @@ -35,7 +35,7 @@ public partial class DynamicTree public struct RayCastResult { public IDynamicTreeProxy Entity; - public float Lambda; + public Real Lambda; public JVector Normal; } @@ -59,7 +59,7 @@ private struct Ray public RayCastFilterPost? FilterPost; public RayCastFilterPre? FilterPre; - public float Lambda; + public Real Lambda; public Ray(in JVector origin, in JVector direction) { @@ -67,7 +67,7 @@ public Ray(in JVector origin, in JVector direction) Direction = direction; FilterPost = null; FilterPre = null; - Lambda = float.MaxValue; + Lambda = Real.MaxValue; } } @@ -83,7 +83,7 @@ public Ray(in JVector origin, in JVector direction) /// Distance from the origin to the ray hit point in units of the ray's direction. /// True if the ray hits, false otherwise. public bool RayCast(JVector origin, JVector direction, RayCastFilterPre? pre, RayCastFilterPost? post, - out IDynamicTreeProxy? proxy, out JVector normal, out float lambda) + out IDynamicTreeProxy? proxy, out JVector normal, out Real lambda) { Ray ray = new(origin, direction) { @@ -97,10 +97,10 @@ public bool RayCast(JVector origin, JVector direction, RayCastFilterPre? pre, Ra return hit; } - /// + /// /// Maximum lambda of the ray's length to consider for intersections. - public bool RayCast(JVector origin, JVector direction, float maxLambda, RayCastFilterPre? pre, RayCastFilterPost? post, - out IDynamicTreeProxy? proxy, out JVector normal, out float lambda) + public bool RayCast(JVector origin, JVector direction, Real maxLambda, RayCastFilterPre? pre, RayCastFilterPost? post, + out IDynamicTreeProxy? proxy, out JVector normal, out Real lambda) { Ray ray = new(origin, direction) { @@ -161,8 +161,8 @@ private bool QueryRay(in Ray ray, out RayCastResult result) ref Node lNode = ref Nodes[node.Left]; ref Node rNode = ref Nodes[node.Right]; - bool lRes = lNode.ExpandedBox.RayIntersect(ray.Origin, ray.Direction, out float lEnter); - bool rRes = rNode.ExpandedBox.RayIntersect(ray.Origin, ray.Direction, out float rEnter); + bool lRes = lNode.ExpandedBox.RayIntersect(ray.Origin, ray.Direction, out Real lEnter); + bool rRes = rNode.ExpandedBox.RayIntersect(ray.Origin, ray.Direction, out Real rEnter); if (lEnter > result.Lambda) lRes = false; if (rEnter > result.Lambda) rRes = false; diff --git a/src/Jitter2/Collision/DynamicTree.cs b/src/Jitter2/Collision/DynamicTree.cs index bd85f6d5..17d8b63f 100644 --- a/src/Jitter2/Collision/DynamicTree.cs +++ b/src/Jitter2/Collision/DynamicTree.cs @@ -38,7 +38,7 @@ public interface IUpdatableBoundingBox /// /// Updates the bounding box. /// - public void UpdateWorldBoundingBox(float dt); + public void UpdateWorldBoundingBox(Real dt); } /// @@ -65,7 +65,7 @@ public interface IRayCastable /// /// true if the ray intersects with the object; otherwise, false. /// - public bool RayCast(in JVector origin, in JVector direction, out JVector normal, out float lambda); + public bool RayCast(in JVector origin, in JVector direction, out JVector normal, out Real lambda); } /// @@ -92,13 +92,13 @@ public partial class DynamicTree /// Specifies the factor by which the bounding box in the dynamic tree structure is expanded. The expansion is calculated as /// * ExpandFactor * alpha, where alpha is a pseudo-random number in the range [1,2]. /// - public const float ExpandFactor = 0.1f; + public const Real ExpandFactor = (Real)0.1; /// /// Specifies a small additional expansion of the bounding box in the AABB tree structure to prevent /// the creation of bounding boxes with zero volume. /// - public const float ExpandEps = 0.01f; + public const Real ExpandEps = (Real)0.01; /// /// Represents a node in the AABB tree. @@ -181,7 +181,7 @@ public enum Timings /// Updates all entities that are marked as active in the active list. /// /// A boolean indicating whether to perform a multi-threaded update. - public void Update(bool multiThread, float dt) + public void Update(bool multiThread, Real dt) { long time = Stopwatch.GetTimestamp(); double invFrequency = 1.0d / Stopwatch.Frequency; @@ -259,7 +259,7 @@ void SetTime(Timings type) } } - private float step_dt; + private Real step_dt; private void UpdateBoundingBoxesCallback(Parallel.Batch batch) { @@ -473,15 +473,15 @@ public void Query(T hits, in JBBox box) where T : ICollection /// The number of times to iterate over all proxies in the tree. Must be greater than zero. /// The chance of a proxy to be removed and re-added to the tree for each sweep. Must be between 0 and 1. - public void Optimize(int sweeps = 100, float chance = 0.01f) + public void Optimize(int sweeps = 100, Real chance = (Real)0.01) { optimizeRandom ??= new Random(0); Optimize(optimizeRandom, sweeps, chance); } - /// + /// /// Provide an instance of a random class. - public void Optimize(Random random, int sweeps, float chance) + public void Optimize(Random random, int sweeps, Real chance) { if (sweeps <= 0) throw new ArgumentOutOfRangeException(nameof(sweeps), "Sweeps must be greater than zero."); if (chance < 0 || chance > 1) throw new ArgumentOutOfRangeException(nameof(chance), "Chance must be between 0 and 1."); @@ -623,13 +623,13 @@ private void ScanForOverlaps(int fraction, bool add) private static void ExpandBoundingBox(ref JBBox box, in JVector direction) { - if (direction.X < 0.0f) box.Min.X += direction.X; + if (direction.X < (Real)0.0) box.Min.X += direction.X; else box.Max.X += direction.X; - if (direction.Y < 0.0f) box.Min.Y += direction.Y; + if (direction.Y < (Real)0.0) box.Min.Y += direction.Y; else box.Max.Y += direction.Y; - if (direction.Z < 0.0f) box.Min.Z += direction.Z; + if (direction.Z < (Real)0.0) box.Min.Z += direction.Z; else box.Max.Z += direction.Z; box.Min.X -= ExpandEps; @@ -641,7 +641,7 @@ private static void ExpandBoundingBox(ref JBBox box, in JVector direction) box.Max.Z += ExpandEps; } - private static float GenerateRandom(ulong seed) + private static Real GenerateRandom(ulong seed) { const uint a = 21_687_443; const uint b = 35_253_893; @@ -651,7 +651,7 @@ private static float GenerateRandom(ulong seed) seed ^= seed << 5; uint randomBits = (uint)seed * a + b; - return MathF.Abs((float)randomBits / uint.MaxValue); + return MathR.Abs((Real)randomBits / uint.MaxValue); } private void InternalAddProxy(IDynamicTreeProxy proxy) @@ -659,9 +659,9 @@ private void InternalAddProxy(IDynamicTreeProxy proxy) JBBox box = proxy.WorldBoundingBox; int index = AllocateNode(); - float pseudoRandomExt = GenerateRandom((ulong)index); + Real pseudoRandomExt = GenerateRandom((ulong)index); - ExpandBoundingBox(ref box, proxy.Velocity * ExpandFactor * (1.0f + pseudoRandomExt)); + ExpandBoundingBox(ref box, proxy.Velocity * ExpandFactor * ((Real)1.0 + pseudoRandomExt)); Nodes[index].Proxy = proxy; Nodes[index].Height = 1; diff --git a/src/Jitter2/Collision/NarrowPhase/ConvexPolytope.cs b/src/Jitter2/Collision/NarrowPhase/ConvexPolytope.cs index 0789c37d..1e8de1b5 100644 --- a/src/Jitter2/Collision/NarrowPhase/ConvexPolytope.cs +++ b/src/Jitter2/Collision/NarrowPhase/ConvexPolytope.cs @@ -49,8 +49,8 @@ public struct Triangle public JVector Normal; public JVector ClosestToOrigin; - public float NormalSq; - public float ClosestToOriginSq; + public Real NormalSq; + public Real ClosestToOriginSq; } private struct Edge @@ -70,7 +70,7 @@ public static bool Equals(in Edge a, in Edge b) } } - private const float NumericEpsilon = 1e-16f; + private const Real NumericEpsilon = (Real)1e-16; // (*) Euler-characteristic: V (vertices) - E (edges) + F (faces) = 2 // We have triangles T instead of faces: F = T @@ -127,60 +127,60 @@ private bool CalcBarycentric(in Triangle tri, out JVector result) JVector ab = b - a; JVector ac = c - a; - float d1 = JVector.Dot(ab, a); - float d2 = JVector.Dot(ac, a); + Real d1 = JVector.Dot(ab, a); + Real d2 = JVector.Dot(ac, a); - if (d1 > 0.0f && d2 > 0.0f) + if (d1 > (Real)0.0 && d2 > (Real)0.0) { - result = new JVector(1, 0, 0); + result = new JVector((Real)1.0, (Real)0.0, (Real)0.0); return true; } - float d3 = JVector.Dot(ab, b); - float d4 = JVector.Dot(ac, b); - if (d3 < 0.0f && d4 > d3) + Real d3 = JVector.Dot(ab, b); + Real d4 = JVector.Dot(ac, b); + if (d3 < (Real)0.0 && d4 > d3) { result = new JVector(0, 1, 0); return true; } - float vc = d1 * d4 - d3 * d2; - if (vc <= 0.0f && d1 < 0.0f && d3 > 0.0f) + Real vc = d1 * d4 - d3 * d2; + if (vc <= (Real)0.0 && d1 < (Real)0.0 && d3 > (Real)0.0) { - float v = d1 / (d1 - d3); - result = new JVector(1.0f - v, v, 0); + Real v = d1 / (d1 - d3); + result = new JVector((Real)1.0 - v, v, 0); return true; } - float d5 = JVector.Dot(ab, c); - float d6 = JVector.Dot(ac, c); - if (d6 < 0.0f && d5 > d6) + Real d5 = JVector.Dot(ab, c); + Real d6 = JVector.Dot(ac, c); + if (d6 < (Real)0.0 && d5 > d6) { result = new JVector(0, 0, 1); return true; } - float vb = d5 * d2 - d1 * d6; - if (vb <= 0.0f && d2 < 0.0f && d6 > 0.0f) + Real vb = d5 * d2 - d1 * d6; + if (vb <= (Real)0.0 && d2 < (Real)0.0 && d6 > (Real)0.0) { - float w = d2 / (d2 - d6); - result = new JVector(1.0f - w, 0, w); + Real w = d2 / (d2 - d6); + result = new JVector((Real)1.0 - w, 0, w); return true; } - float va = d3 * d6 - d5 * d4; - if (va <= 0.0f && (d4 - d3) < 0.0f && (d5 - d6) < 0.0f) + Real va = d3 * d6 - d5 * d4; + if (va <= (Real)0.0 && (d4 - d3) < (Real)0.0 && (d5 - d6) < (Real)0.0) { - float w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); - result = new JVector(0, 1.0f - w, w); + Real w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); + result = new JVector(0, (Real)1.0 - w, w); return true; } - float d = 1.0f / (va + vb + vc); - float vf = vb * d; - float wf = vc * d; + Real d = (Real)1.0 / (va + vb + vc); + Real vf = vb * d; + Real wf = vc * d; - result = new JVector(1.0f - vf - wf, vf, wf); + result = new JVector((Real)1.0 - vf - wf, vf, wf); return false; } @@ -213,7 +213,7 @@ private bool CreateTriangle(short a, short b, short c) } // do we need to flip the triangle? (the origin of the md has to be enclosed) - float delta = JVector.Dot(triangle.Normal, vertices[a].V - center); + Real delta = JVector.Dot(triangle.Normal, vertices[a].V - center); if (delta < 0) { @@ -222,7 +222,7 @@ private bool CreateTriangle(short a, short b, short c) } delta = JVector.Dot(triangle.Normal, vertices[a].V); - triangle.FacingOrigin = delta >= 0.0f; + triangle.FacingOrigin = delta >= (Real)0.0; if (CalcBarycentric(triangle, out JVector bc)) { @@ -248,7 +248,7 @@ private bool CreateTriangle(short a, short b, short c) public ref Triangle GetClosestTriangle() { int closestIndex = -1; - float currentMin = float.MaxValue; + Real currentMin = Real.MaxValue; // We can skip the test for enclosed origin if the origin was // already enclosed once. @@ -279,7 +279,7 @@ public void InitTetrahedron() vPointer = 4; tPointer = 0; - center = 0.25f * (vertices[0].V + vertices[1].V + vertices[2].V + vertices[3].V); + center = (Real)0.25 * (vertices[0].V + vertices[1].V + vertices[2].V + vertices[3].V); CreateTriangle(0, 2, 1); CreateTriangle(0, 1, 3); @@ -297,11 +297,11 @@ public void InitTetrahedron(in JVector point) tPointer = 0; center = point; - const float scale = 1e-2f; // minkowski sums not allowed to be thinner - vertices[0] = new Vertex(center + scale * new JVector(MathF.Sqrt(8.0f / 9.0f), 0.0f, -1.0f / 3.0f)); - vertices[1] = new Vertex(center + scale * new JVector(-MathF.Sqrt(2.0f / 9.0f), MathF.Sqrt(2.0f / 3.0f), -1.0f / 3.0f)); - vertices[2] = new Vertex(center + scale * new JVector(-MathF.Sqrt(2.0f / 9.0f), -MathF.Sqrt(2.0f / 3.0f), -1.0f / 3.0f)); - vertices[3] = new Vertex(center + scale * new JVector(0.0f, 0.0f, 1.0f)); + const Real scale = (Real)1e-2; // minkowski sums not allowed to be thinner + vertices[0] = new Vertex(center + scale * new JVector(MathR.Sqrt((Real)(8.0 / 9.0)), (Real)0.0, -(Real)(1.0 / 3.0))); + vertices[1] = new Vertex(center + scale * new JVector(-MathR.Sqrt((Real)(2.0 / 9.0)), MathR.Sqrt((Real)(2.0 / 3.0)), -(Real)(1.0 / 3.0))); + vertices[2] = new Vertex(center + scale * new JVector(-MathR.Sqrt((Real)(2.0 / 9.0)), -MathR.Sqrt((Real)(2.0 / 3.0)), -(Real)(1.0 / 3.0))); + vertices[3] = new Vertex(center + scale * new JVector((Real)0.0, (Real)0.0, (Real)1.0)); CreateTriangle(2, 0, 1); CreateTriangle(1, 0, 3); diff --git a/src/Jitter2/Collision/NarrowPhase/NarrowPhase.cs b/src/Jitter2/Collision/NarrowPhase/NarrowPhase.cs index 142a5f5c..dd42a584 100644 --- a/src/Jitter2/Collision/NarrowPhase/NarrowPhase.cs +++ b/src/Jitter2/Collision/NarrowPhase/NarrowPhase.cs @@ -35,7 +35,7 @@ namespace Jitter2.Collision; /// public static class NarrowPhase { - private const float NumericEpsilon = 1e-16f; + private const Real NumericEpsilon = (Real)1e-16; private struct Solver { @@ -43,7 +43,7 @@ private struct Solver public bool PointTest(in ISupportMappable supportA, in JVector origin) { - const float CollideEpsilon = 1e-4f; + const Real CollideEpsilon = (Real)1e-4; const int MaxIter = 34; JVector x = origin; @@ -56,16 +56,16 @@ public bool PointTest(in ISupportMappable supportA, in JVector origin) int maxIter = MaxIter; - float distSq = v.LengthSquared(); + Real distSq = v.LengthSquared(); while (distSq > CollideEpsilon * CollideEpsilon && maxIter-- != 0) { supportA.SupportMap(v, out JVector p); JVector.Subtract(x, p, out JVector w); - float vw = JVector.Dot(v, w); + Real vw = JVector.Dot(v, w); - if (vw >= 0.0f) + if (vw >= (Real)0.0) { return false; } @@ -83,13 +83,13 @@ public bool PointTest(in ISupportMappable supportA, in JVector origin) return true; } - public bool RayCast(in ISupportMappable supportA, in JVector origin, in JVector direction, out float lambda, out JVector normal) + public bool RayCast(in ISupportMappable supportA, in JVector origin, in JVector direction, out Real lambda, out JVector normal) { - const float CollideEpsilon = 1e-4f; + const Real CollideEpsilon = (Real)1e-4; const int MaxIter = 34; normal = JVector.Zero; - lambda = 0.0f; + lambda = (Real)0.0; JVector r = direction; JVector x = origin; @@ -102,7 +102,7 @@ public bool RayCast(in ISupportMappable supportA, in JVector origin, in JVector int maxIter = MaxIter; - float distSq = v.LengthSquared(); + Real distSq = v.LengthSquared(); while (distSq > CollideEpsilon * CollideEpsilon && maxIter-- != 0) { @@ -110,15 +110,15 @@ public bool RayCast(in ISupportMappable supportA, in JVector origin, in JVector JVector.Subtract(x, p, out JVector w); - float VdotW = JVector.Dot(v, w); + Real VdotW = JVector.Dot(v, w); - if (VdotW > 0.0f) + if (VdotW > (Real)0.0) { - float VdotR = JVector.Dot(v, r); + Real VdotR = JVector.Dot(v, r); if (VdotR >= -NumericEpsilon) { - lambda = float.PositiveInfinity; + lambda = Real.PositiveInfinity; return false; } @@ -140,20 +140,20 @@ public bool RayCast(in ISupportMappable supportA, in JVector origin, in JVector converged: - float nlen2 = normal.LengthSquared(); + Real nlen2 = normal.LengthSquared(); if (nlen2 > NumericEpsilon) { - normal *= 1.0f / MathF.Sqrt(nlen2); + normal *= (Real)1.0 / MathR.Sqrt(nlen2); } return true; } public bool Sweep(ref MinkowskiDifference mkd, in JVector sweep, - out JVector p1, out JVector p2, out JVector normal, out float lambda) + out JVector p1, out JVector p2, out JVector normal, out Real lambda) { - const float CollideEpsilon = 1e-4f; + const Real CollideEpsilon = (Real)1e-4; const int MaxIter = 34; Unsafe.SkipInit(out SimplexSolverAB simplexSolver); @@ -163,7 +163,7 @@ public bool Sweep(ref MinkowskiDifference mkd, in JVector sweep, JVector posB = mkd.PositionB; - lambda = 0.0f; + lambda = (Real)0.0; p1 = p2 = JVector.Zero; @@ -174,22 +174,22 @@ public bool Sweep(ref MinkowskiDifference mkd, in JVector sweep, int iter = MaxIter; - float distSq = float.MaxValue; + Real distSq = Real.MaxValue; while ((distSq > CollideEpsilon * CollideEpsilon) && (iter-- != 0)) { mkd.Support(v, out Vertex vertex); var w = vertex.V; - float VdotW = -JVector.Dot(v, w); + Real VdotW = -JVector.Dot(v, w); - if (VdotW > 0.0f) + if (VdotW > (Real)0.0) { - float VdotR = JVector.Dot(v, r); + Real VdotR = JVector.Dot(v, r); - if (VdotR >= -1e-12f) + if (VdotR >= -(Real)1e-12) { - lambda = float.PositiveInfinity; + lambda = Real.PositiveInfinity; return false; } @@ -213,19 +213,19 @@ public bool Sweep(ref MinkowskiDifference mkd, in JVector sweep, simplexSolver.GetClosest(out p1, out p2); - float nlen2 = normal.LengthSquared(); + Real nlen2 = normal.LengthSquared(); if (nlen2 > NumericEpsilon) { - normal *= 1.0f / MathF.Sqrt(nlen2); + normal *= (Real)1.0 / MathR.Sqrt(nlen2); } return true; } - private bool SolveMPREPA(in MinkowskiDifference mkd, ref JVector point1, ref JVector point2, ref JVector normal, ref float penetration) + private bool SolveMPREPA(in MinkowskiDifference mkd, ref JVector point1, ref JVector point2, ref JVector normal, ref Real penetration) { - const float CollideEpsilon = 1e-4f; + const Real CollideEpsilon = (Real)1e-4; const int MaxIter = 85; convexPolytope.InitTetrahedron(); @@ -239,7 +239,7 @@ private bool SolveMPREPA(in MinkowskiDifference mkd, ref JVector point1, ref JVe ctri = convexPolytope.GetClosestTriangle(); JVector searchDir = ctri.ClosestToOrigin; - float searchDirSq = ctri.ClosestToOriginSq; + Real searchDirSq = ctri.ClosestToOriginSq; if (ctri.ClosestToOriginSq < NumericEpsilon) { @@ -250,7 +250,7 @@ private bool SolveMPREPA(in MinkowskiDifference mkd, ref JVector point1, ref JVe mkd.Support(searchDir, out Vertex vertex); // compare with the corresponding code in SolveGJKEPA. - float deltaDist = JVector.Dot(ctri.ClosestToOrigin - vertex.V, searchDir); + Real deltaDist = JVector.Dot(ctri.ClosestToOrigin - vertex.V, searchDir); if (deltaDist * deltaDist <= CollideEpsilon * CollideEpsilon * searchDirSq) { @@ -271,14 +271,14 @@ private bool SolveMPREPA(in MinkowskiDifference mkd, ref JVector point1, ref JVe convexPolytope.CalculatePoints(ctri, out point1, out point2); - normal = ctri.Normal * (1.0f / MathF.Sqrt(ctri.NormalSq)); - penetration = MathF.Sqrt(ctri.ClosestToOriginSq); + normal = ctri.Normal * ((Real)1.0 / MathR.Sqrt(ctri.NormalSq)); + penetration = MathR.Sqrt(ctri.ClosestToOriginSq); return true; } public bool SolveMPR(in MinkowskiDifference mkd, - out JVector pointA, out JVector pointB, out JVector normal, out float penetration) + out JVector pointA, out JVector pointB, out JVector normal, out Real penetration) { /* XenoCollide is available under the zlib license: @@ -301,12 +301,12 @@ would be appreciated but is not required. not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ - const float CollideEpsilon = 1e-4f; + const Real CollideEpsilon = (Real)1e-4; const int MaxIter = 34; // If MPR reports a penetration deeper than this value we do not trust // MPR to have found the global minimum and perform an EPA run. - const float EPAPenetrationThreshold = 0.02f; + const Real EPAPenetrationThreshold = (Real)0.02; Unsafe.SkipInit(out Vertex v0); Unsafe.SkipInit(out Vertex v1); @@ -318,7 +318,7 @@ 3. This notice may not be removed or altered from any source distribution. Unsafe.SkipInit(out JVector temp2); Unsafe.SkipInit(out JVector temp3); - penetration = 0.0f; + penetration = (Real)0.0; mkd.GetCenter(out v0); @@ -327,7 +327,7 @@ 3. This notice may not be removed or altered from any source distribution. Math.Abs(v0.V.Z) < NumericEpsilon) { // any direction is fine - v0.V.X = 1e-05f; + v0.V.X = (Real)1e-05; } JVector.Negate(v0.V, out normal); @@ -337,7 +337,7 @@ 3. This notice may not be removed or altered from any source distribution. pointA = v1.A; pointB = v1.B; - if (JVector.Dot(v1.V, normal) <= 0.0f) return false; + if (JVector.Dot(v1.V, normal) <= (Real)0.0) return false; JVector.Cross(v1.V, v0.V, out normal); if (normal.LengthSquared() < NumericEpsilon) @@ -354,17 +354,17 @@ 3. This notice may not be removed or altered from any source distribution. mkd.Support(normal, out v2); - if (JVector.Dot(v2.V, normal) <= 0.0f) return false; + if (JVector.Dot(v2.V, normal) <= (Real)0.0) return false; // Determine whether origin is on + or - side of plane (v1.V,v0.V,v2.V) JVector.Subtract(v1.V, v0.V, out temp1); JVector.Subtract(v2.V, v0.V, out temp2); JVector.Cross(temp1, temp2, out normal); - float dist = JVector.Dot(normal, v0.V); + Real dist = JVector.Dot(normal, v0.V); // If the origin is on the - side of the plane, reverse the direction of the plane - if (dist > 0.0f) + if (dist > (Real)0.0) { JVector.Swap(ref v1.V, ref v2.V); JVector.Swap(ref v1.A, ref v2.A); @@ -385,14 +385,14 @@ 3. This notice may not be removed or altered from any source distribution. mkd.Support(normal, out v3); - if (JVector.Dot(v3.V, normal) <= 0.0f) + if (JVector.Dot(v3.V, normal) <= (Real)0.0) { return false; } // If origin is outside (v1.V,v0.V,v3.V), then eliminate v2.V and loop JVector.Cross(v1.V, v3.V, out temp1); - if (JVector.Dot(temp1, v0.V) < 0.0f) + if (JVector.Dot(temp1, v0.V) < (Real)0.0) { v2 = v3; JVector.Subtract(v1.V, v0.V, out temp1); @@ -403,7 +403,7 @@ 3. This notice may not be removed or altered from any source distribution. // If origin is outside (v3.V,v0.V,v2.V), then eliminate v1.V and loop JVector.Cross(v3.V, v2.V, out temp1); - if (JVector.Dot(temp1, v0.V) < 0.0f) + if (JVector.Dot(temp1, v0.V) < (Real)0.0) { v1 = v3; JVector.Subtract(v3.V, v0.V, out temp1); @@ -427,7 +427,7 @@ 3. This notice may not be removed or altered from any source distribution. JVector.Cross(temp1, temp2, out normal); // normal.Normalize(); - float normalSq = normal.LengthSquared(); + Real normalSq = normal.LengthSquared(); // Can this happen??? Can it be handled more cleanly? if (normalSq < NumericEpsilon) @@ -441,7 +441,7 @@ 3. This notice may not be removed or altered from any source distribution. if (!hit) { // Compute distance from origin to wedge face - float d = JVector.Dot(normal, v1.V); + Real d = JVector.Dot(normal, v1.V); // If the origin is inside the wedge, we have a hit hit = d >= 0; } @@ -449,17 +449,17 @@ 3. This notice may not be removed or altered from any source distribution. mkd.Support(normal, out v4); JVector.Subtract(v4.V, v3.V, out temp3); - float delta = JVector.Dot(temp3, normal); + Real delta = JVector.Dot(temp3, normal); penetration = JVector.Dot(v4.V, normal); // If the boundary is thin enough or the origin is outside the support plane for the newly discovered // vertex, then we can terminate - if (delta * delta <= CollideEpsilon * CollideEpsilon * normalSq || penetration <= 0.0f || + if (delta * delta <= CollideEpsilon * CollideEpsilon * normalSq || penetration <= (Real)0.0 || phase2 > MaxIter) { if (hit) { - float invnormal = 1.0f / (float)Math.Sqrt(normalSq); + Real invnormal = (Real)1.0 / MathR.Sqrt(normalSq); penetration *= invnormal; @@ -479,10 +479,10 @@ 3. This notice may not be removed or altered from any source distribution. // Compute the barycentric coordinates of the origin JVector.Cross(v1.V, temp1, out temp3); - float gamma = JVector.Dot(temp3, normal) * invnormal; + Real gamma = JVector.Dot(temp3, normal) * invnormal; JVector.Cross(temp2, v1.V, out temp3); - float beta = JVector.Dot(temp3, normal) * invnormal; - float alpha = 1.0f - gamma - beta; + Real beta = JVector.Dot(temp3, normal) * invnormal; + Real alpha = (Real)1.0 - gamma - beta; pointA = alpha * v1.A + beta * v2.A + gamma * v3.A; pointB = alpha * v1.B + beta * v2.B + gamma * v3.B; @@ -493,13 +493,13 @@ 3. This notice may not be removed or altered from any source distribution. // Compute the tetrahedron dividing face (v4.V,v0.V,v3.V) JVector.Cross(v4.V, v0.V, out temp1); - float dot = JVector.Dot(temp1, v1.V); + Real dot = JVector.Dot(temp1, v1.V); - if (dot >= 0.0f) + if (dot >= (Real)0.0) { dot = JVector.Dot(temp1, v2.V); - if (dot >= 0.0f) + if (dot >= (Real)0.0) { v1 = v4; // Inside d1 & inside d2 -> eliminate v1.V } @@ -512,7 +512,7 @@ 3. This notice may not be removed or altered from any source distribution. { dot = JVector.Dot(temp1, v3.V); - if (dot >= 0.0f) + if (dot >= (Real)0.0) { v2 = v4; // Outside d1 & inside d3 -> eliminate v2.V } @@ -525,9 +525,9 @@ 3. This notice may not be removed or altered from any source distribution. } public bool Distance(in MinkowskiDifference mkd, - out JVector point1, out JVector point2, out float distance) + out JVector point1, out JVector point2, out Real distance) { - const float CollideEpsilon = 1e-4f; + const Real CollideEpsilon = (Real)1e-4; const int MaxIter = 34; Unsafe.SkipInit(out SimplexSolverAB simplexSolver); @@ -537,7 +537,7 @@ public bool Distance(in MinkowskiDifference mkd, mkd.GetCenter(out var center); JVector v = center.V; - float distSq = v.LengthSquared(); + Real distSq = v.LengthSquared(); while (maxIter-- != 0) { @@ -545,7 +545,7 @@ public bool Distance(in MinkowskiDifference mkd, distSq = v.LengthSquared(); - float deltaDist = JVector.Dot(v - w.V, v); + Real deltaDist = JVector.Dot(v - w.V, v); if (deltaDist * deltaDist < CollideEpsilon * CollideEpsilon * distSq) { break; @@ -554,13 +554,13 @@ public bool Distance(in MinkowskiDifference mkd, if (distSq < CollideEpsilon * CollideEpsilon || !simplexSolver.AddVertex(w, out v)) { - distance = 0.0f; + distance = (Real)0.0; point1 = point2 = JVector.Zero; return false; } } - distance = MathF.Sqrt(distSq); + distance = MathR.Sqrt(distSq); simplexSolver.GetClosest(out point1, out point2); return true; @@ -568,7 +568,7 @@ public bool Distance(in MinkowskiDifference mkd, public bool Overlap(in MinkowskiDifference mkd) { - const float CollideEpsilon = 1e-4f; + const Real CollideEpsilon = (Real)1e-4; const int MaxIter = 34; Unsafe.SkipInit(out SimplexSolverAB simplexSolver); @@ -578,13 +578,13 @@ public bool Overlap(in MinkowskiDifference mkd) mkd.GetCenter(out var center); JVector v = center.V; - float distSq = v.LengthSquared(); + Real distSq = v.LengthSquared(); while (distSq > CollideEpsilon * CollideEpsilon && maxIter-- != 0) { mkd.Support(-v, out var w); - float vw = JVector.Dot(v, w.V); - if (vw >= 0.0f) + Real vw = JVector.Dot(v, w.V); + if (vw >= (Real)0.0) return false; if (!simplexSolver.AddVertex(w, out v)) return true; distSq = v.LengthSquared(); @@ -594,9 +594,9 @@ public bool Overlap(in MinkowskiDifference mkd) } public bool Collision(in MinkowskiDifference mkd, - out JVector point1, out JVector point2, out JVector normal, out float penetration) + out JVector point1, out JVector point2, out JVector normal, out Real penetration) { - const float CollideEpsilon = 1e-4f; + const Real CollideEpsilon = (Real)1e-4; const int MaxIter = 85; mkd.GetCenter(out Vertex centerVertex); @@ -614,7 +614,7 @@ public bool Collision(in MinkowskiDifference mkd, ctri = convexPolytope.GetClosestTriangle(); JVector searchDir = ctri.ClosestToOrigin; - float searchDirSq = ctri.ClosestToOriginSq; + Real searchDirSq = ctri.ClosestToOriginSq; if (!convexPolytope.OriginEnclosed) searchDir.Negate(); @@ -633,7 +633,7 @@ public bool Collision(in MinkowskiDifference mkd, // s = searchDir // // abs(dot(c - v, s)) / len(s) < e <=> [dot(c - v, s)]^2 = e*e*s^2 - float deltaDist = JVector.Dot(ctri.ClosestToOrigin - vertex.V, searchDir); + Real deltaDist = JVector.Dot(ctri.ClosestToOrigin - vertex.V, searchDir); if (deltaDist * deltaDist <= CollideEpsilon * CollideEpsilon * searchDirSq) { @@ -647,7 +647,7 @@ public bool Collision(in MinkowskiDifference mkd, } point1 = point2 = normal = JVector.Zero; - penetration = 0.0f; + penetration = (Real)0.0; Trace.WriteLine($"EPA: Could not converge within {MaxIter} iterations."); @@ -657,11 +657,11 @@ public bool Collision(in MinkowskiDifference mkd, convexPolytope.CalculatePoints(ctri, out point1, out point2); - penetration = MathF.Sqrt(ctri.ClosestToOriginSq); - if (!convexPolytope.OriginEnclosed) penetration *= -1.0f; + penetration = MathR.Sqrt(ctri.ClosestToOriginSq); + if (!convexPolytope.OriginEnclosed) penetration *= -(Real)1.0; - if (MathF.Abs(penetration) > NumericEpsilon) normal = ctri.ClosestToOrigin * (1.0f / penetration); - else normal = ctri.Normal * (1.0f / MathF.Sqrt(ctri.NormalSq)); + if (MathR.Abs(penetration) > NumericEpsilon) normal = ctri.ClosestToOrigin * ((Real)1.0 / penetration); + else normal = ctri.Normal * ((Real)1.0 / MathR.Sqrt(ctri.NormalSq)); return true; } @@ -714,7 +714,7 @@ public static bool PointTest(in ISupportMappable support, in JMatrix orientation /// Returns true if the ray intersects with the shape; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool RayCast(in ISupportMappable support, in JQuaternion orientation, - in JVector position, in JVector origin, in JVector direction, out float lambda, out JVector normal) + in JVector position, in JVector origin, in JVector direction, out Real lambda, out JVector normal) { // rotate the ray into the reference frame of bodyA.. JVector tdirection = JVector.TransposedTransform(direction, orientation); @@ -741,7 +741,7 @@ public static bool RayCast(in ISupportMappable support, in JQuaternion orientati /// /// Returns true if the ray intersects with the shape; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool RayCast(in ISupportMappable support, in JVector origin, in JVector direction, out float lambda, out JVector normal) + public static bool RayCast(in ISupportMappable support, in JVector origin, in JVector direction, out Real lambda, out JVector normal) { return solver.RayCast(support, origin, direction, out lambda, out normal); } @@ -777,7 +777,7 @@ public static bool RayCast(in ISupportMappable support, in JVector origin, in JV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Collision(in ISupportMappable supportA, in ISupportMappable supportB, in JQuaternion orientationB, in JVector positionB, - out JVector pointA, out JVector pointB, out JVector normal, out float penetration) + out JVector pointA, out JVector pointB, out JVector normal, out Real penetration) { Unsafe.SkipInit(out MinkowskiDifference mkd); mkd.SupportA = supportA; @@ -824,7 +824,7 @@ public static bool Collision(in ISupportMappable supportA, in ISupportMappable s public static bool Collision(in ISupportMappable supportA, in ISupportMappable supportB, in JQuaternion orientationA, in JQuaternion orientationB, in JVector positionA, in JVector positionB, - out JVector pointA, out JVector pointB, out JVector normal, out float penetration) + out JVector pointA, out JVector pointB, out JVector normal, out Real penetration) { Unsafe.SkipInit(out MinkowskiDifference mkd); mkd.SupportA = supportA; @@ -865,7 +865,7 @@ public static bool Collision(in ISupportMappable supportA, in ISupportMappable s [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Distance(in ISupportMappable supportA, in ISupportMappable supportB, in JQuaternion orientationB, in JVector positionB, - out JVector pointA, out JVector pointB, out float distance) + out JVector pointA, out JVector pointB, out Real distance) { Unsafe.SkipInit(out MinkowskiDifference mkd); mkd.SupportA = supportA; @@ -895,7 +895,7 @@ public static bool Distance(in ISupportMappable supportA, in ISupportMappable su public static bool Distance(in ISupportMappable supportA, in ISupportMappable supportB, in JQuaternion orientationA, in JQuaternion orientationB, in JVector positionA, in JVector positionB, - out JVector pointA, out JVector pointB, out float distance) + out JVector pointA, out JVector pointB, out Real distance) { Unsafe.SkipInit(out MinkowskiDifference mkd); mkd.SupportA = supportA; @@ -996,7 +996,7 @@ public static bool Overlap(in ISupportMappable supportA, in ISupportMappable sup public static bool MPREPA(in ISupportMappable supportA, in ISupportMappable supportB, in JQuaternion orientationA, in JQuaternion orientationB, in JVector positionA, in JVector positionB, - out JVector pointA, out JVector pointB, out JVector normal, out float penetration) + out JVector pointA, out JVector pointB, out JVector normal, out Real penetration) { Unsafe.SkipInit(out MinkowskiDifference mkd); mkd.SupportA = supportA; @@ -1043,7 +1043,7 @@ public static bool MPREPA(in ISupportMappable supportA, in ISupportMappable supp [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool MPREPA(in ISupportMappable supportA, in ISupportMappable supportB, in JQuaternion orientationB, in JVector positionB, - out JVector pointA, out JVector pointB, out JVector normal, out float penetration) + out JVector pointA, out JVector pointB, out JVector normal, out Real penetration) { Unsafe.SkipInit(out MinkowskiDifference mkd); mkd.SupportA = supportA; @@ -1072,7 +1072,7 @@ public static bool Sweep(in ISupportMappable supportA, in ISupportMappable suppo in JQuaternion orientationA, in JQuaternion orientationB, in JVector positionA, in JVector positionB, in JVector sweepA, in JVector sweepB, - out JVector pointA, out JVector pointB, out JVector normal, out float lambda) + out JVector pointA, out JVector pointB, out JVector normal, out Real lambda) { Unsafe.SkipInit(out MinkowskiDifference mkd); @@ -1123,7 +1123,7 @@ public static bool Sweep(in ISupportMappable supportA, in ISupportMappable suppo [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Sweep(in ISupportMappable supportA, in ISupportMappable supportB, in JQuaternion orientationB, in JVector positionB, in JVector sweepB, - out JVector pointA, out JVector pointB, out JVector normal, out float lambda) + out JVector pointA, out JVector pointB, out JVector normal, out Real lambda) { Unsafe.SkipInit(out MinkowskiDifference mkd); diff --git a/src/Jitter2/Collision/NarrowPhase/SimplexSolver.cs b/src/Jitter2/Collision/NarrowPhase/SimplexSolver.cs index 47048383..51fde3ee 100644 --- a/src/Jitter2/Collision/NarrowPhase/SimplexSolver.cs +++ b/src/Jitter2/Collision/NarrowPhase/SimplexSolver.cs @@ -33,7 +33,7 @@ namespace Jitter2.Collision; public unsafe struct SimplexSolver { - const float Epsilon = 1e-8f; + const Real Epsilon = (Real)1e-8; private JVector v0; private JVector v1; @@ -54,13 +54,13 @@ private JVector ClosestSegment(int i0, int i1, out uint mask) JVector b = ptr[i1]; JVector v = b - a; - float vsq = v.LengthSquared(); + Real vsq = v.LengthSquared(); bool degenerate = vsq < Epsilon; - float t = -JVector.Dot(a, v) / vsq; - float lambda0 = 1 - t; - float lambda1 = t; + Real t = -JVector.Dot(a, v) / vsq; + Real lambda0 = 1 - t; + Real lambda1 = t; mask = (1u << i0 | 1u << i1); @@ -94,25 +94,25 @@ private JVector ClosestTriangle(int i0, int i1, int i2, out uint mask) JVector normal = u % v; - float t = normal.LengthSquared(); - float it = 1.0f / t; + Real t = normal.LengthSquared(); + Real it = (Real)1.0 / t; bool degenerate = t < Epsilon; JVector.Cross(u, a, out var c1); JVector.Cross(a, v, out var c2); - float lambda2 = JVector.Dot(c1, normal) * it; - float lambda1 = JVector.Dot(c2, normal) * it; - float lambda0 = 1.0f - lambda2 - lambda1; + Real lambda2 = JVector.Dot(c1, normal) * it; + Real lambda1 = JVector.Dot(c2, normal) * it; + Real lambda0 = (Real)1.0 - lambda2 - lambda1; - float bestDistance = float.MaxValue; + Real bestDistance = Real.MaxValue; Unsafe.SkipInit(out JVector closestPt); - if (lambda0 < 0.0f || degenerate) + if (lambda0 < (Real)0.0 || degenerate) { var closest = ClosestSegment(i1, i2, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { mask = m; @@ -121,10 +121,10 @@ private JVector ClosestTriangle(int i0, int i1, int i2, out uint mask) } } - if (lambda1 < 0.0f || degenerate) + if (lambda1 < (Real)0.0 || degenerate) { var closest = ClosestSegment(i0, i2, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { mask = m; @@ -133,10 +133,10 @@ private JVector ClosestTriangle(int i0, int i1, int i2, out uint mask) } } - if (lambda2 < 0.0f || degenerate) + if (lambda2 < (Real)0.0 || degenerate) { var closest = ClosestSegment(i0, i1, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { mask = m; @@ -153,31 +153,31 @@ private JVector ClosestTriangle(int i0, int i1, int i2, out uint mask) private JVector ClosestTetrahedron(out uint mask) { [MethodImpl(MethodImplOptions.AggressiveInlining)] - float Determinant(in JVector a, in JVector b, in JVector c, in JVector d) + Real Determinant(in JVector a, in JVector b, in JVector c, in JVector d) { return JVector.Dot(b - a, JVector.Cross(c - a, d - a)); } - float detT = Determinant(v0, v1, v2, v3); - float inverseDetT = 1.0f / detT; + Real detT = Determinant(v0, v1, v2, v3); + Real inverseDetT = (Real)1.0 / detT; bool degenerate = detT * detT < Epsilon; - float lambda0 = Determinant(JVector.Zero, v1, v2, v3) * inverseDetT; - float lambda1 = Determinant(v0, JVector.Zero, v2, v3) * inverseDetT; - float lambda2 = Determinant(v0, v1, JVector.Zero, v3) * inverseDetT; - float lambda3 = 1.0f - lambda0 - lambda1 - lambda2; + Real lambda0 = Determinant(JVector.Zero, v1, v2, v3) * inverseDetT; + Real lambda1 = Determinant(v0, JVector.Zero, v2, v3) * inverseDetT; + Real lambda2 = Determinant(v0, v1, JVector.Zero, v3) * inverseDetT; + Real lambda3 = (Real)1.0 - lambda0 - lambda1 - lambda2; - float bestDistance = float.MaxValue; + Real bestDistance = Real.MaxValue; Unsafe.SkipInit(out JVector closestPt); mask = 0; - if (lambda0 < 0.0f || degenerate) + if (lambda0 < (Real)0.0 || degenerate) { var closest = ClosestTriangle(1, 2, 3, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { mask = m; @@ -186,10 +186,10 @@ float Determinant(in JVector a, in JVector b, in JVector c, in JVector d) } } - if (lambda1 < 0.0f || degenerate) + if (lambda1 < (Real)0.0 || degenerate) { var closest = ClosestTriangle(0, 2, 3, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { mask = m; @@ -198,10 +198,10 @@ float Determinant(in JVector a, in JVector b, in JVector c, in JVector d) } } - if (lambda2 < 0.0f || degenerate) + if (lambda2 < (Real)0.0 || degenerate) { var closest = ClosestTriangle(0, 1, 3, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { mask = m; @@ -210,10 +210,10 @@ float Determinant(in JVector a, in JVector b, in JVector c, in JVector d) } } - if (lambda3 < 0.0f || degenerate) + if (lambda3 < (Real)0.0 || degenerate) { var closest = ClosestTriangle(0, 1, 2, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { mask = m; diff --git a/src/Jitter2/Collision/NarrowPhase/SimplexSolverAB.cs b/src/Jitter2/Collision/NarrowPhase/SimplexSolverAB.cs index aa2aaaf2..cc042a0f 100644 --- a/src/Jitter2/Collision/NarrowPhase/SimplexSolverAB.cs +++ b/src/Jitter2/Collision/NarrowPhase/SimplexSolverAB.cs @@ -35,19 +35,19 @@ namespace Jitter2.Collision; public unsafe struct SimplexSolverAB { - const float Epsilon = 1e-8f; + const Real Epsilon = (Real)1e-8; private struct Barycentric { - public float Lambda0; - public float Lambda1; - public float Lambda2; - public float Lambda3; + public Real Lambda0; + public Real Lambda1; + public Real Lambda2; + public Real Lambda3; - public float this[int i] + public Real this[int i] { - get => ((float*)Unsafe.AsPointer(ref this.Lambda0))[i]; - set => ((float*)Unsafe.AsPointer(ref this.Lambda0))[i] = value; + get => ((Real*)Unsafe.AsPointer(ref this.Lambda0))[i]; + set => ((Real*)Unsafe.AsPointer(ref this.Lambda0))[i] = value; } } @@ -71,13 +71,13 @@ private JVector ClosestSegment(int i0, int i1, ref Barycentric bc, out uint mask JVector b = ptr[i1].V; JVector v = b - a; - float vsq = v.LengthSquared(); + Real vsq = v.LengthSquared(); bool degenerate = vsq < Epsilon; - float t = -JVector.Dot(a, v) / vsq; - float lambda0 = 1 - t; - float lambda1 = t; + Real t = -JVector.Dot(a, v) / vsq; + Real lambda0 = 1 - t; + Real lambda1 = t; mask = (1u << i0 | 1u << i1); @@ -114,26 +114,26 @@ private JVector ClosestTriangle(int i0, int i1, int i2, ref Barycentric bc, out JVector normal = u % v; - float t = normal.LengthSquared(); - float it = 1.0f / t; + Real t = normal.LengthSquared(); + Real it = (Real)1.0 / t; bool degenerate = t < Epsilon; JVector.Cross(u, a, out var c1); JVector.Cross(a, v, out var c2); - float lambda2 = JVector.Dot(c1, normal) * it; - float lambda1 = JVector.Dot(c2, normal) * it; - float lambda0 = 1.0f - lambda2 - lambda1; + Real lambda2 = JVector.Dot(c1, normal) * it; + Real lambda1 = JVector.Dot(c2, normal) * it; + Real lambda0 = (Real)1.0 - lambda2 - lambda1; - float bestDistance = float.MaxValue; + Real bestDistance = Real.MaxValue; Unsafe.SkipInit(out JVector closestPt); Unsafe.SkipInit(out Barycentric b0); - if (lambda0 < 0.0f || degenerate) + if (lambda0 < (Real)0.0 || degenerate) { var closest = ClosestSegment(i1, i2, ref b0, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { bc = b0; @@ -143,10 +143,10 @@ private JVector ClosestTriangle(int i0, int i1, int i2, ref Barycentric bc, out } } - if (lambda1 < 0.0f || degenerate) + if (lambda1 < (Real)0.0 || degenerate) { var closest = ClosestSegment(i0, i2, ref b0, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { bc = b0; @@ -156,10 +156,10 @@ private JVector ClosestTriangle(int i0, int i1, int i2, ref Barycentric bc, out } } - if (lambda2 < 0.0f || degenerate) + if (lambda2 < (Real)0.0 || degenerate) { var closest = ClosestSegment(i0, i1, ref b0, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { bc = b0; @@ -181,32 +181,32 @@ private JVector ClosestTriangle(int i0, int i1, int i2, ref Barycentric bc, out private JVector ClosestTetrahedron(ref Barycentric bc, out uint mask) { [MethodImpl(MethodImplOptions.AggressiveInlining)] - float Determinant(in JVector a, in JVector b, in JVector c, in JVector d) + Real Determinant(in JVector a, in JVector b, in JVector c, in JVector d) { return JVector.Dot(b - a, JVector.Cross(c - a, d - a)); } - float detT = Determinant(v0.V, v1.V, v2.V, v3.V); - float inverseDetT = 1.0f / detT; + Real detT = Determinant(v0.V, v1.V, v2.V, v3.V); + Real inverseDetT = (Real)1.0 / detT; bool degenerate = detT * detT < Epsilon; - float lambda0 = Determinant(JVector.Zero, v1.V, v2.V, v3.V) * inverseDetT; - float lambda1 = Determinant(v0.V, JVector.Zero, v2.V, v3.V) * inverseDetT; - float lambda2 = Determinant(v0.V, v1.V, JVector.Zero, v3.V) * inverseDetT; - float lambda3 = 1.0f - lambda0 - lambda1 - lambda2; + Real lambda0 = Determinant(JVector.Zero, v1.V, v2.V, v3.V) * inverseDetT; + Real lambda1 = Determinant(v0.V, JVector.Zero, v2.V, v3.V) * inverseDetT; + Real lambda2 = Determinant(v0.V, v1.V, JVector.Zero, v3.V) * inverseDetT; + Real lambda3 = (Real)1.0 - lambda0 - lambda1 - lambda2; - float bestDistance = float.MaxValue; + Real bestDistance = Real.MaxValue; Unsafe.SkipInit(out JVector closestPt); Unsafe.SkipInit(out Barycentric b0); mask = 0; - if (lambda0 < 0.0f || degenerate) + if (lambda0 < (Real)0.0 || degenerate) { var closest = ClosestTriangle(1, 2, 3, ref b0, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { bc = b0; @@ -216,10 +216,10 @@ float Determinant(in JVector a, in JVector b, in JVector c, in JVector d) } } - if (lambda1 < 0.0f || degenerate) + if (lambda1 < (Real)0.0 || degenerate) { var closest = ClosestTriangle(0, 2, 3, ref b0, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { bc = b0; @@ -229,10 +229,10 @@ float Determinant(in JVector a, in JVector b, in JVector c, in JVector d) } } - if (lambda2 < 0.0f || degenerate) + if (lambda2 < (Real)0.0 || degenerate) { var closest = ClosestTriangle(0, 1, 3, ref b0, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { bc = b0; @@ -242,10 +242,10 @@ float Determinant(in JVector a, in JVector b, in JVector c, in JVector d) } } - if (lambda3 < 0.0f || degenerate) + if (lambda3 < (Real)0.0 || degenerate) { var closest = ClosestTriangle(0, 1, 2, ref b0, out uint m); - float dist = closest.LengthSquared(); + Real dist = closest.LengthSquared(); if (dist < bestDistance) { bc = b0; @@ -314,7 +314,7 @@ public bool AddVertex(in Vertex vertex, out JVector closest) int i0 = ix[0]; closest = ptr[i0].V; usageMask = 1u << i0; - barycentric[i0] = 1.0f; + barycentric[i0] = (Real)1.0; return true; } case 2: diff --git a/src/Jitter2/Collision/Shapes/BoxShape.cs b/src/Jitter2/Collision/Shapes/BoxShape.cs index f5f0f848..7cc60c2f 100644 --- a/src/Jitter2/Collision/Shapes/BoxShape.cs +++ b/src/Jitter2/Collision/Shapes/BoxShape.cs @@ -38,10 +38,10 @@ public class BoxShape : RigidBodyShape /// public JVector Size { - get => 2.0f * halfSize; + get => (Real)2.0 * halfSize; set { - halfSize = value * 0.5f; + halfSize = value * (Real)0.5; UpdateWorldBoundingBox(); } } @@ -52,7 +52,7 @@ public JVector Size /// The dimensions of the box. public BoxShape(JVector size) { - halfSize = 0.5f * size; + halfSize = (Real)0.5 * size; UpdateWorldBoundingBox(); } @@ -60,9 +60,9 @@ public BoxShape(JVector size) /// Creates a cube shape with the specified side length. /// /// The length of each side of the cube. - public BoxShape(float size) + public BoxShape(Real size) { - halfSize = new JVector(size * 0.5f); + halfSize = new JVector(size * (Real)0.5); UpdateWorldBoundingBox(); } @@ -72,9 +72,9 @@ public BoxShape(float size) /// The length of the box. /// The height of the box. /// The width of the box. - public BoxShape(float length, float height, float width) + public BoxShape(Real length, Real height, Real width) { - halfSize = 0.5f * new JVector(length, height, width); + halfSize = (Real)0.5 * new JVector(length, height, width); UpdateWorldBoundingBox(); } @@ -85,23 +85,23 @@ public override void SupportMap(in JVector direction, out JVector result) result.Z = Math.Sign(direction.Z) * halfSize.Z; } - public override bool LocalRayCast(in JVector origin, in JVector direction, out JVector normal, out float lambda) + public override bool LocalRayCast(in JVector origin, in JVector direction, out JVector normal, out Real lambda) { - float epsilon = 1e-22f; + Real epsilon = (Real)1e-22; JVector min = -halfSize; JVector max = halfSize; normal = JVector.Zero; - lambda = 0.0f; + lambda = (Real)0.0; - float exit = float.PositiveInfinity; + Real exit = Real.PositiveInfinity; - if (MathF.Abs(direction.X) > epsilon) + if (MathR.Abs(direction.X) > epsilon) { - float ix = 1.0f / direction.X; - float t0 = (min.X - origin.X) * ix; - float t1 = (max.X - origin.X) * ix; + Real ix = (Real)1.0 / direction.X; + Real t0 = (min.X - origin.X) * ix; + Real t1 = (max.X - origin.X) * ix; if (t0 > t1) (t0, t1) = (t1, t0); @@ -110,7 +110,7 @@ public override bool LocalRayCast(in JVector origin, in JVector direction, out J if (t0 > lambda) { lambda = t0; - normal = direction.X < 0.0f ? JVector.UnitX : -JVector.UnitX; + normal = direction.X < (Real)0.0 ? JVector.UnitX : -JVector.UnitX; } if (t1 < exit) exit = t1; @@ -120,11 +120,11 @@ public override bool LocalRayCast(in JVector origin, in JVector direction, out J return false; } - if (MathF.Abs(direction.Y) > epsilon) + if (MathR.Abs(direction.Y) > epsilon) { - float iy = 1.0f / direction.Y; - float t0 = (min.Y - origin.Y) * iy; - float t1 = (max.Y - origin.Y) * iy; + Real iy = (Real)1.0 / direction.Y; + Real t0 = (min.Y - origin.Y) * iy; + Real t1 = (max.Y - origin.Y) * iy; if (t0 > t1) (t0, t1) = (t1, t0); @@ -133,7 +133,7 @@ public override bool LocalRayCast(in JVector origin, in JVector direction, out J if (t0 > lambda) { lambda = t0; - normal = direction.Y < 0.0f ? JVector.UnitY : -JVector.UnitY; + normal = direction.Y < (Real)0.0 ? JVector.UnitY : -JVector.UnitY; } if (t1 < exit) exit = t1; @@ -143,11 +143,11 @@ public override bool LocalRayCast(in JVector origin, in JVector direction, out J return false; } - if (MathF.Abs(direction.Z) > epsilon) + if (MathR.Abs(direction.Z) > epsilon) { - float iz = 1.0f / direction.Z; - float t0 = (min.Z - origin.Z) * iz; - float t1 = (max.Z - origin.Z) * iz; + Real iz = (Real)1.0 / direction.Z; + Real t0 = (min.Z - origin.Z) * iz; + Real t1 = (max.Z - origin.Z) * iz; if (t0 > t1) (t0, t1) = (t1, t0); @@ -156,7 +156,7 @@ public override bool LocalRayCast(in JVector origin, in JVector direction, out J if (t0 > lambda) { lambda = t0; - normal = direction.Z < 0.0f ? JVector.UnitZ : -JVector.UnitZ; + normal = direction.Z < (Real)0.0 ? JVector.UnitZ : -JVector.UnitZ; } //if (t1 < exit) exit = t1; } @@ -181,15 +181,15 @@ public override void CalculateBoundingBox(in JQuaternion orientation, in JVector box.Max = position + ths; } - public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out float mass) + public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out Real mass) { - JVector size = halfSize * 2.0f; + JVector size = halfSize * (Real)2.0; mass = size.X * size.Y * size.Z; inertia = JMatrix.Identity; - inertia.M11 = 1.0f / 12.0f * mass * (size.Y * size.Y + size.Z * size.Z); - inertia.M22 = 1.0f / 12.0f * mass * (size.X * size.X + size.Z * size.Z); - inertia.M33 = 1.0f / 12.0f * mass * (size.X * size.X + size.Y * size.Y); + inertia.M11 = (Real)(1.0 / 12.0) * mass * (size.Y * size.Y + size.Z * size.Z); + inertia.M22 = (Real)(1.0 / 12.0) * mass * (size.X * size.X + size.Z * size.Z); + inertia.M33 = (Real)(1.0 / 12.0) * mass * (size.X * size.X + size.Y * size.Y); com = JVector.Zero; } diff --git a/src/Jitter2/Collision/Shapes/CapsuleShape.cs b/src/Jitter2/Collision/Shapes/CapsuleShape.cs index b535d1b8..0af6ee78 100644 --- a/src/Jitter2/Collision/Shapes/CapsuleShape.cs +++ b/src/Jitter2/Collision/Shapes/CapsuleShape.cs @@ -31,13 +31,13 @@ namespace Jitter2.Collision.Shapes; /// public class CapsuleShape : RigidBodyShape { - private float radius; - private float halfLength; + private Real radius; + private Real halfLength; /// /// Gets or sets the radius of the capsule. /// - public float Radius + public Real Radius { get => radius; set @@ -50,12 +50,12 @@ public float Radius /// /// Gets or sets the length of the cylindrical part of the capsule, excluding the half-spheres on both ends. /// - public float Length + public Real Length { - get => 2.0f * halfLength; + get => (Real)2.0 * halfLength; set { - halfLength = value / 2.0f; + halfLength = value / (Real)2.0; UpdateWorldBoundingBox(); } } @@ -65,10 +65,10 @@ public float Length /// /// The radius of the capsule. /// The length of the cylindrical part of the capsule, excluding the half-spheres at both ends. - public CapsuleShape(float radius = 0.5f, float length = 1.0f) + public CapsuleShape(Real radius = (Real)0.5, Real length = (Real)1.0) { this.radius = radius; - halfLength = 0.5f * length; + halfLength = (Real)0.5 * length; UpdateWorldBoundingBox(); } @@ -86,7 +86,7 @@ public override void SupportMap(in JVector direction, out JVector result) // we have to calculate the dot-product with the direction // vector to decide whether p_1 or p_2 is the correct support point - result.Y += MathF.Sign(direction.Y) * halfLength; + result.Y += MathR.Sign(direction.Y) * halfLength; } public override void GetCenter(out JVector point) @@ -98,9 +98,9 @@ public override void CalculateBoundingBox(in JQuaternion orientation, in JVector { JVector delta = halfLength * orientation.GetBasisY(); - box.Max.X = +radius + MathF.Abs(delta.X); - box.Max.Y = +radius + MathF.Abs(delta.Y); - box.Max.Z = +radius + MathF.Abs(delta.Z); + box.Max.X = +radius + MathR.Abs(delta.X); + box.Max.Y = +radius + MathR.Abs(delta.Y); + box.Max.Z = +radius + MathR.Abs(delta.Z); box.Min = -box.Max; @@ -108,20 +108,20 @@ public override void CalculateBoundingBox(in JQuaternion orientation, in JVector box.Max += position; } - public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out float mass) + public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out Real mass) { - float length = 2.0f * halfLength; + Real length = (Real)2.0 * halfLength; - float massSphere = 4.0f / 3.0f * MathF.PI * radius * radius * radius; - float massCylinder = MathF.PI * radius * radius * length; + Real massSphere = (Real)(4.0 / 3.0) * MathR.PI * radius * radius * radius; + Real massCylinder = MathR.PI * radius * radius * length; inertia = JMatrix.Identity; - inertia.M11 = massCylinder * (1.0f / 12.0f * length * length + 1.0f / 4.0f * radius * radius) + massSphere * - (2.0f / 5.0f * radius * radius + 1.0f / 4.0f * length * length + 3.0f / 8.0f * length * radius); - inertia.M22 = 1.0f / 2.0f * massCylinder * radius * radius + 2.0f / 5.0f * massSphere * radius * radius; - inertia.M33 = massCylinder * (1.0f / 12.0f * length * length + 1.0f / 4.0f * radius * radius) + massSphere * - (2.0f / 5.0f * radius * radius + 1.0f / 4.0f * length * length + 3.0f / 8.0f * length * radius); + inertia.M11 = massCylinder * ((Real)(1.0 / 12.0) * length * length + (Real)(1.0 / 4.0) * radius * radius) + massSphere * + ((Real)(2.0 / 5.0) * radius * radius + (Real)(1.0 / 4.0) * length * length + (Real)(3.0 / 8.0) * length * radius); + inertia.M22 = (Real)(1.0 / 2.0) * massCylinder * radius * radius + (Real)(2.0 / 5.0) * massSphere * radius * radius; + inertia.M33 = massCylinder * ((Real)(1.0 / 12.0) * length * length + (Real)(1.0 / 4.0) * radius * radius) + massSphere * + ((Real)(2.0 / 5.0) * radius * radius + (Real)(1.0 / 4.0) * length * length + (Real)(3.0 / 8.0) * length * radius); mass = massCylinder + massSphere; com = JVector.Zero; diff --git a/src/Jitter2/Collision/Shapes/ConeShape.cs b/src/Jitter2/Collision/Shapes/ConeShape.cs index d782d1ad..48ba56b7 100644 --- a/src/Jitter2/Collision/Shapes/ConeShape.cs +++ b/src/Jitter2/Collision/Shapes/ConeShape.cs @@ -31,13 +31,13 @@ namespace Jitter2.Collision.Shapes; /// public class ConeShape : RigidBodyShape { - private float radius; - private float height; + private Real radius; + private Real height; /// /// Gets or sets the radius of the cone at its base. /// - public float Radius + public Real Radius { get => radius; set @@ -50,7 +50,7 @@ public float Radius /// /// Gets or sets the height of the cone. /// - public float Height + public Real Height { get => height; set @@ -65,7 +65,7 @@ public float Height /// /// The radius of the cone at its base. /// The height of the cone. - public ConeShape(float radius = 0.5f, float height = 1.0f) + public ConeShape(Real radius = (Real)0.5, Real height = (Real)1.0) { this.radius = radius; this.height = height; @@ -74,29 +74,29 @@ public ConeShape(float radius = 0.5f, float height = 1.0f) public override void SupportMap(in JVector direction, out JVector result) { - const float ZeroEpsilon = 1e-12f; + const Real ZeroEpsilon = (Real)1e-12; // cone = disk + point // center of mass of a cone is at 0.25 height JVector ndir = direction; - ndir.Y = 0.0f; - float ndir2 = ndir.LengthSquared(); + ndir.Y = (Real)0.0; + Real ndir2 = ndir.LengthSquared(); if (ndir2 > ZeroEpsilon) { - ndir *= radius / MathF.Sqrt(ndir2); + ndir *= radius / MathR.Sqrt(ndir2); } - ndir.Y = -0.25f * height; + ndir.Y = -(Real)0.25 * height; // disk support point vs (0, 0.75 * height, 0) - if (JVector.Dot(direction, ndir) >= direction.Y * 0.75f * height) + if (JVector.Dot(direction, ndir) >= direction.Y * (Real)0.75 * height) { result = ndir; } else { - result = new JVector(0, 0.75f * height, 0); + result = new JVector(0, (Real)0.75 * height, 0); } } @@ -107,40 +107,40 @@ public override void GetCenter(out JVector point) public override void CalculateBoundingBox(in JQuaternion orientation, in JVector position, out JBBox box) { - const float ZeroEpsilon = 1e-12f; + const Real ZeroEpsilon = (Real)1e-12; JVector upa = orientation.GetBasisY(); - float xx = upa.X * upa.X; - float yy = upa.Y * upa.Y; - float zz = upa.Z * upa.Z; + Real xx = upa.X * upa.X; + Real yy = upa.Y * upa.Y; + Real zz = upa.Z * upa.Z; - float l1 = yy + zz; - float l2 = xx + zz; - float l3 = xx + yy; + Real l1 = yy + zz; + Real l2 = xx + zz; + Real l3 = xx + yy; - float xext = 0, yext = 0, zext = 0; + Real xext = 0, yext = 0, zext = 0; if (l1 > ZeroEpsilon) { - float sl = 1.0f / MathF.Sqrt(l1); + Real sl = (Real)1.0 / MathR.Sqrt(l1); xext = (yy + zz) * sl * radius; } if (l2 > ZeroEpsilon) { - float sl = 1.0f / MathF.Sqrt(l2); + Real sl = (Real)1.0 / MathR.Sqrt(l2); yext = (xx + zz) * sl * radius; } if (l3 > ZeroEpsilon) { - float sl = 1.0f / MathF.Sqrt(l3); + Real sl = (Real)1.0 / MathR.Sqrt(l3); zext = (xx + yy) * sl * radius; } - JVector p1 = -0.25f * height * upa; - JVector p2 = +0.75f * height * upa; + JVector p1 = -(Real)0.25 * height * upa; + JVector p2 = +(Real)0.75 * height * upa; box.Min = p1 - new JVector(xext, yext, zext); box.Max = p1 + new JVector(xext, yext, zext); @@ -151,14 +151,14 @@ public override void CalculateBoundingBox(in JQuaternion orientation, in JVector box.Max += position; } - public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out float mass) + public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out Real mass) { - mass = 1.0f / 3.0f * MathF.PI * radius * radius * height; + mass = (Real)(1.0 / 3.0) * MathR.PI * radius * radius * height; inertia = JMatrix.Identity; - inertia.M11 = mass * (3.0f / 20.0f * radius * radius + 3.0f / 80.0f * height * height); - inertia.M22 = 3.0f / 10.0f * mass * radius * radius; - inertia.M33 = mass * (3.0f / 20.0f * radius * radius + 3.0f / 80.0f * height * height); + inertia.M11 = mass * ((Real)(3.0 / 20.0) * radius * radius + (Real)(3.0 / 80.0) * height * height); + inertia.M22 = (Real)(3.0 / 10.0) * mass * radius * radius; + inertia.M33 = mass * ((Real)(3.0 / 20.0) * radius * radius + (Real)(3.0 / 80.0) * height * height); com = JVector.Zero; } diff --git a/src/Jitter2/Collision/Shapes/ConvexHullShape.cs b/src/Jitter2/Collision/Shapes/ConvexHullShape.cs index 81510016..c32b6586 100644 --- a/src/Jitter2/Collision/Shapes/ConvexHullShape.cs +++ b/src/Jitter2/Collision/Shapes/ConvexHullShape.cs @@ -75,7 +75,7 @@ public CHullTriangle(ushort a, ushort b, ushort c) private JBBox cachedBoundingBox; private JMatrix cachedInertia; - private float cachedMass; + private Real cachedMass; private JVector cachedCenter; private CHullVector[] vertices = null!; @@ -208,7 +208,7 @@ public void UpdateShape() CalcInitBox(); } - public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out float mass) + public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out Real mass) { inertia = cachedInertia; com = cachedCenter; @@ -221,8 +221,8 @@ public void CalculateMassInertia() cachedInertia = JMatrix.Zero; cachedMass = 0; - const float a = 1.0f / 60.0f; - const float b = 1.0f / 120.0f; + const Real a = (Real)(1.0 / 60.0); + const Real b = (Real)(1.0 / 120.0); JMatrix C = new(a, b, b, b, a, b, b, b, a); JVector pointWithin = JVector.Zero; @@ -232,7 +232,7 @@ public void CalculateMassInertia() pointWithin += vertices[i].Vertex; } - pointWithin = pointWithin * (1.0f / vertices.Length) + shifted; + pointWithin = pointWithin * ((Real)1.0 / vertices.Length) + shifted; foreach (CHullTriangle tri in indices) { @@ -243,8 +243,8 @@ public void CalculateMassInertia() // check winding { JVector normal = (column1 - column0) % (column2 - column0); - float ddot = JVector.Dot(normal, column0 - pointWithin); - if (ddot < 0.0f) + Real ddot = JVector.Dot(normal, column0 - pointWithin); + if (ddot < (Real)0.0) { (column0, column1) = (column1, column0); } @@ -255,12 +255,12 @@ public void CalculateMassInertia() column0.Y, column1.Y, column2.Y, column0.Z, column1.Z, column2.Z); - float detA = A.Determinant(); + Real detA = A.Determinant(); JMatrix tetrahedronInertia = JMatrix.Multiply(A * C * JMatrix.Transpose(A), detA); - JVector tetrahedronCom = 1.0f / 4.0f * (column0 + column1 + column2); - float tetrahedronMass = 1.0f / 6.0f * detA; + JVector tetrahedronCom = (Real)(1.0 / 4.0) * (column0 + column1 + column2); + Real tetrahedronMass = (Real)(1.0 / 6.0) * detA; cachedInertia += tetrahedronInertia; cachedCenter += tetrahedronMass * tetrahedronCom; @@ -268,13 +268,13 @@ public void CalculateMassInertia() } cachedInertia = JMatrix.Multiply(JMatrix.Identity, cachedInertia.Trace()) - cachedInertia; - cachedCenter *= 1.0f / cachedMass; + cachedCenter *= (Real)1.0 / cachedMass; } public override void CalculateBoundingBox(in JQuaternion orientation, in JVector position, out JBBox box) { - JVector halfSize = 0.5f * (cachedBoundingBox.Max - cachedBoundingBox.Min); - JVector center = 0.5f * (cachedBoundingBox.Max + cachedBoundingBox.Min); + JVector halfSize = (Real)0.5 * (cachedBoundingBox.Max - cachedBoundingBox.Min); + JVector center = (Real)0.5 * (cachedBoundingBox.Max + cachedBoundingBox.Min); JMatrix ori = JMatrix.CreateFromQuaternion(orientation); JMatrix.Absolute(in ori, out JMatrix abs); @@ -318,7 +318,7 @@ private void CalcInitBox() private ushort InternalSupportMap(in JVector direction, out JVector result) { ushort current = 0; - float dotProduct = JVector.Dot(vertices[current].Vertex, direction); + Real dotProduct = JVector.Dot(vertices[current].Vertex, direction); again: var min = vertices[current].NeighborMinIndex; @@ -327,7 +327,7 @@ private ushort InternalSupportMap(in JVector direction, out JVector result) for (int i = min; i < max; i++) { ushort nb = neighborList[i]; - float nbProduct = JVector.Dot(vertices[nb].Vertex, direction); + Real nbProduct = JVector.Dot(vertices[nb].Vertex, direction); if (nbProduct > dotProduct) { diff --git a/src/Jitter2/Collision/Shapes/CylinderShape.cs b/src/Jitter2/Collision/Shapes/CylinderShape.cs index 0a7fab34..8d6c8fd7 100644 --- a/src/Jitter2/Collision/Shapes/CylinderShape.cs +++ b/src/Jitter2/Collision/Shapes/CylinderShape.cs @@ -31,13 +31,13 @@ namespace Jitter2.Collision.Shapes; /// public class CylinderShape : RigidBodyShape { - private float radius; - private float height; + private Real radius; + private Real height; /// /// Gets or sets the radius of the cylinder. /// - public float Radius + public Real Radius { get => radius; set @@ -50,7 +50,7 @@ public float Radius /// /// Gets or sets the height of the cylinder. /// - public float Height + public Real Height { get => height; set @@ -65,7 +65,7 @@ public float Height /// /// The height of the cylinder. /// The radius of the cylinder at its base. - public CylinderShape(float height, float radius) + public CylinderShape(Real height, Real radius) { this.radius = radius; this.height = height; @@ -79,58 +79,58 @@ public override void GetCenter(out JVector point) public override void SupportMap(in JVector direction, out JVector result) { - float sigma = (float)Math.Sqrt(direction.X * direction.X + direction.Z * direction.Z); + Real sigma = (Real)Math.Sqrt(direction.X * direction.X + direction.Z * direction.Z); - if (sigma > 0.0f) + if (sigma > (Real)0.0) { result.X = direction.X / sigma * radius; - result.Y = Math.Sign(direction.Y) * height * 0.5f; + result.Y = Math.Sign(direction.Y) * height * (Real)0.5; result.Z = direction.Z / sigma * radius; } else { - result.X = 0.0f; - result.Y = Math.Sign(direction.Y) * height * 0.5f; - result.Z = 0.0f; + result.X = (Real)0.0; + result.Y = Math.Sign(direction.Y) * height * (Real)0.5; + result.Z = (Real)0.0; } } public override void CalculateBoundingBox(in JQuaternion orientation, in JVector position, out JBBox box) { - const float zeroEpsilon = 1e-12f; + const Real zeroEpsilon = (Real)1e-12; JVector upa = orientation.GetBasisY(); - float xx = upa.X * upa.X; - float yy = upa.Y * upa.Y; - float zz = upa.Z * upa.Z; + Real xx = upa.X * upa.X; + Real yy = upa.Y * upa.Y; + Real zz = upa.Z * upa.Z; - float l1 = yy + zz; - float l2 = xx + zz; - float l3 = xx + yy; + Real l1 = yy + zz; + Real l2 = xx + zz; + Real l3 = xx + yy; - float xext = 0, yext = 0, zext = 0; + Real xext = 0, yext = 0, zext = 0; if (l1 > zeroEpsilon) { - float sl = 1.0f / MathF.Sqrt(l1); + Real sl = (Real)1.0 / MathR.Sqrt(l1); xext = (yy + zz) * sl * radius; } if (l2 > zeroEpsilon) { - float sl = 1.0f / MathF.Sqrt(l2); + Real sl = (Real)1.0 / MathR.Sqrt(l2); yext = (xx + zz) * sl * radius; } if (l3 > zeroEpsilon) { - float sl = 1.0f / MathF.Sqrt(l3); + Real sl = (Real)1.0 / MathR.Sqrt(l3); zext = (xx + yy) * sl * radius; } - JVector p1 = -0.5f * height * upa; - JVector p2 = +0.5f * height * upa; + JVector p1 = -(Real)0.5 * height * upa; + JVector p2 = +(Real)0.5 * height * upa; JVector delta = JVector.Max(p1, p2) + new JVector(xext, yext, zext); @@ -138,15 +138,15 @@ public override void CalculateBoundingBox(in JQuaternion orientation, in JVector box.Max = position + delta; } - public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out float mass) + public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out Real mass) { - mass = MathF.PI * radius * radius * height; + mass = MathR.PI * radius * radius * height; inertia = JMatrix.Identity; - inertia.M11 = 1.0f / 4.0f * mass * radius * radius + 1.0f / 12.0f * mass * height * height; - inertia.M22 = 1.0f / 2.0f * mass * radius * radius; - inertia.M33 = 1.0f / 4.0f * mass * radius * radius + 1.0f / 12.0f * mass * height * height; + inertia.M11 = (Real)(1.0 / 4.0) * mass * radius * radius + (Real)(1.0 / 12.0) * mass * height * height; + inertia.M22 = (Real)(1.0 / 2.0) * mass * radius * radius; + inertia.M33 = (Real)(1.0 / 4.0) * mass * radius * radius + (Real)(1.0 / 12.0) * mass * height * height; com = JVector.Zero; } diff --git a/src/Jitter2/Collision/Shapes/FatTriangleShape.cs b/src/Jitter2/Collision/Shapes/FatTriangleShape.cs index 92d13031..c44f2467 100644 --- a/src/Jitter2/Collision/Shapes/FatTriangleShape.cs +++ b/src/Jitter2/Collision/Shapes/FatTriangleShape.cs @@ -33,18 +33,18 @@ namespace Jitter2.Collision.Shapes; /// public class FatTriangleShape : TriangleShape { - private float thickness; + private Real thickness; /// /// Set or get the thickness of the triangle. /// /// Thickness must be larger than 0.01 length units. - public float Thickness + public Real Thickness { get => thickness; set { - const float minimumThickness = 0.01f; + const Real minimumThickness = (Real)0.01; if (value < minimumThickness) { @@ -60,7 +60,7 @@ public float Thickness /// /// The triangle mesh to which this triangle belongs. /// The index representing the position of the triangle within the mesh. - public FatTriangleShape(TriangleMesh mesh, int index, float thickness = 0.2f) : base(mesh, index) + public FatTriangleShape(TriangleMesh mesh, int index, Real thickness = (Real)0.2) : base(mesh, index) { this.thickness = thickness; UpdateWorldBoundingBox(); @@ -102,8 +102,8 @@ public override void SupportMap(in JVector direction, out JVector result) JVector b = Mesh.Vertices[triangle.IndexB]; JVector c = Mesh.Vertices[triangle.IndexC]; - float min = JVector.Dot(a, direction); - float dot = JVector.Dot(b, direction); + Real min = JVector.Dot(a, direction); + Real dot = JVector.Dot(b, direction); result = a; @@ -120,7 +120,7 @@ public override void SupportMap(in JVector direction, out JVector result) result = c; } - if (JVector.Dot(triangle.Normal, direction) < 0.0f) + if (JVector.Dot(triangle.Normal, direction) < (Real)0.0) result -= triangle.Normal * Thickness; } } \ No newline at end of file diff --git a/src/Jitter2/Collision/Shapes/PointCloudShape.cs b/src/Jitter2/Collision/Shapes/PointCloudShape.cs index 868799da..2c5343a1 100644 --- a/src/Jitter2/Collision/Shapes/PointCloudShape.cs +++ b/src/Jitter2/Collision/Shapes/PointCloudShape.cs @@ -36,7 +36,7 @@ public class PointCloudShape : RigidBodyShape { private JBBox cachedBoundingBox; private JMatrix cachedInertia; - private float cachedMass; + private Real cachedMass; private JVector cachedCenter; private List vertices; @@ -103,7 +103,7 @@ public void CalculateMassInertia() ShapeHelper.CalculateMassInertia(this, out cachedInertia, out cachedCenter, out cachedMass); } - public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out float mass) + public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out Real mass) { inertia = cachedInertia; com = cachedCenter; @@ -112,8 +112,8 @@ public override void CalculateMassInertia(out JMatrix inertia, out JVector com, public override void CalculateBoundingBox(in JQuaternion orientation, in JVector position, out JBBox box) { - JVector halfSize = 0.5f * (cachedBoundingBox.Max - cachedBoundingBox.Min); - JVector center = 0.5f * (cachedBoundingBox.Max + cachedBoundingBox.Min); + JVector halfSize = (Real)0.5 * (cachedBoundingBox.Max - cachedBoundingBox.Min); + JVector center = (Real)0.5 * (cachedBoundingBox.Max + cachedBoundingBox.Min); JMatrix ori = JMatrix.CreateFromQuaternion(orientation); JMatrix.Absolute(in ori, out JMatrix abs); @@ -156,9 +156,9 @@ private void CalcInitBox() public override void SupportMap(in JVector direction, out JVector result) { - float maxDotProduct = float.MinValue; + Real maxDotProduct = Real.MinValue; int maxIndex = 0; - float dotProduct; + Real dotProduct; for (int i = 0; i < vertices.Count; i++) { diff --git a/src/Jitter2/Collision/Shapes/RigidBodyShape.cs b/src/Jitter2/Collision/Shapes/RigidBodyShape.cs index d6d2b542..1112f028 100644 --- a/src/Jitter2/Collision/Shapes/RigidBodyShape.cs +++ b/src/Jitter2/Collision/Shapes/RigidBodyShape.cs @@ -35,7 +35,7 @@ public abstract class RigidBodyShape : Shape public sealed override JVector Velocity => RigidBody?.Velocity ?? JVector.Zero; - public sealed override void UpdateWorldBoundingBox(float dt = 0.0f) + public sealed override void UpdateWorldBoundingBox(Real dt = (Real)0.0) { JBBox box; @@ -63,7 +63,7 @@ public virtual void CalculateBoundingBox(in JQuaternion orientation, in JVector /// constructed using the support map function. /// [ReferenceFrame(ReferenceFrame.Local)] - public virtual void CalculateMassInertia(out JMatrix inertia, out JVector com, out float mass) + public virtual void CalculateMassInertia(out JMatrix inertia, out JVector com, out Real mass) { ShapeHelper.CalculateMassInertia(this, out inertia, out com, out mass); } @@ -89,13 +89,13 @@ public virtual void CalculateMassInertia(out JMatrix inertia, out JVector com, o /// true if the ray intersects with the object; otherwise, false. /// [ReferenceFrame(ReferenceFrame.Local)] - public virtual bool LocalRayCast(in JVector origin, in JVector direction, out JVector normal, out float lambda) + public virtual bool LocalRayCast(in JVector origin, in JVector direction, out JVector normal, out Real lambda) { return NarrowPhase.RayCast(this, origin, direction, out lambda, out normal); } [ReferenceFrame(ReferenceFrame.World)] - public sealed override bool RayCast(in JVector origin, in JVector direction, out JVector normal, out float lambda) + public sealed override bool RayCast(in JVector origin, in JVector direction, out JVector normal, out Real lambda) { ref var data = ref RigidBody.Data; diff --git a/src/Jitter2/Collision/Shapes/Shape.cs b/src/Jitter2/Collision/Shapes/Shape.cs index 69578b84..c563d367 100644 --- a/src/Jitter2/Collision/Shapes/Shape.cs +++ b/src/Jitter2/Collision/Shapes/Shape.cs @@ -52,25 +52,25 @@ public abstract class Shape : IDynamicTreeProxy, IUpdatableBoundingBox, ISupport int IDynamicTreeProxy.NodePtr { get; set; } - protected void SweptExpandBoundingBox(float dt) + protected void SweptExpandBoundingBox(Real dt) { JVector sweptDirection = dt * Velocity; JBBox box = WorldBoundingBox; - float sxa = MathF.Abs(sweptDirection.X); - float sya = MathF.Abs(sweptDirection.Y); - float sza = MathF.Abs(sweptDirection.Z); + Real sxa = MathR.Abs(sweptDirection.X); + Real sya = MathR.Abs(sweptDirection.Y); + Real sza = MathR.Abs(sweptDirection.Z); - float max = MathF.Max(MathF.Max(sxa, sya), sza); + Real max = MathR.Max(MathR.Max(sxa, sya), sza); - if (sweptDirection.X < 0.0f) box.Min.X -= max; + if (sweptDirection.X < (Real)0.0) box.Min.X -= max; else box.Max.X += max; - if (sweptDirection.Y < 0.0f) box.Min.Y -= max; + if (sweptDirection.Y < (Real)0.0) box.Min.Y -= max; else box.Max.Y += max; - if (sweptDirection.Z < 0.0f) box.Min.Z -= max; + if (sweptDirection.Z < (Real)0.0) box.Min.Z -= max; else box.Max.Z += max; WorldBoundingBox = box; @@ -82,10 +82,10 @@ protected void SweptExpandBoundingBox(float dt) public abstract JVector Velocity { get; } [ReferenceFrame(ReferenceFrame.World)] - public abstract void UpdateWorldBoundingBox(float dt = 0.0f); + public abstract void UpdateWorldBoundingBox(Real dt = (Real)0.0); [ReferenceFrame(ReferenceFrame.World)] - public abstract bool RayCast(in JVector origin, in JVector direction, out JVector normal, out float lambda); + public abstract bool RayCast(in JVector origin, in JVector direction, out JVector normal, out Real lambda); /// [ReferenceFrame(ReferenceFrame.Local)] diff --git a/src/Jitter2/Collision/Shapes/ShapeHelper.cs b/src/Jitter2/Collision/Shapes/ShapeHelper.cs index 1e8d2bf9..3ebbdc68 100644 --- a/src/Jitter2/Collision/Shapes/ShapeHelper.cs +++ b/src/Jitter2/Collision/Shapes/ShapeHelper.cs @@ -31,7 +31,7 @@ namespace Jitter2.Collision.Shapes; /// public static class ShapeHelper { - private const float GoldenRatio = 1.6180339887498948482045f; + private const Real GoldenRatio = (Real)1.6180339887498948482045; private static readonly JVector[] icosahedronVertices = new JVector[12] { @@ -77,7 +77,7 @@ private static void Subdivide(ISupportMappable support, T hullCollection, { JVector n = (p3 - p1) % (p2 - p1); - if (n.LengthSquared() > 1e-16f) + if (n.LengthSquared() > (Real)1e-16) { hullCollection.Add(new JTriangle(p1, p2, p3)); } @@ -85,9 +85,9 @@ private static void Subdivide(ISupportMappable support, T hullCollection, return; } - JVector h1 = (v1 + v2) * 0.5f; - JVector h2 = (v2 + v3) * 0.5f; - JVector h3 = (v3 + v1) * 0.5f; + JVector h1 = (v1 + v2) * (Real)0.5; + JVector h2 = (v2 + v3) * (Real)0.5; + JVector h3 = (v3 + v1) * (Real)0.5; support.SupportMap(h1, out JVector sp1); support.SupportMap(h2, out JVector sp2); @@ -150,13 +150,13 @@ public static void CalculateBoundingBox(ISupportMappable support, /// Output parameter for the calculated center of mass vector. /// Output parameter for the calculated mass. public static void CalculateMassInertia(ISupportMappable support, out JMatrix inertia, out JVector centerOfMass, - out float mass, int subdivisions = 4) + out Real mass, int subdivisions = 4) { centerOfMass = JVector.Zero; inertia = JMatrix.Zero; mass = 0; - const float a = 1.0f / 60.0f, b = 1.0f / 120.0f; + const Real a = (Real)(1.0 / 60.0), b = (Real)(1.0 / 120.0); JMatrix C = new(a, b, b, b, a, b, b, b, a); foreach (JTriangle triangle in MakeHull(support, subdivisions)) @@ -170,14 +170,14 @@ public static void CalculateMassInertia(ISupportMappable support, out JMatrix in column0.Y, column1.Y, column2.Y, column0.Z, column1.Z, column2.Z); - float detA = A.Determinant(); + Real detA = A.Determinant(); // now transform this canonical tetrahedron to the target tetrahedron // inertia by a linear transformation A JMatrix tetrahedronInertia = JMatrix.Multiply(A * C * JMatrix.Transpose(A), detA); - JVector tetrahedronCOM = 1.0f / 4.0f * (column0 + column1 + column2); - float tetrahedronMass = 1.0f / 6.0f * detA; + JVector tetrahedronCOM = (Real)(1.0 / 4.0) * (column0 + column1 + column2); + Real tetrahedronMass = (Real)(1.0 / 6.0) * detA; inertia += tetrahedronInertia; centerOfMass += tetrahedronMass * tetrahedronCOM; @@ -185,6 +185,6 @@ public static void CalculateMassInertia(ISupportMappable support, out JMatrix in } inertia = JMatrix.Multiply(JMatrix.Identity, inertia.Trace()) - inertia; - centerOfMass *= 1.0f / mass; + centerOfMass *= (Real)1.0 / mass; } } \ No newline at end of file diff --git a/src/Jitter2/Collision/Shapes/SphereShape.cs b/src/Jitter2/Collision/Shapes/SphereShape.cs index 4a49f71d..432d0ad0 100644 --- a/src/Jitter2/Collision/Shapes/SphereShape.cs +++ b/src/Jitter2/Collision/Shapes/SphereShape.cs @@ -31,12 +31,12 @@ namespace Jitter2.Collision.Shapes; /// public class SphereShape : RigidBodyShape { - private float radius; + private Real radius; /// /// Gets or sets the radius of the sphere. /// - public float Radius + public Real Radius { get => radius; set @@ -50,8 +50,8 @@ public float Radius /// Initializes a new instance of the class with an optional radius parameter. /// The default radius is 1.0 units. /// - /// The radius of the sphere. Defaults to 1.0f. - public SphereShape(float radius = 1.0f) + /// The radius of the sphere. Defaults to (Real)1.0. + public SphereShape(Real radius = (Real)1.0) { this.radius = radius; UpdateWorldBoundingBox(); @@ -82,41 +82,41 @@ public override void CalculateBoundingBox(in JQuaternion orientation, in JVector JVector.Add(box.Max, position, out box.Max); } - public override bool LocalRayCast(in JVector origin, in JVector direction, out JVector normal, out float lambda) + public override bool LocalRayCast(in JVector origin, in JVector direction, out JVector normal, out Real lambda) { normal = JVector.Zero; - lambda = 0.0f; + lambda = (Real)0.0; - float disq = 1.0f / direction.LengthSquared(); - float p = JVector.Dot(direction, origin) * disq; - float d = p * p - (origin.LengthSquared() - radius * radius) * disq; + Real disq = (Real)1.0 / direction.LengthSquared(); + Real p = JVector.Dot(direction, origin) * disq; + Real d = p * p - (origin.LengthSquared() - radius * radius) * disq; - if (d < 0.0f) return false; + if (d < (Real)0.0) return false; - float sqrtd = MathF.Sqrt(d); + Real sqrtd = MathR.Sqrt(d); - float t0 = -p - sqrtd; - float t1 = -p + sqrtd; + Real t0 = -p - sqrtd; + Real t1 = -p + sqrtd; - if (t0 >= 0.0f) + if (t0 >= (Real)0.0) { lambda = t0; JVector.Normalize(origin + t0 * direction, out normal); return true; } - return t1 > 0.0f; + return t1 > (Real)0.0; } - public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out float mass) + public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out Real mass) { - mass = 4.0f / 3.0f * MathF.PI * radius * radius * radius; + mass = (Real)(4.0 / 3.0) * MathR.PI * radius * radius * radius; // (0,0,0) is the center of mass inertia = JMatrix.Identity; - inertia.M11 = 2.0f / 5.0f * mass * radius * radius; - inertia.M22 = 2.0f / 5.0f * mass * radius * radius; - inertia.M33 = 2.0f / 5.0f * mass * radius * radius; + inertia.M11 = (Real)(2.0 / 5.0) * mass * radius * radius; + inertia.M22 = (Real)(2.0 / 5.0) * mass * radius * radius; + inertia.M33 = (Real)(2.0 / 5.0) * mass * radius * radius; com = JVector.Zero; } diff --git a/src/Jitter2/Collision/Shapes/TransformedShape.cs b/src/Jitter2/Collision/Shapes/TransformedShape.cs index 1a06f9b7..97c76933 100644 --- a/src/Jitter2/Collision/Shapes/TransformedShape.cs +++ b/src/Jitter2/Collision/Shapes/TransformedShape.cs @@ -136,7 +136,7 @@ public override void GetCenter(out JVector point) point = JVector.Transform(point, transformation) + translation; } - public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out float mass) + public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out Real mass) { OriginalShape.CalculateMassInertia(out JMatrix oinertia, out JVector ocom, out mass); diff --git a/src/Jitter2/Collision/Shapes/TriangleMesh.cs b/src/Jitter2/Collision/Shapes/TriangleMesh.cs index e7d35e7d..733de4ec 100644 --- a/src/Jitter2/Collision/Shapes/TriangleMesh.cs +++ b/src/Jitter2/Collision/Shapes/TriangleMesh.cs @@ -194,7 +194,7 @@ int GetEdge(Edge e) JVector normal = (C - A) % (B - A); - if (MathHelper.CloseToZero(normal, 1e-12f)) + if (MathHelper.CloseToZero(normal, (Real)1e-12)) { throw new DegenerateTriangleException("Degenerate triangle found in mesh. Try to clean the " + "mesh in the editor of your choice first."); diff --git a/src/Jitter2/Collision/Shapes/TriangleShape.cs b/src/Jitter2/Collision/Shapes/TriangleShape.cs index b75b6cbe..fc54388f 100644 --- a/src/Jitter2/Collision/Shapes/TriangleShape.cs +++ b/src/Jitter2/Collision/Shapes/TriangleShape.cs @@ -47,7 +47,7 @@ public TriangleShape(TriangleMesh mesh, int index) UpdateWorldBoundingBox(); } - public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out float mass) + public override void CalculateMassInertia(out JMatrix inertia, out JVector com, out Real mass) { // This method is not supported for 2D objects in a 3D world as they have no mass/inertia. throw new NotSupportedException($"{nameof(TriangleShape)} has no mass properties." + @@ -84,7 +84,7 @@ public void GetWorldVertices(out JVector a, out JVector b, out JVector c) public override void CalculateBoundingBox(in JQuaternion orientation, in JVector position, out JBBox box) { - const float extraMargin = 0.01f; + const Real extraMargin = (Real)0.01; ref var triangle = ref Mesh.Indices[Index]; var a = Mesh.Vertices[triangle.IndexA]; @@ -107,7 +107,7 @@ public override void CalculateBoundingBox(in JQuaternion orientation, in JVector box.Max += position + extra; } - public override bool LocalRayCast(in JVector origin, in JVector direction, out JVector normal, out float lambda) + public override bool LocalRayCast(in JVector origin, in JVector direction, out JVector normal, out Real lambda) { ref var triangle = ref Mesh.Indices[Index]; var a = Mesh.Vertices[triangle.IndexA]; @@ -124,7 +124,7 @@ public override void GetCenter(out JVector point) JVector b = Mesh.Vertices[triangle.IndexB]; JVector c = Mesh.Vertices[triangle.IndexC]; - point = 1.0f / 3.0f * (a + b + c); + point = (Real)(1.0 / 3.0) * (a + b + c); } public override void SupportMap(in JVector direction, out JVector result) @@ -135,8 +135,8 @@ public override void SupportMap(in JVector direction, out JVector result) JVector b = Mesh.Vertices[triangle.IndexB]; JVector c = Mesh.Vertices[triangle.IndexC]; - float min = JVector.Dot(a, direction); - float dot = JVector.Dot(b, direction); + Real min = JVector.Dot(a, direction); + Real dot = JVector.Dot(b, direction); result = a; diff --git a/src/Jitter2/Dynamics/Constraints/AngularMotor.cs b/src/Jitter2/Dynamics/Constraints/AngularMotor.cs index ded46996..e301fd95 100644 --- a/src/Jitter2/Dynamics/Constraints/AngularMotor.cs +++ b/src/Jitter2/Dynamics/Constraints/AngularMotor.cs @@ -40,7 +40,7 @@ public struct AngularMotorData { internal int _internal; public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; @@ -48,13 +48,13 @@ public struct AngularMotorData public JVector LocalAxis1; public JVector LocalAxis2; - public float Velocity; - public float MaxForce; - public float MaxLambda; + public Real Velocity; + public Real MaxForce; + public Real MaxLambda; - public float EffectiveMass; + public Real EffectiveMass; - public float AccumulatedImpulse; + public Real AccumulatedImpulse; } private JHandle handle; @@ -93,7 +93,7 @@ public void Initialize(JVector axis) Initialize(axis, axis); } - public float TargetVelocity + public Real TargetVelocity { get => handle.Data.Velocity; set => handle.Data.Velocity = value; @@ -103,12 +103,12 @@ public float TargetVelocity public JVector LocalAxis2 => handle.Data.LocalAxis2; - public float MaximumForce + public Real MaximumForce { get => handle.Data.MaxForce; set { - if (value < 0.0f) + if (value < (Real)0.0) { throw new ArgumentException("Maximum force must not be negative."); } @@ -117,7 +117,7 @@ public float MaximumForce } } - public static void PrepareForIteration(ref ConstraintData constraint, float idt) + public static void PrepareForIteration(ref ConstraintData constraint, Real idt) { ref AngularMotorData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); @@ -129,15 +129,15 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) data.EffectiveMass = JVector.Transform(j1, body1.InverseInertiaWorld) * j1 + JVector.Transform(j2, body2.InverseInertiaWorld) * j2; - data.EffectiveMass = 1.0f / data.EffectiveMass; + data.EffectiveMass = (Real)1.0 / data.EffectiveMass; - data.MaxLambda = 1.0f / idt * data.MaxForce; + data.MaxLambda = (Real)1.0 / idt * data.MaxForce; body1.AngularVelocity -= JVector.Transform(j1 * data.AccumulatedImpulse, body1.InverseInertiaWorld); body2.AngularVelocity += JVector.Transform(j2 * data.AccumulatedImpulse, body2.InverseInertiaWorld); } - public static void Iterate(ref ConstraintData constraint, float idt) + public static void Iterate(ref ConstraintData constraint, Real idt) { ref AngularMotorData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref constraint.Body1.Data; @@ -146,11 +146,11 @@ public static void Iterate(ref ConstraintData constraint, float idt) JVector.Transform(data.LocalAxis1, body1.Orientation, out JVector j1); JVector.Transform(data.LocalAxis2, body2.Orientation, out JVector j2); - float jv = -j1 * body1.AngularVelocity + j2 * body2.AngularVelocity; + Real jv = -j1 * body1.AngularVelocity + j2 * body2.AngularVelocity; - float lambda = -(jv - data.Velocity) * data.EffectiveMass; + Real lambda = -(jv - data.Velocity) * data.EffectiveMass; - float olda = data.AccumulatedImpulse; + Real olda = data.AccumulatedImpulse; data.AccumulatedImpulse += lambda; diff --git a/src/Jitter2/Dynamics/Constraints/BallSocket.cs b/src/Jitter2/Dynamics/Constraints/BallSocket.cs index 1f07664a..84315ac2 100644 --- a/src/Jitter2/Dynamics/Constraints/BallSocket.cs +++ b/src/Jitter2/Dynamics/Constraints/BallSocket.cs @@ -42,7 +42,7 @@ public struct BallSocketData internal int _internal; public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; @@ -54,8 +54,8 @@ public struct BallSocketData public JVector R1; public JVector R2; - public float BiasFactor; - public float Softness; + public Real BiasFactor; + public Real Softness; public JMatrix EffectiveMass; public JVector AccumulatedImpulse; @@ -89,11 +89,11 @@ public void Initialize(JVector anchor) JVector.ConjugatedTransform(data.LocalAnchor1, body1.Orientation, out data.LocalAnchor1); JVector.ConjugatedTransform(data.LocalAnchor2, body2.Orientation, out data.LocalAnchor2); - data.BiasFactor = 0.2f; - data.Softness = 0.00f; + data.BiasFactor = (Real)0.2; + data.Softness = (Real)0.0; } - public static void PrepareForIteration(ref ConstraintData constraint, float idt) + public static void PrepareForIteration(ref ConstraintData constraint, Real idt) { ref BallSocketData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref data.Body1.Data; @@ -113,7 +113,7 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) body2.InverseMass * JMatrix.Identity + JMatrix.Multiply(cr2, JMatrix.MultiplyTransposed(body2.InverseInertiaWorld, cr2)); - float softness = data.Softness * idt; + Real softness = data.Softness * idt; data.EffectiveMass.M11 += softness; data.EffectiveMass.M22 += softness; @@ -132,13 +132,13 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) body2.AngularVelocity += JVector.Transform(JVector.Transform(acc, cr2), body2.InverseInertiaWorld); } - public float Softness + public Real Softness { get => handle.Data.Softness; set => handle.Data.Softness = value; } - public float Bias + public Real Bias { get => handle.Data.BiasFactor; set => handle.Data.BiasFactor = value; @@ -146,7 +146,7 @@ public float Bias public JVector Impulse => handle.Data.AccumulatedImpulse; - public static void Iterate(ref ConstraintData constraint, float idt) + public static void Iterate(ref ConstraintData constraint, Real idt) { ref BallSocketData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref constraint.Body1.Data; @@ -160,7 +160,7 @@ public static void Iterate(ref ConstraintData constraint, float idt) JVector jv = -body1.Velocity + JVector.Transform(body1.AngularVelocity, cr1) + body2.Velocity - JVector.Transform(body2.AngularVelocity, cr2); - JVector lambda = -1.0f * JVector.Transform(jv + data.Bias + softnessVector, data.EffectiveMass); + JVector lambda = -(Real)1.0 * JVector.Transform(jv + data.Bias + softnessVector, data.EffectiveMass); data.AccumulatedImpulse += lambda; diff --git a/src/Jitter2/Dynamics/Constraints/ConeLimit.cs b/src/Jitter2/Dynamics/Constraints/ConeLimit.cs index de566e9c..5a9ec27d 100644 --- a/src/Jitter2/Dynamics/Constraints/ConeLimit.cs +++ b/src/Jitter2/Dynamics/Constraints/ConeLimit.cs @@ -41,26 +41,26 @@ public struct ConeLimitData { internal int _internal; public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; public JVector LocalAxis1, LocalAxis2; - public float BiasFactor; - public float Softness; + public Real BiasFactor; + public Real Softness; - public float EffectiveMass; - public float AccumulatedImpulse; - public float Bias; + public Real EffectiveMass; + public Real AccumulatedImpulse; + public Real Bias; - public float LimitLow; - public float LimitHigh; + public Real LimitLow; + public Real LimitHigh; public short Clamp; - public MemoryHelper.MemBlock48 J0; + public MemoryHelper.MemBlock6Real J0; } private JHandle handle; @@ -88,14 +88,14 @@ public void Initialize(JVector axis, AngularLimit limit) JVector.ConjugatedTransform(axis, body1.Orientation, out data.LocalAxis1); JVector.ConjugatedTransform(axis, body2.Orientation, out data.LocalAxis2); - data.Softness = 0.001f; - data.BiasFactor = 0.2f; + data.Softness = (Real)0.001; + data.BiasFactor = (Real)0.2; - float lower = (float)limit.From; - float upper = (float)limit.To; + Real lower = (Real)limit.From; + Real upper = (Real)limit.To; - data.LimitLow = MathF.Cos(lower); - data.LimitHigh = MathF.Cos(upper); + data.LimitLow = MathR.Cos(lower); + data.LimitHigh = MathR.Cos(upper); } public JAngle Angle @@ -110,11 +110,11 @@ public JAngle Angle JVector.Transform(data.LocalAxis1, body1.Orientation, out JVector a1); JVector.Transform(data.LocalAxis2, body2.Orientation, out JVector a2); - return (JAngle)MathF.Acos(JVector.Dot(a1, a2)); + return (JAngle)MathR.Acos(JVector.Dot(a1, a2)); } } - public static void PrepareForIteration(ref ConstraintData constraint, float idt) + public static void PrepareForIteration(ref ConstraintData constraint, Real idt) { ref ConeLimitData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); @@ -131,7 +131,7 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) data.Clamp = 0; - float error = JVector.Dot(a1, a2); + Real error = JVector.Dot(a1, a2); if (error < data.LimitHigh) { @@ -145,7 +145,7 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) } else { - data.AccumulatedImpulse = 0.0f; + data.AccumulatedImpulse = (Real)0.0; return; } @@ -154,7 +154,7 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) data.EffectiveMass += data.Softness * idt; - data.EffectiveMass = 1.0f / data.EffectiveMass; + data.EffectiveMass = (Real)1.0 / data.EffectiveMass; data.Bias = -error * data.BiasFactor * idt; @@ -165,21 +165,21 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) JVector.Transform(data.AccumulatedImpulse * jacobian[1], body2.InverseInertiaWorld); } - public float Softness + public Real Softness { get => handle.Data.Softness; set => handle.Data.Softness = value; } - public float Bias + public Real Bias { get => handle.Data.BiasFactor; set => handle.Data.BiasFactor = value; } - public float Impulse => handle.Data.AccumulatedImpulse; + public Real Impulse => handle.Data.AccumulatedImpulse; - public static void Iterate(ref ConstraintData constraint, float idt) + public static void Iterate(ref ConstraintData constraint, Real idt) { ref ConeLimitData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref constraint.Body1.Data; @@ -189,25 +189,25 @@ public static void Iterate(ref ConstraintData constraint, float idt) var jacobian = new Span(Unsafe.AsPointer(ref data.J0), 2); - float jv = + Real jv = body1.AngularVelocity * jacobian[0] + body2.AngularVelocity * jacobian[1]; - float softnessScalar = data.AccumulatedImpulse * data.Softness * idt; + Real softnessScalar = data.AccumulatedImpulse * data.Softness * idt; - float lambda = -data.EffectiveMass * (jv + data.Bias + softnessScalar); + Real lambda = -data.EffectiveMass * (jv + data.Bias + softnessScalar); - float oldacc = data.AccumulatedImpulse; + Real oldacc = data.AccumulatedImpulse; data.AccumulatedImpulse += lambda; if (data.Clamp == 1) { - data.AccumulatedImpulse = MathF.Min(data.AccumulatedImpulse, 0.0f); + data.AccumulatedImpulse = MathR.Min(data.AccumulatedImpulse, (Real)0.0); } else { - data.AccumulatedImpulse = MathF.Max(data.AccumulatedImpulse, 0.0f); + data.AccumulatedImpulse = MathR.Max(data.AccumulatedImpulse, (Real)0.0); } lambda = data.AccumulatedImpulse - oldacc; diff --git a/src/Jitter2/Dynamics/Constraints/Constraint.cs b/src/Jitter2/Dynamics/Constraints/Constraint.cs index 5c9b478a..73d08b1e 100644 --- a/src/Jitter2/Dynamics/Constraints/Constraint.cs +++ b/src/Jitter2/Dynamics/Constraints/Constraint.cs @@ -30,11 +30,11 @@ namespace Jitter2.Dynamics.Constraints; [StructLayout(LayoutKind.Sequential, Size = ConstraintSize)] public unsafe struct SmallConstraintData { - public const int ConstraintSize = 128; + public const int ConstraintSize = Jitter2.Precision.ConstraintSizeSmall; internal int _internal; - public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* Iterate; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; @@ -43,11 +43,11 @@ public unsafe struct SmallConstraintData [StructLayout(LayoutKind.Sequential, Size = ConstraintSize)] public unsafe struct ConstraintData { - public const int ConstraintSize = 256; + public const int ConstraintSize = Jitter2.Precision.ConstraintSizeFull; internal int _internal; - public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* Iterate; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; @@ -82,8 +82,8 @@ internal Constraint() { } - protected unsafe delegate* iterate = null; - protected unsafe delegate* prepareForIteration = null; + protected unsafe delegate* iterate = null; + protected unsafe delegate* prepareForIteration = null; /// /// Enables or disables this constraint temporarily. For a complete removal of the constraint, diff --git a/src/Jitter2/Dynamics/Constraints/DistanceLimit.cs b/src/Jitter2/Dynamics/Constraints/DistanceLimit.cs index 73954a9c..0333fab0 100644 --- a/src/Jitter2/Dynamics/Constraints/DistanceLimit.cs +++ b/src/Jitter2/Dynamics/Constraints/DistanceLimit.cs @@ -42,7 +42,7 @@ public struct DistanceLimitData { internal int _internal; public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; @@ -50,18 +50,19 @@ public struct DistanceLimitData public JVector LocalAnchor1; public JVector LocalAnchor2; - public float BiasFactor; - public float Softness; - public float Distance; + public Real BiasFactor; + public Real Softness; + public Real Distance; - public float LimitMin; - public float LimitMax; + public Real LimitMin; + public Real LimitMax; - public float EffectiveMass; - public float AccumulatedImpulse; - public float Bias; + public Real EffectiveMass; + public Real AccumulatedImpulse; + public Real Bias; - public MemoryHelper.MemBlock48 J0; + + public MemoryHelper.MemBlock12Real J0; public short Clamp; } @@ -99,8 +100,8 @@ public void Initialize(JVector anchor1, JVector anchor2, LinearLimit limit) JVector.ConjugatedTransform(data.LocalAnchor1, body1.Orientation, out data.LocalAnchor1); JVector.ConjugatedTransform(data.LocalAnchor2, body2.Orientation, out data.LocalAnchor2); - data.Softness = 0.001f; - data.BiasFactor = 0.2f; + data.Softness = (Real)0.001; + data.BiasFactor = (Real)0.2; data.Distance = (anchor2 - anchor1).Length(); (data.LimitMin, data.LimitMax) = limit; @@ -144,7 +145,7 @@ public JVector Anchor2 } } - public float TargetDistance + public Real TargetDistance { set { @@ -154,7 +155,7 @@ public float TargetDistance get => handle.Data.Distance; } - public float Distance + public Real Distance { get { @@ -174,7 +175,7 @@ public float Distance } } - public static void PrepareForIteration(ref ConstraintData constraint, float idt) + public static void PrepareForIteration(ref ConstraintData constraint, Real idt) { ref DistanceLimitData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref data.Body1.Data; @@ -188,7 +189,7 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) JVector.Subtract(p2, p1, out JVector dp); - float error = dp.Length() - data.Distance; + Real error = dp.Length() - data.Distance; data.Clamp = 0; @@ -204,18 +205,18 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) } else { - data.AccumulatedImpulse = 0.0f; + data.AccumulatedImpulse = (Real)0.0; return; } JVector n = p2 - p1; - if (n.LengthSquared() != 0.0f) n.Normalize(); + if (n.LengthSquared() != (Real)0.0) n.Normalize(); var jacobian = new Span(Unsafe.AsPointer(ref data.J0), 4); - jacobian[0] = -1.0f * n; - jacobian[1] = -1.0f * (r1 % n); - jacobian[2] = 1.0f * n; + jacobian[0] = -(Real)1.0 * n; + jacobian[1] = -(Real)1.0 * (r1 % n); + jacobian[2] = (Real)1.0 * n; jacobian[3] = r2 % n; data.EffectiveMass = body1.InverseMass + @@ -225,7 +226,7 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) data.EffectiveMass += data.Softness * idt; - data.EffectiveMass = 1.0f / data.EffectiveMass; + data.EffectiveMass = (Real)1.0 / data.EffectiveMass; data.Bias = error * data.BiasFactor * idt; @@ -236,21 +237,21 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) body2.AngularVelocity += JVector.Transform(data.AccumulatedImpulse * jacobian[3], body2.InverseInertiaWorld); } - public float Softness + public Real Softness { get => handle.Data.Softness; set => handle.Data.Softness = value; } - public float Bias + public Real Bias { get => handle.Data.BiasFactor; set => handle.Data.BiasFactor = value; } - public float Impulse => handle.Data.AccumulatedImpulse; + public Real Impulse => handle.Data.AccumulatedImpulse; - public static void Iterate(ref ConstraintData constraint, float idt) + public static void Iterate(ref ConstraintData constraint, Real idt) { ref DistanceLimitData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref constraint.Body1.Data; @@ -260,27 +261,27 @@ public static void Iterate(ref ConstraintData constraint, float idt) var jacobian = new Span(Unsafe.AsPointer(ref data.J0), 4); - float jv = + Real jv = body1.Velocity * jacobian[0] + body1.AngularVelocity * jacobian[1] + body2.Velocity * jacobian[2] + body2.AngularVelocity * jacobian[3]; - float softnessScalar = data.AccumulatedImpulse * data.Softness * idt; + Real softnessScalar = data.AccumulatedImpulse * data.Softness * idt; - float lambda = -data.EffectiveMass * (jv + data.Bias + softnessScalar); + Real lambda = -data.EffectiveMass * (jv + data.Bias + softnessScalar); - float oldacc = data.AccumulatedImpulse; + Real oldacc = data.AccumulatedImpulse; data.AccumulatedImpulse += lambda; if (data.Clamp == 1) { - data.AccumulatedImpulse = MathF.Min(data.AccumulatedImpulse, 0.0f); + data.AccumulatedImpulse = MathR.Min(data.AccumulatedImpulse, (Real)0.0); } else { - data.AccumulatedImpulse = MathF.Max(data.AccumulatedImpulse, 0.0f); + data.AccumulatedImpulse = MathR.Max(data.AccumulatedImpulse, (Real)0.0); } lambda = data.AccumulatedImpulse - oldacc; diff --git a/src/Jitter2/Dynamics/Constraints/FixedAngle.cs b/src/Jitter2/Dynamics/Constraints/FixedAngle.cs index 0964d7e4..dee18072 100644 --- a/src/Jitter2/Dynamics/Constraints/FixedAngle.cs +++ b/src/Jitter2/Dynamics/Constraints/FixedAngle.cs @@ -39,16 +39,16 @@ public struct FixedAngleData { internal int _internal; public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; - public float MinAngle; - public float MaxAngle; + public Real MinAngle; + public Real MaxAngle; - public float BiasFactor; - public float Softness; + public Real BiasFactor; + public Real Softness; public JVector Axis; public JQuaternion Q0; @@ -78,8 +78,8 @@ public void Initialize() ref RigidBodyData body1 = ref data.Body1.Data; ref RigidBodyData body2 = ref data.Body2.Data; - data.Softness = 0.001f; - data.BiasFactor = 0.2f; + data.Softness = (Real)0.001; + data.BiasFactor = (Real)0.2; JQuaternion q1 = body1.Orientation; JQuaternion q2 = body2.Orientation; @@ -87,7 +87,7 @@ public void Initialize() data.Q0 = q2.Conjugate() * q1; } - public static void PrepareForIteration(ref ConstraintData constraint, float idt) + public static void PrepareForIteration(ref ConstraintData constraint, Real idt) { ref FixedAngleData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); @@ -105,10 +105,10 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) data.Jacobian = QMatrix.ProjectMultiplyLeftRight(data.Q0 * q1.Conjugate(), q2); - if (quat0.W < 0.0f) + if (quat0.W < (Real)0.0) { - error *= -1.0f; - data.Jacobian *= -1.0f; + error *= -(Real)1.0; + data.Jacobian *= -(Real)1.0; } data.EffectiveMass = JMatrix.Multiply(data.Jacobian, JMatrix.MultiplyTransposed(body1.InverseInertiaWorld + body2.InverseInertiaWorld, data.Jacobian)); @@ -125,13 +125,13 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) body2.AngularVelocity -= JVector.Transform(JVector.TransposedTransform(data.AccumulatedImpulse, data.Jacobian), body2.InverseInertiaWorld); } - public float Softness + public Real Softness { get => handle.Data.Softness; set => handle.Data.Softness = value; } - public float Bias + public Real Bias { get => handle.Data.BiasFactor; set => handle.Data.BiasFactor = value; @@ -139,7 +139,7 @@ public float Bias public JVector Impulse => handle.Data.AccumulatedImpulse; - public static void Iterate(ref ConstraintData constraint, float idt) + public static void Iterate(ref ConstraintData constraint, Real idt) { ref FixedAngleData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref constraint.Body1.Data; @@ -147,7 +147,7 @@ public static void Iterate(ref ConstraintData constraint, float idt) JVector jv = JVector.Transform(body1.AngularVelocity - body2.AngularVelocity, data.Jacobian); JVector softness = data.AccumulatedImpulse * (data.Softness * idt); - JVector lambda = -1.0f * JVector.Transform(jv + data.Bias + softness, data.EffectiveMass); + JVector lambda = -(Real)1.0 * JVector.Transform(jv + data.Bias + softness, data.EffectiveMass); data.AccumulatedImpulse += lambda; diff --git a/src/Jitter2/Dynamics/Constraints/HingeAngle.cs b/src/Jitter2/Dynamics/Constraints/HingeAngle.cs index f2094cc3..95eb5c47 100644 --- a/src/Jitter2/Dynamics/Constraints/HingeAngle.cs +++ b/src/Jitter2/Dynamics/Constraints/HingeAngle.cs @@ -40,19 +40,19 @@ public struct HingeAngleData { internal int _internal; public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; - public float MinAngle; - public float MaxAngle; + public Real MinAngle; + public Real MaxAngle; - public float BiasFactor; - public float LimitBias; + public Real BiasFactor; + public Real LimitBias; - public float LimitSoftness; - public float Softness; + public Real LimitSoftness; + public Real Softness; public JVector Axis; public JQuaternion Q0; @@ -86,13 +86,13 @@ public void Initialize(JVector axis, AngularLimit limit) ref RigidBodyData body1 = ref data.Body1.Data; ref RigidBodyData body2 = ref data.Body2.Data; - data.Softness = 0.001f; - data.LimitSoftness = 0.001f; - data.BiasFactor = 0.2f; - data.LimitBias = 0.1f; + data.Softness = (Real)0.001; + data.LimitSoftness = (Real)0.001; + data.BiasFactor = (Real)0.2; + data.LimitBias = (Real)0.1; - data.MinAngle = MathF.Sin((float)limit.From / 2.0f); - data.MaxAngle = MathF.Sin((float)limit.To / 2.0f); + data.MinAngle = MathR.Sin((Real)limit.From / (Real)2.0); + data.MaxAngle = MathR.Sin((Real)limit.To / (Real)2.0); data.Axis = JVector.TransposedTransform(axis, body2.Orientation); @@ -107,12 +107,12 @@ public AngularLimit Limit set { ref HingeAngleData data = ref handle.Data; - data.MinAngle = MathF.Sin((float)value.From / 2.0f); - data.MaxAngle = MathF.Sin((float)value.To / 2.0f); + data.MinAngle = MathR.Sin((Real)value.From / (Real)2.0); + data.MaxAngle = MathR.Sin((Real)value.To / (Real)2.0); } } - public static void PrepareForIteration(ref ConstraintData constraint, float idt) + public static void PrepareForIteration(ref ConstraintData constraint, Real idt) { ref HingeAngleData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); @@ -134,12 +134,12 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) data.Clamp = 0; - JMatrix m0 = (-1.0f / 2.0f) * QMatrix.ProjectMultiplyLeftRight(data.Q0 * q1.Conjugate(), q2); + JMatrix m0 = (-(Real)(1.0 / 2.0)) * QMatrix.ProjectMultiplyLeftRight(data.Q0 * q1.Conjugate(), q2); - if (quat0.W < 0.0f) + if (quat0.W < (Real)0.0) { - error *= -1.0f; - m0 *= -1.0f; + error *= -(Real)1.0; + m0 *= -(Real)1.0; } data.Jacobian.UnsafeGet(0) = JVector.TransposedTransform(p0, m0); @@ -152,8 +152,8 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) data.EffectiveMass.M22 += data.Softness * idt; data.EffectiveMass.M33 += data.LimitSoftness * idt; - float maxa = data.MaxAngle; - float mina = data.MinAngle; + Real maxa = data.MaxAngle; + Real mina = data.MinAngle; if (error.Z > maxa) { @@ -198,35 +198,35 @@ public JAngle Angle JQuaternion quat0 = data.Q0 * q1.Conjugate() * q2; - if (quat0.W < 0.0f) + if (quat0.W < (Real)0.0) { - quat0 *= -1.0f; + quat0 *= -(Real)1.0; } - float error = JVector.Dot(data.Axis, new JVector(quat0.X, quat0.Y, quat0.Z)); - return (JAngle)(2.0f * MathF.Asin(error)); + Real error = JVector.Dot(data.Axis, new JVector(quat0.X, quat0.Y, quat0.Z)); + return (JAngle)((Real)2.0 * MathR.Asin(error)); } } - public float Softness + public Real Softness { get => handle.Data.Softness; set => handle.Data.Softness = value; } - public float LimitSoftness + public Real LimitSoftness { get => handle.Data.LimitSoftness; set => handle.Data.LimitSoftness = value; } - public float Bias + public Real Bias { get => handle.Data.BiasFactor; set => handle.Data.BiasFactor = value; } - public float LimitBias + public Real LimitBias { get => handle.Data.LimitBias; set => handle.Data.LimitBias = value; @@ -234,7 +234,7 @@ public float LimitBias public JVector Impulse => handle.Data.AccumulatedImpulse; - public static void Iterate(ref ConstraintData constraint, float idt) + public static void Iterate(ref ConstraintData constraint, Real idt) { ref HingeAngleData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref constraint.Body1.Data; @@ -247,7 +247,7 @@ public static void Iterate(ref ConstraintData constraint, float idt) softness.Y *= data.Softness; softness.Z *= data.LimitSoftness; - JVector lambda = -1.0f * JVector.Transform(jv + data.Bias + softness, data.EffectiveMass); + JVector lambda = -(Real)1.0 * JVector.Transform(jv + data.Bias + softness, data.EffectiveMass); JVector origAcc = data.AccumulatedImpulse; @@ -255,11 +255,11 @@ public static void Iterate(ref ConstraintData constraint, float idt) if (data.Clamp == 1) { - data.AccumulatedImpulse.Z = MathF.Min(0, data.AccumulatedImpulse.Z); + data.AccumulatedImpulse.Z = MathR.Min(0, data.AccumulatedImpulse.Z); } else if (data.Clamp == 2) { - data.AccumulatedImpulse.Z = MathF.Max(0, data.AccumulatedImpulse.Z); + data.AccumulatedImpulse.Z = MathR.Max(0, data.AccumulatedImpulse.Z); } else { diff --git a/src/Jitter2/Dynamics/Constraints/Internal/QMatrix.cs b/src/Jitter2/Dynamics/Constraints/Internal/QMatrix.cs index 78d818b0..8a12323b 100644 --- a/src/Jitter2/Dynamics/Constraints/Internal/QMatrix.cs +++ b/src/Jitter2/Dynamics/Constraints/Internal/QMatrix.cs @@ -31,20 +31,20 @@ namespace Jitter2.Dynamics.Constraints; internal unsafe struct QMatrix { - private MemoryHelper.MemBlock64 mem; + private MemoryHelper.MemBlock16Real mem; - public float* Pointer => (float*)Unsafe.AsPointer(ref mem); + public Real* Pointer => (Real*)Unsafe.AsPointer(ref mem); - private static QMatrix Multiply(float* left, float* right) + private static QMatrix Multiply(Real* left, Real* right) { Unsafe.SkipInit(out QMatrix res); - float* result = res.Pointer; + Real* result = res.Pointer; for (int c = 0; c < 4; c++) { for (int r = 0; r < 4; r++) { - float* tt = &result[4 * c + r]; + Real* tt = &result[4 * c + r]; *tt = 0; for (int k = 0; k < 4; k++) { @@ -56,26 +56,9 @@ private static QMatrix Multiply(float* left, float* right) return res; } - public static JMatrix ProjectMultiplyLeftRight(in JQuaternion left, in JQuaternion right) - { - Unsafe.SkipInit(out JMatrix res); - - res.M11 = -left.X * right.X + left.W * right.W + left.Z * right.Z + left.Y * right.Y; - res.M12 = -left.X * right.Y + left.W * right.Z - left.Z * right.W - left.Y * right.X; - res.M13 = -left.X * right.Z - left.W * right.Y - left.Z * right.X + left.Y * right.W; - res.M21 = -left.Y * right.X + left.Z * right.W - left.W * right.Z - left.X * right.Y; - res.M22 = -left.Y * right.Y + left.Z * right.Z + left.W * right.W + left.X * right.X; - res.M23 = -left.Y * right.Z - left.Z * right.Y + left.W * right.X - left.X * right.W; - res.M31 = -left.Z * right.X - left.Y * right.W - left.X * right.Z + left.W * right.Y; - res.M32 = -left.Z * right.Y - left.Y * right.Z + left.X * right.W - left.W * right.X; - res.M33 = -left.Z * right.Z + left.Y * right.Y + left.X * right.X + left.W * right.W; - - return res; - } - public JMatrix Projection() { - float* m = Pointer; + Real* m = Pointer; return new JMatrix(m[0x5], m[0x9], m[0xD], m[0x6], m[0xA], m[0xE], @@ -85,7 +68,7 @@ public JMatrix Projection() public static QMatrix CreateLM(in JQuaternion quat) { Unsafe.SkipInit(out QMatrix result); - float* q = result.Pointer; + Real* q = result.Pointer; q[0x0] = +quat.W; q[0x4] = -quat.X; @@ -110,7 +93,7 @@ public static QMatrix CreateLM(in JQuaternion quat) public static QMatrix CreateRM(in JQuaternion quat) { Unsafe.SkipInit(out QMatrix result); - float* q = result.Pointer; + Real* q = result.Pointer; q[0x0] = +quat.W; q[0x4] = -quat.X; @@ -138,8 +121,25 @@ public static QMatrix Multiply(ref QMatrix left, ref QMatrix right) { fixed (QMatrix* rptr = &right) { - return Multiply((float*)lptr, (float*)rptr); + return Multiply((Real*)lptr, (Real*)rptr); } } } + + public static JMatrix ProjectMultiplyLeftRight(in JQuaternion left, in JQuaternion right) + { + Unsafe.SkipInit(out JMatrix res); + + res.M11 = -left.X * right.X + left.W * right.W + left.Z * right.Z + left.Y * right.Y; + res.M12 = -left.X * right.Y + left.W * right.Z - left.Z * right.W - left.Y * right.X; + res.M13 = -left.X * right.Z - left.W * right.Y - left.Z * right.X + left.Y * right.W; + res.M21 = -left.Y * right.X + left.Z * right.W - left.W * right.Z - left.X * right.Y; + res.M22 = -left.Y * right.Y + left.Z * right.Z + left.W * right.W + left.X * right.X; + res.M23 = -left.Y * right.Z - left.Z * right.Y + left.W * right.X - left.X * right.W; + res.M31 = -left.Z * right.X - left.Y * right.W - left.X * right.Z + left.W * right.Y; + res.M32 = -left.Z * right.Y - left.Y * right.Z + left.X * right.W - left.W * right.X; + res.M33 = -left.Z * right.Z + left.Y * right.Y + left.X * right.X + left.W * right.W; + + return res; + } } \ No newline at end of file diff --git a/src/Jitter2/Dynamics/Constraints/Limit.cs b/src/Jitter2/Dynamics/Constraints/Limit.cs index c2672d9d..29b2a7f9 100644 --- a/src/Jitter2/Dynamics/Constraints/Limit.cs +++ b/src/Jitter2/Dynamics/Constraints/Limit.cs @@ -32,12 +32,12 @@ public struct AngularLimit public JAngle To { get; set; } public static readonly AngularLimit Full = - new(JAngle.FromRadiant(-MathF.PI), JAngle.FromRadiant(MathF.PI)); + new(JAngle.FromRadiant(-MathR.PI), JAngle.FromRadiant(MathR.PI)); public static readonly AngularLimit Fixed = - new(JAngle.FromRadiant(+1e-6f), JAngle.FromRadiant(-1e-6f)); + new(JAngle.FromRadiant(+(Real)1e-6), JAngle.FromRadiant(-(Real)1e-6)); - public static AngularLimit FromDegree(float min, float max) + public static AngularLimit FromDegree(Real min, Real max) { return new AngularLimit(JAngle.FromDegree(min), JAngle.FromDegree(max)); } @@ -57,27 +57,27 @@ public readonly void Deconstruct(out JAngle limitMin, out JAngle limitMax) public struct LinearLimit { - public float From { get; set; } - public float To { get; set; } + public Real From { get; set; } + public Real To { get; set; } public static readonly LinearLimit Full = - new(float.NegativeInfinity, float.PositiveInfinity); + new(Real.NegativeInfinity, Real.PositiveInfinity); public static readonly LinearLimit Fixed = - new(1e-6f, -1e-6f); + new((Real)1e-6, -(Real)1e-6); - public LinearLimit(float from, float to) + public LinearLimit(Real from, Real to) { From = from; To = to; } - public static LinearLimit FromMinMax(float min, float max) + public static LinearLimit FromMinMax(Real min, Real max) { return new LinearLimit(min, max); } - public readonly void Deconstruct(out float limitMin, out float limitMax) + public readonly void Deconstruct(out Real limitMin, out Real limitMax) { limitMin = From; limitMax = To; diff --git a/src/Jitter2/Dynamics/Constraints/LinearMotor.cs b/src/Jitter2/Dynamics/Constraints/LinearMotor.cs index f55e657d..26b6409a 100644 --- a/src/Jitter2/Dynamics/Constraints/LinearMotor.cs +++ b/src/Jitter2/Dynamics/Constraints/LinearMotor.cs @@ -41,7 +41,7 @@ public struct LinearMotorData { internal int _internal; public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; @@ -49,13 +49,13 @@ public struct LinearMotorData public JVector LocalAxis1; public JVector LocalAxis2; - public float Velocity; - public float MaxForce; - public float MaxLambda; + public Real Velocity; + public Real MaxForce; + public Real MaxLambda; - public float EffectiveMass; + public Real EffectiveMass; - public float AccumulatedImpulse; + public Real AccumulatedImpulse; } private JHandle handle; @@ -101,18 +101,18 @@ public void Initialize(JVector axis1, JVector axis2) data.Velocity = 0; } - public float TargetVelocity + public Real TargetVelocity { get => handle.Data.Velocity; set => handle.Data.Velocity = value; } - public float MaximumForce + public Real MaximumForce { get => handle.Data.MaxForce; set { - if (value < 0.0f) + if (value < (Real)0.0) { throw new ArgumentException("Maximum force must not be negative."); } @@ -121,9 +121,9 @@ public float MaximumForce } } - public float Impulse => handle.Data.AccumulatedImpulse; + public Real Impulse => handle.Data.AccumulatedImpulse; - public static void PrepareForIteration(ref ConstraintData constraint, float idt) + public static void PrepareForIteration(ref ConstraintData constraint, Real idt) { ref LinearMotorData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); @@ -134,8 +134,8 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) JVector.Transform(data.LocalAxis2, body2.Orientation, out JVector j2); data.EffectiveMass = body1.InverseMass + body2.InverseMass; - data.EffectiveMass = 1.0f / data.EffectiveMass; - data.MaxLambda = (1.0f / idt) * data.MaxForce; + data.EffectiveMass = (Real)1.0 / data.EffectiveMass; + data.MaxLambda = ((Real)1.0 / idt) * data.MaxForce; body1.Velocity -= j1 * data.AccumulatedImpulse * body1.InverseMass; body2.Velocity += j2 * data.AccumulatedImpulse * body2.InverseMass; @@ -149,7 +149,7 @@ public override void DebugDraw(IDebugDrawer drawer) ref RigidBodyData body2 = ref data.Body2.Data; } - public static void Iterate(ref ConstraintData constraint, float idt) + public static void Iterate(ref ConstraintData constraint, Real idt) { ref LinearMotorData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref constraint.Body1.Data; @@ -158,11 +158,11 @@ public static void Iterate(ref ConstraintData constraint, float idt) JVector.Transform(data.LocalAxis1, body1.Orientation, out JVector j1); JVector.Transform(data.LocalAxis2, body2.Orientation, out JVector j2); - float jv = -j1 * body1.Velocity + j2 * body2.Velocity; + Real jv = -j1 * body1.Velocity + j2 * body2.Velocity; - float lambda = -(jv - data.Velocity) * data.EffectiveMass; + Real lambda = -(jv - data.Velocity) * data.EffectiveMass; - float olda = data.AccumulatedImpulse; + Real olda = data.AccumulatedImpulse; data.AccumulatedImpulse += lambda; diff --git a/src/Jitter2/Dynamics/Constraints/PointOnLine.cs b/src/Jitter2/Dynamics/Constraints/PointOnLine.cs index 2e2a04ac..451036e3 100644 --- a/src/Jitter2/Dynamics/Constraints/PointOnLine.cs +++ b/src/Jitter2/Dynamics/Constraints/PointOnLine.cs @@ -43,7 +43,7 @@ public struct PointOnLineData internal int _internal; public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; @@ -53,17 +53,17 @@ public struct PointOnLineData public JVector LocalAnchor1; public JVector LocalAnchor2; - public float BiasFactor; - public float LimitBias; - public float Softness; - public float LimitSoftness; + public Real BiasFactor; + public Real LimitBias; + public Real Softness; + public Real LimitSoftness; public JMatrix EffectiveMass; public JVector AccumulatedImpulse; public JVector Bias; - public float Min; - public float Max; + public Real Min; + public Real Max; public ushort Clamp; @@ -109,15 +109,15 @@ public void Initialize(JVector axis, JVector anchor1, JVector anchor2, LinearLim JVector.ConjugatedTransform(axis, body1.Orientation, out data.LocalAxis); - data.BiasFactor = 0.01f; - data.Softness = 0.00001f; - data.LimitSoftness = 0.0001f; - data.LimitBias = 0.2f; + data.BiasFactor = (Real)0.01; + data.Softness = (Real)0.00001; + data.LimitSoftness = (Real)0.0001; + data.LimitBias = (Real)0.2; (data.Min, data.Max) = limit; } - public float Distance + public Real Distance { get { @@ -140,7 +140,7 @@ public float Distance } [System.Runtime.CompilerServices.SkipLocalsInit] - public static void PrepareForIteration(ref ConstraintData constraint, float idt) + public static void PrepareForIteration(ref ConstraintData constraint, Real idt) { ref PointOnLineData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref data.Body1.Data; @@ -252,13 +252,13 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) body2.AngularVelocity += JVector.Transform(jacobian[3] * acc.X + jacobian[7] * acc.Y + jacobian[11] * acc.Z, body2.InverseInertiaWorld); } - public float Softness + public Real Softness { get => handle.Data.Softness; set => handle.Data.Softness = value; } - public float Bias + public Real Bias { get => handle.Data.BiasFactor; set => handle.Data.BiasFactor = value; @@ -266,20 +266,20 @@ public float Bias public JVector Impulse => handle.Data.AccumulatedImpulse; - public float LimitSoftness + public Real LimitSoftness { get => handle.Data.LimitSoftness; set => handle.Data.LimitSoftness = value; } - public float LimitBias + public Real LimitBias { get => handle.Data.LimitBias; set => handle.Data.LimitBias = value; } [System.Runtime.CompilerServices.SkipLocalsInit] - public static void Iterate(ref ConstraintData constraint, float idt) + public static void Iterate(ref ConstraintData constraint, Real idt) { ref PointOnLineData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref constraint.Body1.Data; @@ -332,20 +332,20 @@ public static void Iterate(ref ConstraintData constraint, float idt) softnessVector.Y *= data.Softness; softnessVector.Z *= data.LimitSoftness; - JVector lambda = -1.0f * JVector.Transform(jv + data.Bias + softnessVector, data.EffectiveMass); + JVector lambda = -(Real)1.0 * JVector.Transform(jv + data.Bias + softnessVector, data.EffectiveMass); JVector origAcc = data.AccumulatedImpulse; data.AccumulatedImpulse += lambda; if ((data.Clamp & 1) != 0) - data.AccumulatedImpulse.Z = MathF.Min(data.AccumulatedImpulse.Z, 0.0f); + data.AccumulatedImpulse.Z = MathR.Min(data.AccumulatedImpulse.Z, (Real)0.0); else if ((data.Clamp & 2) != 0) - data.AccumulatedImpulse.Z = MathF.Max(data.AccumulatedImpulse.Z, 0.0f); + data.AccumulatedImpulse.Z = MathR.Max(data.AccumulatedImpulse.Z, (Real)0.0); else { - data.AccumulatedImpulse.Z = 0.0f; - origAcc.Z = 0.0f; + data.AccumulatedImpulse.Z = (Real)0.0; + origAcc.Z = (Real)0.0; } lambda = data.AccumulatedImpulse - origAcc; diff --git a/src/Jitter2/Dynamics/Constraints/PointOnPlane.cs b/src/Jitter2/Dynamics/Constraints/PointOnPlane.cs index d34c34b8..d72361a0 100644 --- a/src/Jitter2/Dynamics/Constraints/PointOnPlane.cs +++ b/src/Jitter2/Dynamics/Constraints/PointOnPlane.cs @@ -43,7 +43,7 @@ public struct SliderData internal int _internal; public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; @@ -53,19 +53,19 @@ public struct SliderData public JVector LocalAnchor1; public JVector LocalAnchor2; - public float BiasFactor; - public float Softness; + public Real BiasFactor; + public Real Softness; - public float EffectiveMass; - public float AccumulatedImpulse; - public float Bias; + public Real EffectiveMass; + public Real AccumulatedImpulse; + public Real Bias; - public float Min; - public float Max; + public Real Min; + public Real Max; public ushort Clamp; - public MemoryHelper.MemBlock48 J0; + public MemoryHelper.MemBlock12Real J0; } private JHandle handle; @@ -107,13 +107,13 @@ public void Initialize(JVector axis, JVector anchor1, JVector anchor2, LinearLim JVector.ConjugatedTransform(axis, body1.Orientation, out data.LocalAxis); - data.BiasFactor = 0.01f; - data.Softness = 0.00001f; + data.BiasFactor = (Real)0.01; + data.Softness = (Real)0.00001; (data.Min, data.Max) = limit; } - public static void PrepareForIteration(ref ConstraintData constraint, float idt) + public static void PrepareForIteration(ref ConstraintData constraint, Real idt) { ref SliderData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref data.Body1.Data; @@ -138,9 +138,9 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) jacobian[2] = axis; jacobian[3] = R2 % axis; - float error = JVector.Dot(U, axis); + Real error = JVector.Dot(U, axis); - data.EffectiveMass = 1.0f; + data.EffectiveMass = (Real)1.0; if (error > data.Max) { @@ -163,11 +163,11 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) JVector.Transform(jacobian[3], body2.InverseInertiaWorld) * jacobian[3]; data.EffectiveMass += (data.Softness * idt); - data.EffectiveMass = 1.0f / data.EffectiveMass; + data.EffectiveMass = (Real)1.0 / data.EffectiveMass; data.Bias = error * data.BiasFactor * idt; - float acc = data.AccumulatedImpulse; + Real acc = data.AccumulatedImpulse; body1.Velocity += body1.InverseMass * (jacobian[0] * acc); body1.AngularVelocity += JVector.Transform(jacobian[1] * acc, body1.InverseInertiaWorld); @@ -176,21 +176,21 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) body2.AngularVelocity += JVector.Transform(jacobian[3] * acc, body2.InverseInertiaWorld); } - public float Softness + public Real Softness { get => handle.Data.Softness; set => handle.Data.Softness = value; } - public float Bias + public Real Bias { get => handle.Data.BiasFactor; set => handle.Data.BiasFactor = value; } - public float Impulse => handle.Data.AccumulatedImpulse; + public Real Impulse => handle.Data.AccumulatedImpulse; - public static void Iterate(ref ConstraintData constraint, float idt) + public static void Iterate(ref ConstraintData constraint, Real idt) { ref SliderData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref constraint.Body1.Data; @@ -200,24 +200,24 @@ public static void Iterate(ref ConstraintData constraint, float idt) var jacobian = new Span(Unsafe.AsPointer(ref data.J0), 4); - float jv = jacobian[0] * body1.Velocity + jacobian[1] * body1.AngularVelocity + jacobian[2] * body2.Velocity + + Real jv = jacobian[0] * body1.Velocity + jacobian[1] * body1.AngularVelocity + jacobian[2] * body2.Velocity + jacobian[3] * body2.AngularVelocity; - float softness = data.AccumulatedImpulse * data.Softness * idt; + Real softness = data.AccumulatedImpulse * data.Softness * idt; - float lambda = -1.0f * (jv + data.Bias + softness) * data.EffectiveMass; + Real lambda = -(Real)1.0 * (jv + data.Bias + softness) * data.EffectiveMass; - float origAcc = data.AccumulatedImpulse; + Real origAcc = data.AccumulatedImpulse; data.AccumulatedImpulse += lambda; if (data.Clamp == 1) { - data.AccumulatedImpulse = MathF.Min(data.AccumulatedImpulse, 0.0f); + data.AccumulatedImpulse = MathR.Min(data.AccumulatedImpulse, (Real)0.0); } else { - data.AccumulatedImpulse = MathF.Max(data.AccumulatedImpulse, 0.0f); + data.AccumulatedImpulse = MathR.Max(data.AccumulatedImpulse, (Real)0.0); } lambda = data.AccumulatedImpulse - origAcc; diff --git a/src/Jitter2/Dynamics/Constraints/TwistAngle.cs b/src/Jitter2/Dynamics/Constraints/TwistAngle.cs index a43419f0..2d5b6a7f 100644 --- a/src/Jitter2/Dynamics/Constraints/TwistAngle.cs +++ b/src/Jitter2/Dynamics/Constraints/TwistAngle.cs @@ -41,7 +41,7 @@ public struct TwistLimitData { internal int _internal; public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; @@ -50,15 +50,15 @@ public struct TwistLimitData public JQuaternion Q0; - public float Angle1, Angle2; + public Real Angle1, Angle2; public ushort Clamp; - public float BiasFactor; - public float Softness; + public Real BiasFactor; + public Real Softness; - public float EffectiveMass; - public float AccumulatedImpulse; - public float Bias; + public Real EffectiveMass; + public Real AccumulatedImpulse; + public Real Bias; public JVector Jacobian; } @@ -85,14 +85,14 @@ public void Initialize(JVector axis1, JVector axis2, AngularLimit limit) ref RigidBodyData body1 = ref data.Body1.Data; ref RigidBodyData body2 = ref data.Body2.Data; - data.Softness = 0.0001f; - data.BiasFactor = 0.2f; + data.Softness = (Real)0.0001; + data.BiasFactor = (Real)0.2; axis1.Normalize(); axis2.Normalize(); - data.Angle1 = MathF.Sin((float)limit.From / 2.0f); - data.Angle2 = MathF.Sin((float)limit.To / 2.0f); + data.Angle1 = MathR.Sin((Real)limit.From / (Real)2.0); + data.Angle2 = MathR.Sin((Real)limit.To / (Real)2.0); data.B = JVector.TransposedTransform(axis2, body2.Orientation); @@ -107,8 +107,8 @@ public AngularLimit Limit set { ref TwistLimitData data = ref handle.Data; - data.Angle1 = MathF.Sin((float)value.From / 2.0f); - data.Angle2 = MathF.Sin((float)value.To / 2.0f); + data.Angle1 = MathR.Sin((Real)value.From / (Real)2.0); + data.Angle2 = MathR.Sin((Real)value.To / (Real)2.0); } } @@ -122,7 +122,7 @@ public void Initialize(JVector axis1, JVector axis2) Initialize(axis1, axis2, AngularLimit.Fixed); } - public static void PrepareForIteration(ref ConstraintData constraint, float idt) + public static void PrepareForIteration(ref ConstraintData constraint, Real idt) { ref TwistLimitData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); @@ -132,7 +132,7 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) JQuaternion q1 = body1.Orientation; JQuaternion q2 = body2.Orientation; - JMatrix m = (-1.0f / 2.0f) * QMatrix.ProjectMultiplyLeftRight(data.Q0 * q1.Conjugate(), q2); + JMatrix m = (-(Real)(1.0 / 2.0)) * QMatrix.ProjectMultiplyLeftRight(data.Q0 * q1.Conjugate(), q2); JQuaternion q = data.Q0 * q1.Conjugate() * q2; @@ -142,13 +142,13 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) data.EffectiveMass += (data.Softness * idt); - data.EffectiveMass = 1.0f / data.EffectiveMass; + data.EffectiveMass = (Real)1.0 / data.EffectiveMass; - float error = JVector.Dot(data.B, new JVector(q.X, q.Y, q.Z)); + Real error = JVector.Dot(data.B, new JVector(q.X, q.Y, q.Z)); - if (q.W < 0.0f) + if (q.W < (Real)0.0) { - error *= -1.0f; + error *= -(Real)1.0; data.Jacobian *= -1; } @@ -166,7 +166,7 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) } else { - data.AccumulatedImpulse = 0.0f; + data.AccumulatedImpulse = (Real)0.0; return; } @@ -186,29 +186,29 @@ public JAngle Angle JQuaternion quat0 = data.Q0 * q1.Conjugate() * q2; - if (quat0.W < 0.0f) + if (quat0.W < (Real)0.0) { - quat0 *= -1.0f; + quat0 *= -(Real)1.0; } - float error = JVector.Dot(data.B, new JVector(quat0.X, quat0.Y, quat0.Z)); - return (JAngle)(2.0f * MathF.Asin(error)); + Real error = JVector.Dot(data.B, new JVector(quat0.X, quat0.Y, quat0.Z)); + return (JAngle)((Real)2.0 * MathR.Asin(error)); } } - public float Softness + public Real Softness { get => handle.Data.Softness; set => handle.Data.Softness = value; } - public float Bias + public Real Bias { get => handle.Data.BiasFactor; set => handle.Data.BiasFactor = value; } - public float Impulse => handle.Data.AccumulatedImpulse; + public Real Impulse => handle.Data.AccumulatedImpulse; public override void DebugDraw(IDebugDrawer drawer) { @@ -218,7 +218,7 @@ public override void DebugDraw(IDebugDrawer drawer) ref RigidBodyData body2 = ref data.Body2.Data; } - public static void Iterate(ref ConstraintData constraint, float idt) + public static void Iterate(ref ConstraintData constraint, Real idt) { ref TwistLimitData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref constraint.Body1.Data; @@ -226,22 +226,22 @@ public static void Iterate(ref ConstraintData constraint, float idt) if (data.Clamp == 0) return; - float jv = (body1.AngularVelocity - body2.AngularVelocity) * data.Jacobian; + Real jv = (body1.AngularVelocity - body2.AngularVelocity) * data.Jacobian; - float softnessScalar = data.AccumulatedImpulse * (data.Softness * idt); + Real softnessScalar = data.AccumulatedImpulse * (data.Softness * idt); - float lambda = -data.EffectiveMass * (jv + data.Bias + softnessScalar); + Real lambda = -data.EffectiveMass * (jv + data.Bias + softnessScalar); - float origAcc = data.AccumulatedImpulse; + Real origAcc = data.AccumulatedImpulse; data.AccumulatedImpulse += lambda; if (data.Clamp == 1) { - data.AccumulatedImpulse = MathF.Min(data.AccumulatedImpulse, 0.0f); + data.AccumulatedImpulse = MathR.Min(data.AccumulatedImpulse, (Real)0.0); } else { - data.AccumulatedImpulse = MathF.Max(data.AccumulatedImpulse, 0.0f); + data.AccumulatedImpulse = MathR.Max(data.AccumulatedImpulse, (Real)0.0); } lambda = data.AccumulatedImpulse - origAcc; diff --git a/src/Jitter2/Dynamics/Contact.cs b/src/Jitter2/Dynamics/Contact.cs index 864f06b9..68313275 100644 --- a/src/Jitter2/Dynamics/Contact.cs +++ b/src/Jitter2/Dynamics/Contact.cs @@ -59,7 +59,7 @@ public struct ContactData /// A sphere may slide down a ramp. Within one timestep Jitter may detect the collision, create the contact, /// solve the contact, integrate velocities and positions and then consider the contact as broken, since the /// movement orthogonal to the contact normal exceeds a threshold. This results in no intact contact before calling - /// and no intact contact after the call. However, the correspondig bit for the + /// and no intact contact after the call. However, the corresponding bit for the /// solver-phase will be set in this scenario. /// public uint UsageMask; @@ -69,8 +69,8 @@ public struct ContactData public ArbiterKey Key; - public float Restitution; - public float Friction; + public Real Restitution; + public Real Friction; public bool IsSpeculative; @@ -79,11 +79,11 @@ public struct ContactData public Contact Contact2; public Contact Contact3; - public unsafe void PrepareForIteration(float dt) + public unsafe void PrepareForIteration(Real dt) { var ptr = (ContactData*)Unsafe.AsPointer(ref this); - if (Vector128.IsHardwareAccelerated) + if (Vector.IsHardwareAccelerated) { if ((UsageMask & MaskContact0) != 0) Contact0.PrepareForIterationAccelerated(ptr, dt); if ((UsageMask & MaskContact1) != 0) Contact1.PrepareForIterationAccelerated(ptr, dt); @@ -103,7 +103,7 @@ public unsafe void Iterate(bool applyBias) { var ptr = (ContactData*)Unsafe.AsPointer(ref this); - if (Vector128.IsHardwareAccelerated) + if (Vector.IsHardwareAccelerated) { if ((UsageMask & MaskContact0) != 0) Contact0.IterateAccelerated(ptr, applyBias); if ((UsageMask & MaskContact1) != 0) Contact1.IterateAccelerated(ptr, applyBias); @@ -119,6 +119,12 @@ public unsafe void Iterate(bool applyBias) } } + /// + /// Gets a value indicating whether the current system supports hardware acceleration + /// for SIMD (Single Instruction, Multiple Data) operations. + /// + public static bool IsHardwareAccelerated => Vector.IsHardwareAccelerated; + public unsafe void UpdatePosition() { UsageMask &= MaskContactAll; @@ -152,8 +158,8 @@ public void Init(RigidBody body1, RigidBody body2) Body1 = body1.handle; Body2 = body2.handle; - Friction = MathF.Max(body1.Friction, body2.Friction); - Restitution = MathF.Max(body1.Restitution, body2.Restitution); + Friction = MathR.Max(body1.Friction, body2.Friction); + Restitution = MathR.Max(body1.Restitution, body2.Restitution); UsageMask = 0; } @@ -184,7 +190,7 @@ public void Init(RigidBody body1, RigidBody body2) /// /// Adds a new collision result to the contact manifold. Keeps at most four points. /// - public unsafe void AddContact(in JVector point1, in JVector point2, in JVector normal, float penetration) + public unsafe void AddContact(in JVector point1, in JVector point2, in JVector normal, Real penetration) { if ((UsageMask & MaskContactAll) == MaskContactAll) { @@ -197,13 +203,13 @@ public unsafe void AddContact(in JVector point1, in JVector point2, in JVector n // to an already existing point. Replace this point by the new one. Contact* closest = (Contact*)IntPtr.Zero; - float distanceSq = float.MaxValue; + Real distanceSq = Real.MaxValue; JVector relP1 = point1 - Body1.Data.Position; if ((UsageMask & MaskContact0) != 0) { - float distSq = (Contact0.RelativePosition1 - relP1).LengthSquared(); + Real distSq = (Contact0.RelativePosition1 - relP1).LengthSquared(); if (distSq < distanceSq) { distanceSq = distSq; @@ -213,7 +219,7 @@ public unsafe void AddContact(in JVector point1, in JVector point2, in JVector n if ((UsageMask & MaskContact1) != 0) { - float distSq = (Contact1.RelativePosition1 - relP1).LengthSquared(); + Real distSq = (Contact1.RelativePosition1 - relP1).LengthSquared(); if (distSq < distanceSq) { distanceSq = distSq; @@ -223,7 +229,7 @@ public unsafe void AddContact(in JVector point1, in JVector point2, in JVector n if ((UsageMask & MaskContact2) != 0) { - float distSq = (Contact2.RelativePosition1 - relP1).LengthSquared(); + Real distSq = (Contact2.RelativePosition1 - relP1).LengthSquared(); if (distSq < distanceSq) { distanceSq = distSq; @@ -233,7 +239,7 @@ public unsafe void AddContact(in JVector point1, in JVector point2, in JVector n if ((UsageMask & MaskContact3) != 0) { - float distSq = (Contact3.RelativePosition1 - relP1).LengthSquared(); + Real distSq = (Contact3.RelativePosition1 - relP1).LengthSquared(); if (distSq < distanceSq) { distanceSq = distSq; @@ -271,7 +277,7 @@ public unsafe void AddContact(in JVector point1, in JVector point2, in JVector n } } - private static float CalcArea4Points(in JVector p0, in JVector p1, in JVector p2, in JVector p3) + private static Real CalcArea4Points(in JVector p0, in JVector p1, in JVector p2, in JVector p3) { JVector a0 = p0 - p1; JVector a1 = p0 - p2; @@ -284,26 +290,26 @@ private static float CalcArea4Points(in JVector p0, in JVector p1, in JVector p2 JVector tmp1 = a1 % b1; JVector tmp2 = a2 % b2; - return MathF.Max(MathF.Max(tmp0.LengthSquared(), tmp1.LengthSquared()), tmp2.LengthSquared()); + return MathR.Max(MathR.Max(tmp0.LengthSquared(), tmp1.LengthSquared()), tmp2.LengthSquared()); } - private void SortCachedPoints(in JVector point1, in JVector point2, in JVector normal, float penetration) + private void SortCachedPoints(in JVector point1, in JVector point2, in JVector normal, Real penetration) { JVector.Subtract(point1, Body1.Data.Position, out JVector rp1); // calculate 4 possible cases areas, and take the biggest area // int maxPenetrationIndex = -1; - // float maxPenetration = penetration; + // Real maxPenetration = penetration; // always prefer the new point - const float epsilon = -0.0001f; + const Real epsilon = -(Real)0.0001; - float biggestArea = 0; + Real biggestArea = 0; ref Contact cref = ref Contact0; uint index = 0; - float clsq = CalcArea4Points(rp1, Contact1.RelativePosition1, Contact2.RelativePosition1, Contact3.RelativePosition1); + Real clsq = CalcArea4Points(rp1, Contact1.RelativePosition1, Contact2.RelativePosition1, Contact3.RelativePosition1); if (clsq > biggestArea + epsilon) { @@ -347,10 +353,10 @@ private void SortCachedPoints(in JVector point1, in JVector point2, in JVector n [StructLayout(LayoutKind.Explicit)] public struct Contact { - public const float MaximumBias = 100.0f; - public const float BiasFactor = 0.2f; - public const float AllowedPenetration = 0.01f; - public const float BreakThreshold = 0.02f; + public const Real MaximumBias = (Real)100.0; + public const Real BiasFactor = (Real)0.2; + public const Real AllowedPenetration = (Real)0.01; + public const Real BreakThreshold = (Real)0.02; [Flags] public enum Flags @@ -362,45 +368,45 @@ public enum Flags public Flags Flag; [FieldOffset(4)] - public float Bias; + public Real Bias; - [FieldOffset(8)] - public float PenaltyBias; + [FieldOffset(4+1*sizeof(Real))] + public Real PenaltyBias; - [FieldOffset(12)] - public float Penetration; + [FieldOffset(4+2*sizeof(Real))] + public Real Penetration; - [FieldOffset(16)] - internal Vector128 NormalTangentX; + [FieldOffset(4+3*sizeof(Real))] + internal VectorReal NormalTangentX; - [FieldOffset(28)] - internal Vector128 NormalTangentY; + [FieldOffset(4+6*sizeof(Real))] + internal VectorReal NormalTangentY; - [FieldOffset(40)] - internal Vector128 NormalTangentZ; + [FieldOffset(4+9*sizeof(Real))] + internal VectorReal NormalTangentZ; - [FieldOffset(52)] - internal Vector128 MassNormalTangent; + [FieldOffset(4+12*sizeof(Real))] + internal VectorReal MassNormalTangent; - [FieldOffset(64)] - internal Vector128 Accumulated; + [FieldOffset(4+15*sizeof(Real))] + internal VectorReal Accumulated; - [FieldOffset(80)] + [FieldOffset(4+19*sizeof(Real))] [ReferenceFrame(ReferenceFrame.Local)] internal JVector Position1; - [FieldOffset(92)] + [FieldOffset(4+22*sizeof(Real))] [ReferenceFrame(ReferenceFrame.Local)] internal JVector Position2; /// /// Position of the contact relative to the center of mass on the first body. /// - [FieldOffset(104)] + [FieldOffset(4+25*sizeof(Real))] [ReferenceFrame(ReferenceFrame.World)] public JVector RelativePosition1; /// /// Position of the contact relative to the center of mass on the second body. /// - [FieldOffset(116)] + [FieldOffset(4+28*sizeof(Real))] [ReferenceFrame(ReferenceFrame.World)] public JVector RelativePosition2; [ReferenceFrame(ReferenceFrame.World)] public JVector Normal => new JVector(NormalTangentX.GetElement(0), NormalTangentY.GetElement(0), NormalTangentZ.GetElement(0)); @@ -409,16 +415,16 @@ public enum Flags [ReferenceFrame(ReferenceFrame.World)] public JVector Tangent2 => new JVector(NormalTangentX.GetElement(2), NormalTangentY.GetElement(2), NormalTangentZ.GetElement(2)); - public float Impulse => Accumulated.GetElement(0); + public Real Impulse => Accumulated.GetElement(0); - public float TangentImpulse1 => Accumulated.GetElement(1); + public Real TangentImpulse1 => Accumulated.GetElement(1); - public float TangentImpulse2 => Accumulated.GetElement(2); + public Real TangentImpulse2 => Accumulated.GetElement(2); public void Initialize(ref RigidBodyData b1, ref RigidBodyData b2, in JVector point1, in JVector point2, in JVector n, - float penetration, bool newContact, float restitution) + Real penetration, bool newContact, Real restitution) { - Debug.Assert(Math.Abs(n.LengthSquared() - 1.0f) < 1e-3); + Debug.Assert(Math.Abs(n.LengthSquared() - (Real)1.0) < 1e-3); JVector.Subtract(point1, b1.Position, out RelativePosition1); JVector.Subtract(point2, b2.Position, out RelativePosition2); @@ -431,28 +437,28 @@ public void Initialize(ref RigidBodyData b1, ref RigidBodyData b2, in JVector po if (!newContact) return; Flag = Flags.NewContact; - Accumulated = Vector128.Create(0.0f); + Accumulated = Vector.Create((Real)0.0); JVector dv = b2.Velocity + b2.AngularVelocity % RelativePosition2; dv -= b1.Velocity + b1.AngularVelocity % RelativePosition1; - float relNormalVel = JVector.Dot(dv, n); + Real relNormalVel = JVector.Dot(dv, n); Bias = 0; // Fake restitution - if (relNormalVel < -1.0f) + if (relNormalVel < (Real)(-1.0)) { Bias = -restitution * relNormalVel; } var tangent1 = dv - n * relNormalVel; - float num = tangent1.LengthSquared(); + Real num = tangent1.LengthSquared(); - if (num > 1e-12f) + if (num > (Real)1e-12) { - num = 1.0f / MathF.Sqrt(num); + num = (Real)1.0 / MathR.Sqrt(num); tangent1 *= num; } else @@ -462,9 +468,9 @@ public void Initialize(ref RigidBodyData b1, ref RigidBodyData b2, in JVector po var tangent2 = tangent1 % n; - NormalTangentX = Vector128.Create(n.X, tangent1.X, tangent2.X, 0); - NormalTangentY = Vector128.Create(n.Y, tangent1.Y, tangent2.Y, 0); - NormalTangentZ = Vector128.Create(n.Z, tangent1.Z, tangent2.Z, 0); + NormalTangentX = Vector.Create(n.X, tangent1.X, tangent2.X, 0); + NormalTangentY = Vector.Create(n.Y, tangent1.Y, tangent2.Y, 0); + NormalTangentZ = Vector.Create(n.Z, tangent1.Z, tangent2.Z, 0); } public unsafe bool UpdatePosition(ContactData* cd) @@ -487,13 +493,13 @@ public unsafe bool UpdatePosition(ContactData* cd) Penetration = JVector.Dot(dist, n); - if (Penetration < -BreakThreshold * 0.1f) + if (Penetration < -BreakThreshold * (Real)0.1) { return false; } dist -= Penetration * n; - float tangentialOffsetSq = dist.LengthSquared(); + Real tangentialOffsetSq = dist.LengthSquared(); if (tangentialOffsetSq > BreakThreshold * BreakThreshold) { @@ -504,15 +510,15 @@ public unsafe bool UpdatePosition(ContactData* cd) } // Fallback for missing hardware acceleration - #region public unsafe void PrepareForIteration(ContactData* cd, float idt) - public unsafe void PrepareForIteration(ContactData* cd, float idt) + #region public unsafe void PrepareForIteration(ContactData* cd, Real idt) + public unsafe void PrepareForIteration(ContactData* cd, Real idt) { ref var b1 = ref cd->Body1.Data; ref var b2 = ref cd->Body2.Data; - float accumulatedNormalImpulse = Accumulated.GetElement(0); - float accumulatedTangentImpulse1 = Accumulated.GetElement(1); - float accumulatedTangentImpulse2 = Accumulated.GetElement(2); + Real accumulatedNormalImpulse = Accumulated.GetElement(0); + Real accumulatedTangentImpulse1 = Accumulated.GetElement(1); + Real accumulatedTangentImpulse2 = Accumulated.GetElement(2); var normal = new JVector(NormalTangentX.GetElement(0), NormalTangentY.GetElement(0), NormalTangentZ.GetElement(0)); var tangent1 = new JVector(NormalTangentX.GetElement(1), NormalTangentY.GetElement(1), NormalTangentZ.GetElement(1)); @@ -524,11 +530,11 @@ public unsafe void PrepareForIteration(ContactData* cd, float idt) JVector.Add(RelativePosition2, b2.Position, out JVector p2); JVector.Subtract(p1, p2, out JVector dist); - float inverseMass = b1.InverseMass + b2.InverseMass; + Real inverseMass = b1.InverseMass + b2.InverseMass; - float kTangent1 = inverseMass; - float kTangent2 = inverseMass; - float kNormal = inverseMass; + Real kTangent1 = inverseMass; + Real kTangent2 = inverseMass; + Real kNormal = inverseMass; if (!cd->IsSpeculative) { @@ -578,12 +584,12 @@ public unsafe void PrepareForIteration(ContactData* cd, float idt) accumulatedTangentImpulse2 * mTt2; } - float massTangent1 = 1.0f / kTangent1; - float massTangent2 = 1.0f / kTangent2; - float massNormal = 1.0f / kNormal; + Real massTangent1 = (Real)1.0 / kTangent1; + Real massTangent2 = (Real)1.0 / kTangent2; + Real massNormal = (Real)1.0 / kNormal; JVector mass = new JVector(massNormal, massTangent1, massTangent2); - Unsafe.CopyBlock(Unsafe.AsPointer(ref MassNormalTangent), Unsafe.AsPointer(ref mass), 12); + Unsafe.CopyBlock(Unsafe.AsPointer(ref MassNormalTangent), Unsafe.AsPointer(ref mass), 3*sizeof(Real)); if ((Flag & Flags.NewContact) == 0) { @@ -595,8 +601,8 @@ public unsafe void PrepareForIteration(ContactData* cd, float idt) Bias = Penetration * idt; } - PenaltyBias = BiasFactor * idt * Math.Max(0.0f, Penetration - AllowedPenetration); - PenaltyBias = Math.Clamp(PenaltyBias, 0.0f, MaximumBias); + PenaltyBias = BiasFactor * idt * Math.Max((Real)0.0, Penetration - AllowedPenetration); + PenaltyBias = Math.Clamp(PenaltyBias, (Real)0.0, MaximumBias); JVector impulse = normal * accumulatedNormalImpulse + tangent1 * accumulatedTangentImpulse1 + @@ -616,12 +622,12 @@ public unsafe void Iterate(ContactData* cd, bool applyBias) ref var b1 = ref cd->Body1.Data; ref var b2 = ref cd->Body2.Data; - float massNormal = MassNormalTangent.GetElement(0); - float massTangent1 = MassNormalTangent.GetElement(1); - float massTangent2 = MassNormalTangent.GetElement(2); - float accumulatedNormalImpulse = Accumulated.GetElement(0); - float accumulatedTangentImpulse1 = Accumulated.GetElement(1); - float accumulatedTangentImpulse2 = Accumulated.GetElement(2); + Real massNormal = MassNormalTangent.GetElement(0); + Real massTangent1 = MassNormalTangent.GetElement(1); + Real massTangent2 = MassNormalTangent.GetElement(2); + Real accumulatedNormalImpulse = Accumulated.GetElement(0); + Real accumulatedTangentImpulse1 = Accumulated.GetElement(1); + Real accumulatedTangentImpulse2 = Accumulated.GetElement(2); var normal = new JVector(NormalTangentX.GetElement(0), NormalTangentY.GetElement(0), NormalTangentZ.GetElement(0)); var tangent1 = new JVector(NormalTangentX.GetElement(1), NormalTangentY.GetElement(1), NormalTangentZ.GetElement(1)); @@ -630,36 +636,36 @@ public unsafe void Iterate(ContactData* cd, bool applyBias) JVector dv = b2.Velocity + b2.AngularVelocity % RelativePosition2; dv -= b1.Velocity + b1.AngularVelocity % RelativePosition1; - float vn = JVector.Dot(normal, dv); - float vt1 = JVector.Dot(tangent1, dv); - float vt2 = JVector.Dot(tangent2, dv); + Real vn = JVector.Dot(normal, dv); + Real vt1 = JVector.Dot(tangent1, dv); + Real vt2 = JVector.Dot(tangent2, dv); - float normalImpulse = -vn; + Real normalImpulse = -vn; - if (applyBias) normalImpulse += MathF.Max(PenaltyBias, Bias); + if (applyBias) normalImpulse += MathR.Max(PenaltyBias, Bias); else normalImpulse += Bias; normalImpulse *= massNormal; - float oldNormalImpulse = accumulatedNormalImpulse; - accumulatedNormalImpulse = MathF.Max(oldNormalImpulse + normalImpulse, 0.0f); + Real oldNormalImpulse = accumulatedNormalImpulse; + accumulatedNormalImpulse = MathR.Max(oldNormalImpulse + normalImpulse, (Real)0.0); normalImpulse = accumulatedNormalImpulse - oldNormalImpulse; - float maxTangentImpulse = cd->Friction * accumulatedNormalImpulse; - float tangentImpulse1 = massTangent1 * -vt1; - float tangentImpulse2 = massTangent2 * -vt2; + Real maxTangentImpulse = cd->Friction * accumulatedNormalImpulse; + Real tangentImpulse1 = massTangent1 * -vt1; + Real tangentImpulse2 = massTangent2 * -vt2; - float oldTangentImpulse1 = accumulatedTangentImpulse1; + Real oldTangentImpulse1 = accumulatedTangentImpulse1; accumulatedTangentImpulse1 = oldTangentImpulse1 + tangentImpulse1; accumulatedTangentImpulse1 = Math.Clamp(accumulatedTangentImpulse1, -maxTangentImpulse, maxTangentImpulse); tangentImpulse1 = accumulatedTangentImpulse1 - oldTangentImpulse1; - float oldTangentImpulse2 = accumulatedTangentImpulse2; + Real oldTangentImpulse2 = accumulatedTangentImpulse2; accumulatedTangentImpulse2 = oldTangentImpulse2 + tangentImpulse2; accumulatedTangentImpulse2 = Math.Clamp(accumulatedTangentImpulse2, -maxTangentImpulse, maxTangentImpulse); tangentImpulse2 = accumulatedTangentImpulse2 - oldTangentImpulse2; - Accumulated = Vector128.Create(accumulatedNormalImpulse, accumulatedTangentImpulse1, accumulatedTangentImpulse2, 0); + Accumulated = Vector.Create(accumulatedNormalImpulse, accumulatedTangentImpulse1, accumulatedTangentImpulse2, 0); if (!cd->IsSpeculative) { @@ -693,12 +699,12 @@ public unsafe void Iterate(ContactData* cd, bool applyBias) #endregion [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static float GetSum3(Vector128 vector) + private static Real GetSum3(VectorReal vector) { return vector.GetElement(0) + vector.GetElement(1) + vector.GetElement(2); } - public unsafe void PrepareForIterationAccelerated(ContactData* cd, float idt) + public unsafe void PrepareForIterationAccelerated(ContactData* cd, Real idt) { ref var b1 = ref cd->Body1.Data; ref var b2 = ref cd->Body2.Data; @@ -706,7 +712,7 @@ public unsafe void PrepareForIterationAccelerated(ContactData* cd, float idt) JVector.Transform(Position1, b1.Orientation, out RelativePosition1); JVector.Transform(Position2, b2.Orientation, out RelativePosition2); - Vector128 kNormalTangent = Vector128.Create(b1.InverseMass + b2.InverseMass); + VectorReal kNormalTangent = Vector.Create(b1.InverseMass + b2.InverseMass); if (!cd->IsSpeculative) { @@ -718,68 +724,68 @@ public unsafe void PrepareForIterationAccelerated(ContactData* cd, float idt) Penetration = JVector.Dot(dist, n); - var rp1X = Vector128.Create(RelativePosition1.X); - var rp1Y = Vector128.Create(RelativePosition1.Y); - var rp1Z = Vector128.Create(RelativePosition1.Z); + var rp1X = Vector.Create(RelativePosition1.X); + var rp1Y = Vector.Create(RelativePosition1.Y); + var rp1Z = Vector.Create(RelativePosition1.Z); - var rp2X = Vector128.Create(RelativePosition2.X); - var rp2Y = Vector128.Create(RelativePosition2.Y); - var rp2Z = Vector128.Create(RelativePosition2.Z); + var rp2X = Vector.Create(RelativePosition2.X); + var rp2Y = Vector.Create(RelativePosition2.Y); + var rp2Z = Vector.Create(RelativePosition2.Z); - var rrx = Vector128.Subtract(Vector128.Multiply(rp1Y, NormalTangentZ), Vector128.Multiply(rp1Z, NormalTangentY)); - var rry = Vector128.Subtract(Vector128.Multiply(rp1Z, NormalTangentX), Vector128.Multiply(rp1X, NormalTangentZ)); - var rrz = Vector128.Subtract(Vector128.Multiply(rp1X, NormalTangentY), Vector128.Multiply(rp1Y, NormalTangentX)); + var rrx = Vector.Subtract(Vector.Multiply(rp1Y, NormalTangentZ), Vector.Multiply(rp1Z, NormalTangentY)); + var rry = Vector.Subtract(Vector.Multiply(rp1Z, NormalTangentX), Vector.Multiply(rp1X, NormalTangentZ)); + var rrz = Vector.Subtract(Vector.Multiply(rp1X, NormalTangentY), Vector.Multiply(rp1Y, NormalTangentX)); - var ixx = Vector128.Create(b1.InverseInertiaWorld.M11); - var ixy = Vector128.Create(b1.InverseInertiaWorld.M21); - var ixz = Vector128.Create(b1.InverseInertiaWorld.M31); - var iyy = Vector128.Create(b1.InverseInertiaWorld.M22); - var iyz = Vector128.Create(b1.InverseInertiaWorld.M23); - var izz = Vector128.Create(b1.InverseInertiaWorld.M33); + var ixx = Vector.Create(b1.InverseInertiaWorld.M11); + var ixy = Vector.Create(b1.InverseInertiaWorld.M21); + var ixz = Vector.Create(b1.InverseInertiaWorld.M31); + var iyy = Vector.Create(b1.InverseInertiaWorld.M22); + var iyz = Vector.Create(b1.InverseInertiaWorld.M23); + var izz = Vector.Create(b1.InverseInertiaWorld.M33); - var e1 = Vector128.Add(Vector128.Add(Vector128.Multiply(ixx, rrx), Vector128.Multiply(ixy, rry)), Vector128.Multiply(ixz, rrz)); - var e2 = Vector128.Add(Vector128.Add(Vector128.Multiply(ixy, rrx), Vector128.Multiply(iyy, rry)), Vector128.Multiply(iyz, rrz)); - var e3 = Vector128.Add(Vector128.Add(Vector128.Multiply(ixz, rrx), Vector128.Multiply(iyz, rry)), Vector128.Multiply(izz, rrz)); + var e1 = Vector.Add(Vector.Add(Vector.Multiply(ixx, rrx), Vector.Multiply(ixy, rry)), Vector.Multiply(ixz, rrz)); + var e2 = Vector.Add(Vector.Add(Vector.Multiply(ixy, rrx), Vector.Multiply(iyy, rry)), Vector.Multiply(iyz, rrz)); + var e3 = Vector.Add(Vector.Add(Vector.Multiply(ixz, rrx), Vector.Multiply(iyz, rry)), Vector.Multiply(izz, rrz)); - rrx = Vector128.Subtract(Vector128.Multiply(rp2Y, NormalTangentZ), Vector128.Multiply(rp2Z, NormalTangentY)); - rry = Vector128.Subtract(Vector128.Multiply(rp2Z, NormalTangentX), Vector128.Multiply(rp2X, NormalTangentZ)); - rrz = Vector128.Subtract(Vector128.Multiply(rp2X, NormalTangentY), Vector128.Multiply(rp2Y, NormalTangentX)); + rrx = Vector.Subtract(Vector.Multiply(rp2Y, NormalTangentZ), Vector.Multiply(rp2Z, NormalTangentY)); + rry = Vector.Subtract(Vector.Multiply(rp2Z, NormalTangentX), Vector.Multiply(rp2X, NormalTangentZ)); + rrz = Vector.Subtract(Vector.Multiply(rp2X, NormalTangentY), Vector.Multiply(rp2Y, NormalTangentX)); - ixx = Vector128.Create(b2.InverseInertiaWorld.M11); - ixy = Vector128.Create(b2.InverseInertiaWorld.M21); - ixz = Vector128.Create(b2.InverseInertiaWorld.M31); - iyy = Vector128.Create(b2.InverseInertiaWorld.M22); - iyz = Vector128.Create(b2.InverseInertiaWorld.M23); - izz = Vector128.Create(b2.InverseInertiaWorld.M33); + ixx = Vector.Create(b2.InverseInertiaWorld.M11); + ixy = Vector.Create(b2.InverseInertiaWorld.M21); + ixz = Vector.Create(b2.InverseInertiaWorld.M31); + iyy = Vector.Create(b2.InverseInertiaWorld.M22); + iyz = Vector.Create(b2.InverseInertiaWorld.M23); + izz = Vector.Create(b2.InverseInertiaWorld.M33); - var f1 = Vector128.Add(Vector128.Add(Vector128.Multiply(ixx, rrx), Vector128.Multiply(ixy, rry)), Vector128.Multiply(ixz, rrz)); - var f2 = Vector128.Add(Vector128.Add(Vector128.Multiply(ixy, rrx), Vector128.Multiply(iyy, rry)), Vector128.Multiply(iyz, rrz)); - var f3 = Vector128.Add(Vector128.Add(Vector128.Multiply(ixz, rrx), Vector128.Multiply(iyz, rry)), Vector128.Multiply(izz, rrz)); + var f1 = Vector.Add(Vector.Add(Vector.Multiply(ixx, rrx), Vector.Multiply(ixy, rry)), Vector.Multiply(ixz, rrz)); + var f2 = Vector.Add(Vector.Add(Vector.Multiply(ixy, rrx), Vector.Multiply(iyy, rry)), Vector.Multiply(iyz, rrz)); + var f3 = Vector.Add(Vector.Add(Vector.Multiply(ixz, rrx), Vector.Multiply(iyz, rry)), Vector.Multiply(izz, rrz)); - var ktnx = Vector128.Subtract(Vector128.Add(Vector128.Subtract(Vector128.Multiply(e2, rp1Z), Vector128.Multiply(e3, rp1Y)), Vector128.Multiply(f2, rp2Z)), Vector128.Multiply(f3, rp2Y)); - var ktny = Vector128.Subtract(Vector128.Add(Vector128.Subtract(Vector128.Multiply(e3, rp1X), Vector128.Multiply(e1, rp1Z)), Vector128.Multiply(f3, rp2X)), Vector128.Multiply(f1, rp2Z)); - var ktnz = Vector128.Subtract(Vector128.Add(Vector128.Subtract(Vector128.Multiply(e1, rp1Y), Vector128.Multiply(e2, rp1X)), Vector128.Multiply(f1, rp2Y)), Vector128.Multiply(f2, rp2X)); + var ktnx = Vector.Subtract(Vector.Add(Vector.Subtract(Vector.Multiply(e2, rp1Z), Vector.Multiply(e3, rp1Y)), Vector.Multiply(f2, rp2Z)), Vector.Multiply(f3, rp2Y)); + var ktny = Vector.Subtract(Vector.Add(Vector.Subtract(Vector.Multiply(e3, rp1X), Vector.Multiply(e1, rp1Z)), Vector.Multiply(f3, rp2X)), Vector.Multiply(f1, rp2Z)); + var ktnz = Vector.Subtract(Vector.Add(Vector.Subtract(Vector.Multiply(e1, rp1Y), Vector.Multiply(e2, rp1X)), Vector.Multiply(f1, rp2Y)), Vector.Multiply(f2, rp2X)); - var kres = Vector128.Add(Vector128.Add(Vector128.Multiply(NormalTangentX, ktnx), Vector128.Multiply(NormalTangentY, ktny)), Vector128.Multiply(NormalTangentZ, ktnz)); + var kres = Vector.Add(Vector.Add(Vector.Multiply(NormalTangentX, ktnx), Vector.Multiply(NormalTangentY, ktny)), Vector.Multiply(NormalTangentZ, ktnz)); - kNormalTangent = Vector128.Add(kNormalTangent, kres); + kNormalTangent = Vector.Add(kNormalTangent, kres); Unsafe.SkipInit(out JVector angularImpulse1); - angularImpulse1.X = GetSum3(Vector128.Multiply(Accumulated, e1)); - angularImpulse1.Y = GetSum3(Vector128.Multiply(Accumulated, e2)); - angularImpulse1.Z = GetSum3(Vector128.Multiply(Accumulated, e3)); + angularImpulse1.X = GetSum3(Vector.Multiply(Accumulated, e1)); + angularImpulse1.Y = GetSum3(Vector.Multiply(Accumulated, e2)); + angularImpulse1.Z = GetSum3(Vector.Multiply(Accumulated, e3)); Unsafe.SkipInit(out JVector angularImpulse2); - angularImpulse2.X = GetSum3(Vector128.Multiply(Accumulated, f1)); - angularImpulse2.Y = GetSum3(Vector128.Multiply(Accumulated, f2)); - angularImpulse2.Z = GetSum3(Vector128.Multiply(Accumulated, f3)); + angularImpulse2.X = GetSum3(Vector.Multiply(Accumulated, f1)); + angularImpulse2.Y = GetSum3(Vector.Multiply(Accumulated, f2)); + angularImpulse2.Z = GetSum3(Vector.Multiply(Accumulated, f3)); b1.AngularVelocity -= angularImpulse1; b2.AngularVelocity += angularImpulse2; } - var mnt = Vector128.Divide(Vector128.Create(1.0f), kNormalTangent); - Unsafe.CopyBlock(Unsafe.AsPointer(ref MassNormalTangent), Unsafe.AsPointer(ref mnt), 12); + var mnt = Vector.Divide(Vector.Create((Real)1.0), kNormalTangent); + Unsafe.CopyBlock(Unsafe.AsPointer(ref MassNormalTangent), Unsafe.AsPointer(ref mnt), 3*sizeof(Real)); if ((Flag & Flags.NewContact) == 0) { @@ -792,14 +798,14 @@ public unsafe void PrepareForIterationAccelerated(ContactData* cd, float idt) Bias = Penetration * idt; } - PenaltyBias = BiasFactor * idt * Math.Max(0.0f, Penetration - AllowedPenetration); - PenaltyBias = Math.Clamp(PenaltyBias, 0.0f, MaximumBias); + PenaltyBias = BiasFactor * idt * Math.Max((Real)0.0, Penetration - AllowedPenetration); + PenaltyBias = Math.Clamp(PenaltyBias, (Real)0.0, MaximumBias); // warm-starting, linear Unsafe.SkipInit(out JVector linearImpulse); - linearImpulse.X = GetSum3(Vector128.Multiply(Accumulated, NormalTangentX)); - linearImpulse.Y = GetSum3(Vector128.Multiply(Accumulated, NormalTangentY)); - linearImpulse.Z = GetSum3(Vector128.Multiply(Accumulated, NormalTangentZ)); + linearImpulse.X = GetSum3(Vector.Multiply(Accumulated, NormalTangentX)); + linearImpulse.Y = GetSum3(Vector.Multiply(Accumulated, NormalTangentY)); + linearImpulse.Z = GetSum3(Vector.Multiply(Accumulated, NormalTangentZ)); b1.Velocity -= b1.InverseMass * linearImpulse; b2.Velocity += b2.InverseMass * linearImpulse; @@ -815,81 +821,81 @@ public unsafe void IterateAccelerated(ContactData* cd, bool applyBias) JVector dv = b2.Velocity + b2.AngularVelocity % RelativePosition2; dv -= b1.Velocity + b1.AngularVelocity % RelativePosition1; - var vdots = Vector128.Add(Vector128.Add(Vector128.Multiply(NormalTangentX, Vector128.Create(dv.X)), Vector128.Multiply(NormalTangentY, Vector128.Create(dv.Y))), Vector128.Multiply(NormalTangentZ, Vector128.Create(dv.Z))); + var vdots = Vector.Add(Vector.Add(Vector.Multiply(NormalTangentX, Vector.Create(dv.X)), Vector.Multiply(NormalTangentY, Vector.Create(dv.Y))), Vector.Multiply(NormalTangentZ, Vector.Create(dv.Z))); - float bias = applyBias ? MathF.Max(PenaltyBias, Bias) : Bias; + Real bias = applyBias ? MathR.Max(PenaltyBias, Bias) : Bias; - var impulse = Vector128.Multiply(MassNormalTangent, (Vector128.Subtract(Vector128.Create(bias, 0, 0, 0), vdots))); + var impulse = Vector.Multiply(MassNormalTangent, (Vector.Subtract(Vector.Create(bias, 0, 0, 0), vdots))); var oldImpulse = Accumulated; - float maxTangentImpulse = cd->Friction * Accumulated.GetElement(0); + Real maxTangentImpulse = cd->Friction * Accumulated.GetElement(0); - Accumulated = Vector128.Add(oldImpulse, impulse); + Accumulated = Vector.Add(oldImpulse, impulse); - var minImpulse = Vector128.Create(0, -maxTangentImpulse, -maxTangentImpulse, 0); - var maxImpulse = Vector128.Create(float.MaxValue, maxTangentImpulse, maxTangentImpulse, 0); + var minImpulse = Vector.Create(0, -maxTangentImpulse, -maxTangentImpulse, 0); + var maxImpulse = Vector.Create(Real.MaxValue, maxTangentImpulse, maxTangentImpulse, 0); - Accumulated = Vector128.Min(Vector128.Max(Accumulated, minImpulse), maxImpulse); - impulse = Vector128.Subtract(Accumulated, oldImpulse); + Accumulated = Vector.Min(Vector.Max(Accumulated, minImpulse), maxImpulse); + impulse = Vector.Subtract(Accumulated, oldImpulse); if (!cd->IsSpeculative) { - var rp1X = Vector128.Create(RelativePosition1.X); - var rp1Y = Vector128.Create(RelativePosition1.Y); - var rp1Z = Vector128.Create(RelativePosition1.Z); - - var rp2X = Vector128.Create(RelativePosition2.X); - var rp2Y = Vector128.Create(RelativePosition2.Y); - var rp2Z = Vector128.Create(RelativePosition2.Z); - - var rrx = Vector128.Subtract(Vector128.Multiply(rp1Y, NormalTangentZ), Vector128.Multiply(rp1Z, NormalTangentY)); - var rry = Vector128.Subtract(Vector128.Multiply(rp1Z, NormalTangentX), Vector128.Multiply(rp1X, NormalTangentZ)); - var rrz = Vector128.Subtract(Vector128.Multiply(rp1X, NormalTangentY), Vector128.Multiply(rp1Y, NormalTangentX)); - - var ixx = Vector128.Create(b1.InverseInertiaWorld.M11); - var ixy = Vector128.Create(b1.InverseInertiaWorld.M21); - var ixz = Vector128.Create(b1.InverseInertiaWorld.M31); - var iyy = Vector128.Create(b1.InverseInertiaWorld.M22); - var iyz = Vector128.Create(b1.InverseInertiaWorld.M23); - var izz = Vector128.Create(b1.InverseInertiaWorld.M33); - - var e1 = Vector128.Add(Vector128.Add(Vector128.Multiply(ixx, rrx), Vector128.Multiply(ixy, rry)), Vector128.Multiply(ixz, rrz)); - var e2 = Vector128.Add(Vector128.Add(Vector128.Multiply(ixy, rrx), Vector128.Multiply(iyy, rry)), Vector128.Multiply(iyz, rrz)); - var e3 = Vector128.Add(Vector128.Add(Vector128.Multiply(ixz, rrx), Vector128.Multiply(iyz, rry)), Vector128.Multiply(izz, rrz)); - - rrx = Vector128.Subtract(Vector128.Multiply(rp2Y, NormalTangentZ), Vector128.Multiply(rp2Z, NormalTangentY)); - rry = Vector128.Subtract(Vector128.Multiply(rp2Z, NormalTangentX), Vector128.Multiply(rp2X, NormalTangentZ)); - rrz = Vector128.Subtract(Vector128.Multiply(rp2X, NormalTangentY), Vector128.Multiply(rp2Y, NormalTangentX)); - - ixx = Vector128.Create(b2.InverseInertiaWorld.M11); - ixy = Vector128.Create(b2.InverseInertiaWorld.M21); - ixz = Vector128.Create(b2.InverseInertiaWorld.M31); - iyy = Vector128.Create(b2.InverseInertiaWorld.M22); - iyz = Vector128.Create(b2.InverseInertiaWorld.M23); - izz = Vector128.Create(b2.InverseInertiaWorld.M33); - - var f1 = Vector128.Add(Vector128.Add(Vector128.Multiply(ixx, rrx), Vector128.Multiply(ixy, rry)), Vector128.Multiply(ixz, rrz)); - var f2 = Vector128.Add(Vector128.Add(Vector128.Multiply(ixy, rrx), Vector128.Multiply(iyy, rry)), Vector128.Multiply(iyz, rrz)); - var f3 = Vector128.Add(Vector128.Add(Vector128.Multiply(ixz, rrx), Vector128.Multiply(iyz, rry)), Vector128.Multiply(izz, rrz)); + var rp1X = Vector.Create(RelativePosition1.X); + var rp1Y = Vector.Create(RelativePosition1.Y); + var rp1Z = Vector.Create(RelativePosition1.Z); + + var rp2X = Vector.Create(RelativePosition2.X); + var rp2Y = Vector.Create(RelativePosition2.Y); + var rp2Z = Vector.Create(RelativePosition2.Z); + + var rrx = Vector.Subtract(Vector.Multiply(rp1Y, NormalTangentZ), Vector.Multiply(rp1Z, NormalTangentY)); + var rry = Vector.Subtract(Vector.Multiply(rp1Z, NormalTangentX), Vector.Multiply(rp1X, NormalTangentZ)); + var rrz = Vector.Subtract(Vector.Multiply(rp1X, NormalTangentY), Vector.Multiply(rp1Y, NormalTangentX)); + + var ixx = Vector.Create(b1.InverseInertiaWorld.M11); + var ixy = Vector.Create(b1.InverseInertiaWorld.M21); + var ixz = Vector.Create(b1.InverseInertiaWorld.M31); + var iyy = Vector.Create(b1.InverseInertiaWorld.M22); + var iyz = Vector.Create(b1.InverseInertiaWorld.M23); + var izz = Vector.Create(b1.InverseInertiaWorld.M33); + + var e1 = Vector.Add(Vector.Add(Vector.Multiply(ixx, rrx), Vector.Multiply(ixy, rry)), Vector.Multiply(ixz, rrz)); + var e2 = Vector.Add(Vector.Add(Vector.Multiply(ixy, rrx), Vector.Multiply(iyy, rry)), Vector.Multiply(iyz, rrz)); + var e3 = Vector.Add(Vector.Add(Vector.Multiply(ixz, rrx), Vector.Multiply(iyz, rry)), Vector.Multiply(izz, rrz)); + + rrx = Vector.Subtract(Vector.Multiply(rp2Y, NormalTangentZ), Vector.Multiply(rp2Z, NormalTangentY)); + rry = Vector.Subtract(Vector.Multiply(rp2Z, NormalTangentX), Vector.Multiply(rp2X, NormalTangentZ)); + rrz = Vector.Subtract(Vector.Multiply(rp2X, NormalTangentY), Vector.Multiply(rp2Y, NormalTangentX)); + + ixx = Vector.Create(b2.InverseInertiaWorld.M11); + ixy = Vector.Create(b2.InverseInertiaWorld.M21); + ixz = Vector.Create(b2.InverseInertiaWorld.M31); + iyy = Vector.Create(b2.InverseInertiaWorld.M22); + iyz = Vector.Create(b2.InverseInertiaWorld.M23); + izz = Vector.Create(b2.InverseInertiaWorld.M33); + + var f1 = Vector.Add(Vector.Add(Vector.Multiply(ixx, rrx), Vector.Multiply(ixy, rry)), Vector.Multiply(ixz, rrz)); + var f2 = Vector.Add(Vector.Add(Vector.Multiply(ixy, rrx), Vector.Multiply(iyy, rry)), Vector.Multiply(iyz, rrz)); + var f3 = Vector.Add(Vector.Add(Vector.Multiply(ixz, rrx), Vector.Multiply(iyz, rry)), Vector.Multiply(izz, rrz)); Unsafe.SkipInit(out JVector angularImpulse1); - angularImpulse1.X = GetSum3(Vector128.Multiply(impulse, e1)); - angularImpulse1.Y = GetSum3(Vector128.Multiply(impulse, e2)); - angularImpulse1.Z = GetSum3(Vector128.Multiply(impulse, e3)); + angularImpulse1.X = GetSum3(Vector.Multiply(impulse, e1)); + angularImpulse1.Y = GetSum3(Vector.Multiply(impulse, e2)); + angularImpulse1.Z = GetSum3(Vector.Multiply(impulse, e3)); Unsafe.SkipInit(out JVector angularImpulse2); - angularImpulse2.X = GetSum3(Vector128.Multiply(impulse, f1)); - angularImpulse2.Y = GetSum3(Vector128.Multiply(impulse, f2)); - angularImpulse2.Z = GetSum3(Vector128.Multiply(impulse, f3)); + angularImpulse2.X = GetSum3(Vector.Multiply(impulse, f1)); + angularImpulse2.Y = GetSum3(Vector.Multiply(impulse, f2)); + angularImpulse2.Z = GetSum3(Vector.Multiply(impulse, f3)); b1.AngularVelocity -= angularImpulse1; b2.AngularVelocity += angularImpulse2; } Unsafe.SkipInit(out JVector linearImpulse); - linearImpulse.X = GetSum3(Vector128.Multiply(impulse, NormalTangentX)); - linearImpulse.Y = GetSum3(Vector128.Multiply(impulse, NormalTangentY)); - linearImpulse.Z = GetSum3(Vector128.Multiply(impulse, NormalTangentZ)); + linearImpulse.X = GetSum3(Vector.Multiply(impulse, NormalTangentX)); + linearImpulse.Y = GetSum3(Vector.Multiply(impulse, NormalTangentY)); + linearImpulse.Z = GetSum3(Vector.Multiply(impulse, NormalTangentZ)); b1.Velocity -= b1.InverseMass * linearImpulse; b2.Velocity += b2.InverseMass * linearImpulse; diff --git a/src/Jitter2/Dynamics/RigidBody.cs b/src/Jitter2/Dynamics/RigidBody.cs index 0214a4ec..bde6e034 100644 --- a/src/Jitter2/Dynamics/RigidBody.cs +++ b/src/Jitter2/Dynamics/RigidBody.cs @@ -49,7 +49,7 @@ public struct RigidBodyData public JQuaternion Orientation; public JMatrix InverseInertiaWorld; - public float InverseMass; + public Real InverseMass; public bool IsActive; public bool IsStatic; @@ -65,8 +65,8 @@ public sealed class RigidBody : IListIndex, IDebugDrawable public readonly ulong RigidBodyId; - private float restitution = 0.0f; - private float friction = 0.2f; + private Real restitution = (Real)0.0; + private Real friction = (Real)0.2; /// /// Due to performance considerations, the data used to simulate this body (e.g., velocity or position) @@ -147,17 +147,17 @@ internal void RaiseEndCollide(Arbiter arbiter) internal int islandMarker; - internal float sleepTime = 0.0f; + internal Real sleepTime = (Real)0.0; - internal float inactiveThresholdLinearSq = 0.1f; - internal float inactiveThresholdAngularSq = 0.1f; - internal float deactivationTimeThreshold = 1.0f; + internal Real inactiveThresholdLinearSq = (Real)0.1; + internal Real inactiveThresholdAngularSq = (Real)0.1; + internal Real deactivationTimeThreshold = (Real)1.0; - internal float linearDampingMultiplier = 0.998f; - internal float angularDampingMultiplier = 0.995f; + internal Real linearDampingMultiplier = (Real)0.998; + internal Real angularDampingMultiplier = (Real)0.995; internal JMatrix inverseInertia = JMatrix.Identity; - internal float inverseMass = 1.0f; + internal Real inverseMass = (Real)1.0; /// /// Gets or sets the friction coefficient for this object. @@ -171,12 +171,12 @@ internal void RaiseEndCollide(Arbiter arbiter) /// /// Thrown if the value is not between 0 and 1. /// - public float Friction + public Real Friction { get => friction; set { - if (value < 0.0f || value > 1.0f) + if (value < (Real)0.0 || value > (Real)1.0) { throw new ArgumentOutOfRangeException(nameof(value), "Friction must be between 0 and 1."); @@ -198,12 +198,12 @@ public float Friction /// /// Thrown if the value is not between 0 and 1. /// - public float Restitution + public Real Restitution { get => restitution; set { - if (value < 0.0f || value > 1.0f) + if (value < (Real)0.0 || value > (Real)1.0) { throw new ArgumentOutOfRangeException(nameof(value), "Restitution must be between 0 and 1."); @@ -251,7 +251,7 @@ internal RigidBody(JHandle handle, World world) public TimeSpan DeactivationTime { get => TimeSpan.FromSeconds(deactivationTimeThreshold); - set => deactivationTimeThreshold = (float)value.TotalSeconds; + set => deactivationTimeThreshold = (Real)value.TotalSeconds; } /// @@ -259,9 +259,9 @@ public TimeSpan DeactivationTime /// remain below the specified values for the duration of , the body is deactivated. /// The threshold values are given in rad/s and length units/s, respectively. /// - public (float angular, float linear) DeactivationThreshold + public (Real angular, Real linear) DeactivationThreshold { - get => (MathF.Sqrt(inactiveThresholdAngularSq), MathF.Sqrt(inactiveThresholdLinearSq)); + get => (MathR.Sqrt(inactiveThresholdAngularSq), MathR.Sqrt(inactiveThresholdLinearSq)); set { if (value.linear < 0 || value.angular < 0) @@ -279,27 +279,27 @@ public TimeSpan DeactivationTime /// Gets or sets the damping factors for linear and angular motion. /// A damping factor of 0 means the body is not damped, while 1 brings /// the body to a halt immediately. Damping is applied when calling - /// . Jitter multiplies the respective + /// . Jitter multiplies the respective /// velocity each step by 1 minus the damping factor. Note that the values /// are not scaled by time; a smaller time-step in - /// results in increased damping. + /// results in increased damping. /// /// /// The damping factors should be within the range [0, 1]. /// - public (float linear, float angular) Damping + public (Real linear, Real angular) Damping { - get => (1.0f - linearDampingMultiplier, 1.0f - angularDampingMultiplier); + get => ((Real)1.0 - linearDampingMultiplier, (Real)1.0 - angularDampingMultiplier); set { - if (value.linear < 0.0f || value.linear > 1.0f || value.angular < 0.0f || value.angular > 1.0f) + if (value.linear < (Real)0.0 || value.linear > (Real)1.0 || value.angular < (Real)0.0 || value.angular > (Real)1.0) { throw new ArgumentOutOfRangeException(nameof(value), "Damping multiplier has to be within [0, 1]."); } - linearDampingMultiplier = 1.0f - value.linear; - angularDampingMultiplier = 1.0f - value.angular; + linearDampingMultiplier = (Real)1.0 - value.linear; + angularDampingMultiplier = (Real)1.0 - value.angular; } } @@ -311,7 +311,7 @@ public override int GetHashCode() private void SetDefaultMassInertia() { inverseInertia = JMatrix.Identity; - Data.InverseMass = 1.0f; + Data.InverseMass = (Real)1.0; UpdateWorldInertia(); } @@ -374,7 +374,7 @@ private void UpdateWorldInertia() if (Data.IsStatic) { Data.InverseInertiaWorld = JMatrix.Zero; - Data.InverseMass = 0.0f; + Data.InverseMass = (Real)0.0; } else { @@ -470,19 +470,19 @@ public void AddShape(RigidBodyShape shape, bool setMassInertia = true) } /// - /// Represents the force to be applied to the body during the next call to . + /// Represents the force to be applied to the body during the next call to . /// This value is automatically reset to zero after the call. /// public JVector Force { get; set; } /// - /// Represents the torque to be applied to the body during the next call to . + /// Represents the torque to be applied to the body during the next call to . /// This value is automatically reset to zero after the call. /// public JVector Torque { get; set; } /// - /// Applies a force to the rigid body, thereby altering its velocity. This force is effective for a single frame only and is reset to zero during the next call to . + /// Applies a force to the rigid body, thereby altering its velocity. This force is effective for a single frame only and is reset to zero during the next call to . /// /// The force to be applied. public void AddForce(in JVector force) @@ -492,7 +492,7 @@ public void AddForce(in JVector force) /// /// Applies a force to the rigid body, altering its velocity. This force is applied for a single frame only and is - /// reset to zero with the subsequent call to . + /// reset to zero with the subsequent call to . /// /// The force to be applied. /// The position where the force will be applied. @@ -606,12 +606,12 @@ public void SetMassInertia() if (shapes.Count == 0) { inverseInertia = JMatrix.Identity; - Data.InverseMass = 1.0f; + Data.InverseMass = (Real)1.0; return; } JMatrix inertia = JMatrix.Zero; - float mass = 0.0f; + Real mass = (Real)0.0; for (int i = 0; i < shapes.Count; i++) { @@ -628,7 +628,7 @@ public void SetMassInertia() "RigidBody.AddShape, call AddShape with setMassInertia set to false."); } - inverseMass = 1.0f / mass; + inverseMass = (Real)1.0 / mass; UpdateWorldInertia(); } @@ -636,9 +636,9 @@ public void SetMassInertia() /// /// Sets a new mass value and scales the inertia according to the ratio of the old mass to the new mass. /// - public void SetMassInertia(float mass) + public void SetMassInertia(Real mass) { - if (mass <= 0.0f) + if (mass <= (Real)0.0) { // we do not protect against NaN here, since it is the users responsibility // to not feed NaNs to the engine. @@ -646,8 +646,8 @@ public void SetMassInertia(float mass) } SetMassInertia(); - inverseInertia = JMatrix.Multiply(inverseInertia, 1.0f / (Data.InverseMass * mass)); - inverseMass = 1.0f / mass; + inverseInertia = JMatrix.Multiply(inverseInertia, (Real)1.0 / (Data.InverseMass * mass)); + inverseMass = (Real)1.0 / mass; UpdateWorldInertia(); } @@ -656,11 +656,11 @@ public void SetMassInertia(float mass) /// /// Set the inverse values. /// - public void SetMassInertia(in JMatrix inertia, float mass, bool setAsInverse = false) + public void SetMassInertia(in JMatrix inertia, Real mass, bool setAsInverse = false) { if (setAsInverse) { - if (float.IsInfinity(mass) || mass < 0.0f) + if (Real.IsInfinity(mass) || mass < (Real)0.0) { throw new ArgumentException("Inverse mass must be finite and not negative.", nameof(mass)); } @@ -670,7 +670,7 @@ public void SetMassInertia(in JMatrix inertia, float mass, bool setAsInverse = f } else { - if (mass <= 0.0f) + if (mass <= (Real)0.0) { throw new ArgumentException("Mass can not be zero or negative.", nameof(mass)); } @@ -680,7 +680,7 @@ public void SetMassInertia(in JMatrix inertia, float mass, bool setAsInverse = f throw new ArgumentException("Inertia matrix is not invertible.", nameof(inertia)); } - inverseMass = 1.0f / mass; + inverseMass = (Real)1.0 / mass; } UpdateWorldInertia(); @@ -715,10 +715,10 @@ public void DebugDraw(IDebugDrawer drawer) /// /// Gets the mass of the rigid body. To modify the mass, use - /// or - /// . + /// or + /// . /// - public float Mass => 1.0f / inverseMass; + public Real Mass => (Real)1.0 / inverseMass; int IListIndex.ListIndex { get; set; } = -1; } \ No newline at end of file diff --git a/src/Jitter2/Jitter2.csproj b/src/Jitter2/Jitter2.csproj index 08f826a3..5d2e871a 100644 --- a/src/Jitter2/Jitter2.csproj +++ b/src/Jitter2/Jitter2.csproj @@ -1,46 +1,58 @@ - - net7.0;net8.0;net9.0 - disable - enable - true - + + net7.0;net8.0;net9.0 + disable + enable + true + - - CS1591;CS1573 - + + CS1591;CS1573 + - - - Jitter Physics 2, the evolution of Jitter Physics, is an impulse-based dynamics engine with a semi-implicit Euler integrator. - It is a fast, simple, and dependency-free engine written in C# with a clear and user-friendly API. - - true - readme.md - https://jitterphysics.com - icon.png - physics engine;collision;csharp;dotnet - MIT - notgiven688 - https://github.com/notgiven688/jitterphysics2.git - git - Embedded - True - true - snupkg - + + + Jitter Physics 2, the evolution of Jitter Physics, is an impulse-based dynamics engine with a semi-implicit Euler integrator. + It is a fast, simple, and dependency-free engine written in C# with a clear and user-friendly API. + + true + readme.md + https://jitterphysics.com + icon.png + physics engine;collision;csharp;dotnet + MIT + notgiven688 + https://github.com/notgiven688/jitterphysics2.git + git + Embedded + true + true + snupkg + - - - - + + + + - - $(DefineConstants);RELEASE;TRACE - false - portable - true - + + + $(DefineConstants);RELEASE;TRACE + false + portable + true + + + + + $(DefineConstants);USE_DOUBLE_PRECISION + Jitter2.Double + + Jitter Physics 2 with double precision enabled. This is an impulse-based dynamics engine with a semi-implicit Euler integrator. + + Jitter2.Double + physics engine;collision;csharp;dotnet;double precision + diff --git a/src/Jitter2/LinearMath/JAngle.cs b/src/Jitter2/LinearMath/JAngle.cs index 21ca5116..2a4dcd8b 100644 --- a/src/Jitter2/LinearMath/JAngle.cs +++ b/src/Jitter2/LinearMath/JAngle.cs @@ -26,12 +26,12 @@ namespace Jitter2.LinearMath; /// -/// A 32-bit floating point variable representing an angle. This structure exists to eliminate +/// A 32-bit Realing point variable representing an angle. This structure exists to eliminate /// ambiguity between radians and degrees in the Jitter API. /// public struct JAngle : IEquatable { - public float Radiant { get; set; } + public Real Radiant { get; set; } public readonly override bool Equals(object? obj) { @@ -48,23 +48,23 @@ public readonly override int GetHashCode() return Radiant.GetHashCode(); } - public float Degree + public Real Degree { - readonly get => Radiant / MathF.PI * 180.0f; - set => Radiant = value / 180.0f * MathF.PI; + readonly get => Radiant / MathR.PI * (Real)180.0; + set => Radiant = value / (Real)180.0 * MathR.PI; } - public static JAngle FromRadiant(float rad) + public static JAngle FromRadiant(Real rad) { return new JAngle { Radiant = rad }; } - public static JAngle FromDegree(float deg) + public static JAngle FromDegree(Real deg) { return new JAngle { Degree = deg }; } - public static explicit operator JAngle(float angle) + public static explicit operator JAngle(Real angle) { return FromRadiant(angle); } @@ -86,35 +86,35 @@ public static explicit operator JAngle(float angle) public static bool operator ==(JAngle l, JAngle r) { - return (float)l == (float)r; + return (Real)l == (Real)r; } public static bool operator !=(JAngle l, JAngle r) { - return (float)l != (float)r; + return (Real)l != (Real)r; } public static bool operator <(JAngle l, JAngle r) { - return (float)l < (float)r; + return (Real)l < (Real)r; } public static bool operator >(JAngle l, JAngle r) { - return (float)l > (float)r; + return (Real)l > (Real)r; } public static bool operator >=(JAngle l, JAngle r) { - return (float)l >= (float)r; + return (Real)l >= (Real)r; } public static bool operator <=(JAngle l, JAngle r) { - return (float)l <= (float)r; + return (Real)l <= (Real)r; } - public static explicit operator float(JAngle angle) + public static explicit operator Real(JAngle angle) { return angle.Radiant; } diff --git a/src/Jitter2/LinearMath/JBBox.cs b/src/Jitter2/LinearMath/JBBox.cs index 7acf5e2e..917a09a6 100644 --- a/src/Jitter2/LinearMath/JBBox.cs +++ b/src/Jitter2/LinearMath/JBBox.cs @@ -28,7 +28,7 @@ namespace Jitter2.LinearMath; /// public struct JBBox { - public const float Epsilon = 1e-12f; + public const Real Epsilon = (Real)1e-12; public enum ContainmentType { @@ -46,10 +46,10 @@ public enum ContainmentType static JBBox() { - LargeBox.Min = new JVector(float.MinValue); - LargeBox.Max = new JVector(float.MaxValue); - SmallBox.Min = new JVector(float.MaxValue); - SmallBox.Max = new JVector(float.MinValue); + LargeBox.Min = new JVector(Real.MinValue); + LargeBox.Max = new JVector(Real.MaxValue); + SmallBox.Min = new JVector(Real.MaxValue); + SmallBox.Max = new JVector(Real.MinValue); } public JBBox(JVector min, JVector max) @@ -64,14 +64,14 @@ internal void InverseTransform(ref JVector position, ref JMatrix orientation) JVector.Subtract(Min, position, out Min); JVector.Add(Max, Min, out JVector center); - center.X *= 0.5f; - center.Y *= 0.5f; - center.Z *= 0.5f; + center.X *= (Real)0.5; + center.Y *= (Real)0.5; + center.Z *= (Real)0.5; JVector.Subtract(Max, Min, out JVector halfExtents); - halfExtents.X *= 0.5f; - halfExtents.Y *= 0.5f; - halfExtents.Z *= 0.5f; + halfExtents.X *= (Real)0.5; + halfExtents.Y *= (Real)0.5; + halfExtents.Z *= (Real)0.5; JVector.TransposedTransform(center, orientation, out center); @@ -84,8 +84,8 @@ internal void InverseTransform(ref JVector position, ref JMatrix orientation) public void Transform(ref JMatrix orientation) { - JVector halfExtents = 0.5f * (Max - Min); - JVector center = 0.5f * (Max + Min); + JVector halfExtents = (Real)0.5 * (Max - Min); + JVector center = (Real)0.5 * (Max + Min); JVector.Transform(center, orientation, out center); @@ -96,13 +96,13 @@ public void Transform(ref JMatrix orientation) Min = center - halfExtents; } - private bool Intersect1D(float start, float dir, float min, float max, - ref float enter, ref float exit) + private bool Intersect1D(Real start, Real dir, Real min, Real max, + ref Real enter, ref Real exit) { if (dir * dir < Epsilon * Epsilon) return start >= min && start <= max; - float t0 = (min - start) / dir; - float t1 = (max - start) / dir; + Real t0 = (min - start) / dir; + Real t1 = (max - start) / dir; if (t0 > t1) { @@ -118,7 +118,7 @@ private bool Intersect1D(float start, float dir, float min, float max, public bool SegmentIntersect(in JVector origin, in JVector direction) { - float enter = 0.0f, exit = 1.0f; + Real enter = (Real)0.0, exit = (Real)1.0; if (!Intersect1D(origin.X, direction.X, Min.X, Max.X, ref enter, ref exit)) return false; @@ -134,7 +134,7 @@ public bool SegmentIntersect(in JVector origin, in JVector direction) public bool RayIntersect(in JVector origin, in JVector direction) { - float enter = 0.0f, exit = float.MaxValue; + Real enter = (Real)0.0, exit = Real.MaxValue; if (!Intersect1D(origin.X, direction.X, Min.X, Max.X, ref enter, ref exit)) return false; @@ -148,10 +148,10 @@ public bool RayIntersect(in JVector origin, in JVector direction) return true; } - public bool RayIntersect(in JVector origin, in JVector direction, out float enter) + public bool RayIntersect(in JVector origin, in JVector direction, out Real enter) { - enter = 0.0f; - float exit = float.MaxValue; + enter = (Real)0.0; + Real exit = Real.MaxValue; if (!Intersect1D(origin.X, direction.X, Min.X, Max.X, ref enter, ref exit)) return false; @@ -194,8 +194,8 @@ public void AddPoint(in JVector point) public static JBBox CreateFromPoints(JVector[] points) { - JVector vector3 = new JVector(float.MaxValue); - JVector vector2 = new JVector(float.MinValue); + JVector vector3 = new JVector(Real.MaxValue); + JVector vector2 = new JVector(Real.MinValue); for (int i = 0; i < points.Length; i++) { @@ -245,17 +245,17 @@ public static void CreateMerged(in JBBox original, in JBBox additional, out JBBo JVector.Max(original.Max, additional.Max, out result.Max); } - public readonly JVector Center => (Min + Max) * (1.0f / 2.0f); + public readonly JVector Center => (Min + Max) * ((Real)(1.0 / 2.0)); - public float GetVolume() + public Real GetVolume() { JVector len = Max - Min; return len.X * len.Y * len.Z; } - public float GetSurfaceArea() + public Real GetSurfaceArea() { JVector len = Max - Min; - return 2.0f * (len.X * len.Y + len.Y * len.Z + len.Z * len.X); + return (Real)2.0 * (len.X * len.Y + len.Y * len.Z + len.Z * len.X); } } \ No newline at end of file diff --git a/src/Jitter2/LinearMath/JMatrix.cs b/src/Jitter2/LinearMath/JMatrix.cs index f89ce6fa..03d0711d 100644 --- a/src/Jitter2/LinearMath/JMatrix.cs +++ b/src/Jitter2/LinearMath/JMatrix.cs @@ -28,20 +28,20 @@ namespace Jitter2.LinearMath; /// -/// 3x3 matrix of 32 bit float values in column major format. +/// Represents a three-by-three matrix with components of type . /// -[StructLayout(LayoutKind.Explicit, Size = 36)] +[StructLayout(LayoutKind.Explicit, Size = 9*sizeof(Real))] public struct JMatrix { - [FieldOffset(0)] public float M11; - [FieldOffset(4)] public float M21; - [FieldOffset(8)] public float M31; - [FieldOffset(12)] public float M12; - [FieldOffset(16)] public float M22; - [FieldOffset(20)] public float M32; - [FieldOffset(24)] public float M13; - [FieldOffset(28)] public float M23; - [FieldOffset(32)] public float M33; + [FieldOffset(0*sizeof(Real))] public Real M11; + [FieldOffset(1*sizeof(Real))] public Real M21; + [FieldOffset(2*sizeof(Real))] public Real M31; + [FieldOffset(3*sizeof(Real))] public Real M12; + [FieldOffset(4*sizeof(Real))] public Real M22; + [FieldOffset(5*sizeof(Real))] public Real M32; + [FieldOffset(6*sizeof(Real))] public Real M13; + [FieldOffset(7*sizeof(Real))] public Real M23; + [FieldOffset(8*sizeof(Real))] public Real M33; public static readonly JMatrix Identity; public static readonly JMatrix Zero; @@ -52,13 +52,13 @@ static JMatrix() Identity = new JMatrix { - M11 = 1.0f, - M22 = 1.0f, - M33 = 1.0f + M11 = (Real)1.0, + M22 = (Real)1.0, + M33 = (Real)1.0 }; } - public JMatrix(float m11, float m12, float m13, float m21, float m22, float m23, float m31, float m32, float m33) + public JMatrix(Real m11, Real m12, Real m13, Real m21, Real m22, Real m23, Real m31, Real m32, Real m33) { M11 = m11; M12 = m12; @@ -91,7 +91,7 @@ public unsafe ref JVector UnsafeGet(int index) [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe JVector GetColumn(int index) { - fixed (float* ptr = &M11) + fixed (Real* ptr = &M11) { JVector* vptr = (JVector*)ptr; return vptr[index]; @@ -119,10 +119,10 @@ public static JMatrix TransposedMultiply(in JMatrix matrix1, in JMatrix matrix2) return result; } - public static JMatrix CreateRotationMatrix(JVector axis, float angle) + public static JMatrix CreateRotationMatrix(JVector axis, Real angle) { - float c = MathF.Cos(angle / 2.0f); - float s = MathF.Sin(angle / 2.0f); + Real c = MathR.Cos(angle / (Real)2.0); + Real s = MathR.Sin(angle / (Real)2.0); axis *= s; JQuaternion jq = new(axis.X, axis.Y, axis.Z, c); CreateFromQuaternion(in jq, out JMatrix result); @@ -132,15 +132,15 @@ public static JMatrix CreateRotationMatrix(JVector axis, float angle) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Multiply(in JMatrix matrix1, in JMatrix matrix2, out JMatrix result) { - float num0 = matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21 + matrix1.M13 * matrix2.M31; - float num1 = matrix1.M11 * matrix2.M12 + matrix1.M12 * matrix2.M22 + matrix1.M13 * matrix2.M32; - float num2 = matrix1.M11 * matrix2.M13 + matrix1.M12 * matrix2.M23 + matrix1.M13 * matrix2.M33; - float num3 = matrix1.M21 * matrix2.M11 + matrix1.M22 * matrix2.M21 + matrix1.M23 * matrix2.M31; - float num4 = matrix1.M21 * matrix2.M12 + matrix1.M22 * matrix2.M22 + matrix1.M23 * matrix2.M32; - float num5 = matrix1.M21 * matrix2.M13 + matrix1.M22 * matrix2.M23 + matrix1.M23 * matrix2.M33; - float num6 = matrix1.M31 * matrix2.M11 + matrix1.M32 * matrix2.M21 + matrix1.M33 * matrix2.M31; - float num7 = matrix1.M31 * matrix2.M12 + matrix1.M32 * matrix2.M22 + matrix1.M33 * matrix2.M32; - float num8 = matrix1.M31 * matrix2.M13 + matrix1.M32 * matrix2.M23 + matrix1.M33 * matrix2.M33; + Real num0 = matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21 + matrix1.M13 * matrix2.M31; + Real num1 = matrix1.M11 * matrix2.M12 + matrix1.M12 * matrix2.M22 + matrix1.M13 * matrix2.M32; + Real num2 = matrix1.M11 * matrix2.M13 + matrix1.M12 * matrix2.M23 + matrix1.M13 * matrix2.M33; + Real num3 = matrix1.M21 * matrix2.M11 + matrix1.M22 * matrix2.M21 + matrix1.M23 * matrix2.M31; + Real num4 = matrix1.M21 * matrix2.M12 + matrix1.M22 * matrix2.M22 + matrix1.M23 * matrix2.M32; + Real num5 = matrix1.M21 * matrix2.M13 + matrix1.M22 * matrix2.M23 + matrix1.M23 * matrix2.M33; + Real num6 = matrix1.M31 * matrix2.M11 + matrix1.M32 * matrix2.M21 + matrix1.M33 * matrix2.M31; + Real num7 = matrix1.M31 * matrix2.M12 + matrix1.M32 * matrix2.M22 + matrix1.M33 * matrix2.M32; + Real num8 = matrix1.M31 * matrix2.M13 + matrix1.M32 * matrix2.M23 + matrix1.M33 * matrix2.M33; result.M11 = num0; result.M12 = num1; @@ -166,15 +166,15 @@ public static JMatrix Add(JMatrix matrix1, JMatrix matrix2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MultiplyTransposed(in JMatrix matrix1, in JMatrix matrix2, out JMatrix result) { - float num0 = matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M12 + matrix1.M13 * matrix2.M13; - float num1 = matrix1.M11 * matrix2.M21 + matrix1.M12 * matrix2.M22 + matrix1.M13 * matrix2.M23; - float num2 = matrix1.M11 * matrix2.M31 + matrix1.M12 * matrix2.M32 + matrix1.M13 * matrix2.M33; - float num3 = matrix1.M21 * matrix2.M11 + matrix1.M22 * matrix2.M12 + matrix1.M23 * matrix2.M13; - float num4 = matrix1.M21 * matrix2.M21 + matrix1.M22 * matrix2.M22 + matrix1.M23 * matrix2.M23; - float num5 = matrix1.M21 * matrix2.M31 + matrix1.M22 * matrix2.M32 + matrix1.M23 * matrix2.M33; - float num6 = matrix1.M31 * matrix2.M11 + matrix1.M32 * matrix2.M12 + matrix1.M33 * matrix2.M13; - float num7 = matrix1.M31 * matrix2.M21 + matrix1.M32 * matrix2.M22 + matrix1.M33 * matrix2.M23; - float num8 = matrix1.M31 * matrix2.M31 + matrix1.M32 * matrix2.M32 + matrix1.M33 * matrix2.M33; + Real num0 = matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M12 + matrix1.M13 * matrix2.M13; + Real num1 = matrix1.M11 * matrix2.M21 + matrix1.M12 * matrix2.M22 + matrix1.M13 * matrix2.M23; + Real num2 = matrix1.M11 * matrix2.M31 + matrix1.M12 * matrix2.M32 + matrix1.M13 * matrix2.M33; + Real num3 = matrix1.M21 * matrix2.M11 + matrix1.M22 * matrix2.M12 + matrix1.M23 * matrix2.M13; + Real num4 = matrix1.M21 * matrix2.M21 + matrix1.M22 * matrix2.M22 + matrix1.M23 * matrix2.M23; + Real num5 = matrix1.M21 * matrix2.M31 + matrix1.M22 * matrix2.M32 + matrix1.M23 * matrix2.M33; + Real num6 = matrix1.M31 * matrix2.M11 + matrix1.M32 * matrix2.M12 + matrix1.M33 * matrix2.M13; + Real num7 = matrix1.M31 * matrix2.M21 + matrix1.M32 * matrix2.M22 + matrix1.M33 * matrix2.M23; + Real num8 = matrix1.M31 * matrix2.M31 + matrix1.M32 * matrix2.M32 + matrix1.M33 * matrix2.M33; result.M11 = num0; result.M12 = num1; @@ -187,12 +187,12 @@ public static void MultiplyTransposed(in JMatrix matrix1, in JMatrix matrix2, ou result.M33 = num8; } - public static JMatrix CreateRotationX(float radians) + public static JMatrix CreateRotationX(Real radians) { JMatrix result = Identity; - float c = (float)Math.Cos(radians); - float s = (float)Math.Sin(radians); + Real c = MathR.Cos(radians); + Real s = MathR.Sin(radians); // [ 1 0 0 ] // [ 0 c -s ] @@ -205,12 +205,12 @@ public static JMatrix CreateRotationX(float radians) return result; } - public static JMatrix CreateRotationY(float radians) + public static JMatrix CreateRotationY(Real radians) { JMatrix result = Identity; - float c = (float)Math.Cos(radians); - float s = (float)Math.Sin(radians); + Real c = MathR.Cos(radians); + Real s = MathR.Sin(radians); // [ c 0 s ] // [ 0 1 0 ] @@ -223,12 +223,12 @@ public static JMatrix CreateRotationY(float radians) return result; } - public static JMatrix CreateRotationZ(float radians) + public static JMatrix CreateRotationZ(Real radians) { JMatrix result = Identity; - float c = (float)Math.Cos(radians); - float s = (float)Math.Sin(radians); + Real c = MathR.Cos(radians); + Real s = MathR.Sin(radians); // [ c -s 0 ] // [ s c 0 ] @@ -260,7 +260,7 @@ public static JMatrix CreateScale(in JVector scale) /// Create a scaling matrix. /// /// - public static JMatrix CreateScale(float x, float y, float z) + public static JMatrix CreateScale(Real x, Real y, Real z) { return CreateScale(new JVector(x, y, z)); } @@ -271,15 +271,15 @@ public static JMatrix CreateScale(float x, float y, float z) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void TransposedMultiply(in JMatrix matrix1, in JMatrix matrix2, out JMatrix result) { - float num0 = matrix1.M11 * matrix2.M11 + matrix1.M21 * matrix2.M21 + matrix1.M31 * matrix2.M31; - float num1 = matrix1.M11 * matrix2.M12 + matrix1.M21 * matrix2.M22 + matrix1.M31 * matrix2.M32; - float num2 = matrix1.M11 * matrix2.M13 + matrix1.M21 * matrix2.M23 + matrix1.M31 * matrix2.M33; - float num3 = matrix1.M12 * matrix2.M11 + matrix1.M22 * matrix2.M21 + matrix1.M32 * matrix2.M31; - float num4 = matrix1.M12 * matrix2.M12 + matrix1.M22 * matrix2.M22 + matrix1.M32 * matrix2.M32; - float num5 = matrix1.M12 * matrix2.M13 + matrix1.M22 * matrix2.M23 + matrix1.M32 * matrix2.M33; - float num6 = matrix1.M13 * matrix2.M11 + matrix1.M23 * matrix2.M21 + matrix1.M33 * matrix2.M31; - float num7 = matrix1.M13 * matrix2.M12 + matrix1.M23 * matrix2.M22 + matrix1.M33 * matrix2.M32; - float num8 = matrix1.M13 * matrix2.M13 + matrix1.M23 * matrix2.M23 + matrix1.M33 * matrix2.M33; + Real num0 = matrix1.M11 * matrix2.M11 + matrix1.M21 * matrix2.M21 + matrix1.M31 * matrix2.M31; + Real num1 = matrix1.M11 * matrix2.M12 + matrix1.M21 * matrix2.M22 + matrix1.M31 * matrix2.M32; + Real num2 = matrix1.M11 * matrix2.M13 + matrix1.M21 * matrix2.M23 + matrix1.M31 * matrix2.M33; + Real num3 = matrix1.M12 * matrix2.M11 + matrix1.M22 * matrix2.M21 + matrix1.M32 * matrix2.M31; + Real num4 = matrix1.M12 * matrix2.M12 + matrix1.M22 * matrix2.M22 + matrix1.M32 * matrix2.M32; + Real num5 = matrix1.M12 * matrix2.M13 + matrix1.M22 * matrix2.M23 + matrix1.M32 * matrix2.M33; + Real num6 = matrix1.M13 * matrix2.M11 + matrix1.M23 * matrix2.M21 + matrix1.M33 * matrix2.M31; + Real num7 = matrix1.M13 * matrix2.M12 + matrix1.M23 * matrix2.M22 + matrix1.M33 * matrix2.M32; + Real num8 = matrix1.M13 * matrix2.M13 + matrix1.M23 * matrix2.M23 + matrix1.M33 * matrix2.M33; result.M11 = num0; result.M12 = num1; @@ -321,7 +321,7 @@ public static void Subtract(in JMatrix matrix1, in JMatrix matrix2, out JMatrix } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly float Determinant() + public readonly Real Determinant() { return M11 * M22 * M33 + M12 * M23 * M31 + M13 * M21 * M32 - M31 * M22 * M13 - M32 * M23 * M11 - M33 * M21 * M12; @@ -330,25 +330,25 @@ public readonly float Determinant() [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Inverse(in JMatrix matrix, out JMatrix result) { - float idet = 1.0f / matrix.Determinant(); + Real idet = (Real)1.0 / matrix.Determinant(); - if (!float.IsNormal(idet)) + if (!Real.IsNormal(idet)) { result = new JMatrix(); return false; } - float num11 = matrix.M22 * matrix.M33 - matrix.M23 * matrix.M32; - float num12 = matrix.M13 * matrix.M32 - matrix.M12 * matrix.M33; - float num13 = matrix.M12 * matrix.M23 - matrix.M22 * matrix.M13; + Real num11 = matrix.M22 * matrix.M33 - matrix.M23 * matrix.M32; + Real num12 = matrix.M13 * matrix.M32 - matrix.M12 * matrix.M33; + Real num13 = matrix.M12 * matrix.M23 - matrix.M22 * matrix.M13; - float num21 = matrix.M23 * matrix.M31 - matrix.M33 * matrix.M21; - float num22 = matrix.M11 * matrix.M33 - matrix.M31 * matrix.M13; - float num23 = matrix.M13 * matrix.M21 - matrix.M23 * matrix.M11; + Real num21 = matrix.M23 * matrix.M31 - matrix.M33 * matrix.M21; + Real num22 = matrix.M11 * matrix.M33 - matrix.M31 * matrix.M13; + Real num23 = matrix.M13 * matrix.M21 - matrix.M23 * matrix.M11; - float num31 = matrix.M21 * matrix.M32 - matrix.M31 * matrix.M22; - float num32 = matrix.M12 * matrix.M31 - matrix.M32 * matrix.M11; - float num33 = matrix.M11 * matrix.M22 - matrix.M21 * matrix.M12; + Real num31 = matrix.M21 * matrix.M32 - matrix.M31 * matrix.M22; + Real num32 = matrix.M12 * matrix.M31 - matrix.M32 * matrix.M11; + Real num33 = matrix.M11 * matrix.M22 - matrix.M21 * matrix.M12; result.M11 = num11 * idet; result.M12 = num12 * idet; @@ -364,16 +364,16 @@ public static bool Inverse(in JMatrix matrix, out JMatrix result) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static JMatrix Multiply(JMatrix matrix1, float scaleFactor) + public static JMatrix Multiply(JMatrix matrix1, Real scaleFactor) { Multiply(in matrix1, scaleFactor, out JMatrix result); return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Multiply(in JMatrix matrix1, float scaleFactor, out JMatrix result) + public static void Multiply(in JMatrix matrix1, Real scaleFactor, out JMatrix result) { - float num = scaleFactor; + Real num = scaleFactor; result.M11 = matrix1.M11 * num; result.M12 = matrix1.M12 * num; result.M13 = matrix1.M13 * num; @@ -409,20 +409,20 @@ public static void Absolute(in JMatrix matrix, out JMatrix result) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void CreateFromQuaternion(in JQuaternion quaternion, out JMatrix result) { - float r = quaternion.W; - float i = quaternion.X; - float j = quaternion.Y; - float k = quaternion.Z; + Real r = quaternion.W; + Real i = quaternion.X; + Real j = quaternion.Y; + Real k = quaternion.Z; - result.M11 = 1.0f - 2.0f * (j * j + k * k); - result.M12 = 2.0f * (i * j - k * r); - result.M13 = 2.0f * (i * k + j * r); - result.M21 = 2.0f * (i * j + k * r); - result.M22 = 1.0f - 2.0f * (i * i + k * k); - result.M23 = 2.0f * (j * k - i * r); - result.M31 = 2.0f * (i * k - j * r); - result.M32 = 2.0f * (j * k + i * r); - result.M33 = 1.0f - 2.0f * (i * i + j * j); + result.M11 = (Real)1.0 - (Real)2.0 * (j * j + k * k); + result.M12 = (Real)2.0 * (i * j - k * r); + result.M13 = (Real)2.0 * (i * k + j * r); + result.M21 = (Real)2.0 * (i * j + k * r); + result.M22 = (Real)1.0 - (Real)2.0 * (i * i + k * k); + result.M23 = (Real)2.0 * (j * k - i * r); + result.M31 = (Real)2.0 * (i * k - j * r); + result.M32 = (Real)2.0 * (j * k + i * r); + result.M33 = (Real)1.0 - (Real)2.0 * (i * i + j * j); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -472,20 +472,20 @@ private static void Transpose(in JMatrix matrix, out JMatrix result) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Trace() + public Real Trace() { return M11 + M22 + M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static JMatrix operator *(float factor, in JMatrix matrix) + public static JMatrix operator *(Real factor, in JMatrix matrix) { Multiply(matrix, factor, out JMatrix result); return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static JMatrix operator *(in JMatrix matrix, float factor) + public static JMatrix operator *(in JMatrix matrix, Real factor) { Multiply(matrix, factor, out JMatrix result); return result; diff --git a/src/Jitter2/LinearMath/JQuaternion.cs b/src/Jitter2/LinearMath/JQuaternion.cs index 3963d656..365531c6 100644 --- a/src/Jitter2/LinearMath/JQuaternion.cs +++ b/src/Jitter2/LinearMath/JQuaternion.cs @@ -31,10 +31,10 @@ namespace Jitter2.LinearMath; /// public struct JQuaternion { - public float X; - public float Y; - public float Z; - public float W; + public Real X; + public Real Y; + public Real Z; + public Real W; /// /// Gets the identity quaternion (0, 0, 0, 1). @@ -48,7 +48,7 @@ public struct JQuaternion /// The Y component. /// The Z component. /// The W component. - public JQuaternion(float x, float y, float z, float w) + public JQuaternion(Real x, Real y, Real z, Real w) { X = x; Y = y; @@ -61,7 +61,7 @@ public JQuaternion(float x, float y, float z, float w) /// /// The W component. /// The vector component. - public JQuaternion(float w, in JVector v) + public JQuaternion(Real w, in JVector v) { X = v.X; Y = v.Y; @@ -186,9 +186,9 @@ public readonly JVector GetBasisX() { JVector result; - result.X = 1.0f - 2.0f * (Y * Y + Z * Z); - result.Y = 2.0f * (X * Y + Z * W); - result.Z = 2.0f * (X * Z - Y * W); + result.X = (Real)1.0 - (Real)2.0 * (Y * Y + Z * Z); + result.Y = (Real)2.0 * (X * Y + Z * W); + result.Z = (Real)2.0 * (X * Z - Y * W); return result; } @@ -201,9 +201,9 @@ public readonly JVector GetBasisY() { JVector result; - result.X = 2.0f * (X * Y - Z * W); - result.Y = 1.0f - 2.0f * (X * X + Z * Z); - result.Z = 2.0f * (Y * Z + X * W); + result.X = (Real)2.0 * (X * Y - Z * W); + result.Y = (Real)1.0 - (Real)2.0 * (X * X + Z * Z); + result.Z = (Real)2.0 * (Y * Z + X * W); return result; } @@ -216,9 +216,9 @@ public readonly JVector GetBasisZ() { JVector result; - result.X = 2.0f * (X * Z + Y * W); - result.Y = 2.0f * (Y * Z - X * W); - result.Z = 1.0f - 2.0f * (X * X + Y * Y); + result.X = (Real)2.0 * (X * Z + Y * W); + result.Y = (Real)2.0 * (Y * Z - X * W); + result.Z = (Real)1.0 - (Real)2.0 * (X * X + Y * Y); return result; } @@ -228,10 +228,10 @@ public readonly JVector GetBasisZ() /// /// The angle of rotation in radians. /// A quaternion representing the rotation. - public static JQuaternion CreateRotationX(float radians) + public static JQuaternion CreateRotationX(Real radians) { - float halfAngle = radians * 0.5f; - (float sha, float cha) = MathF.SinCos(halfAngle); + Real halfAngle = radians * (Real)0.5; + (Real sha, Real cha) = MathR.SinCos(halfAngle); return new JQuaternion(sha, 0, 0, cha); } @@ -240,10 +240,10 @@ public static JQuaternion CreateRotationX(float radians) /// /// The angle of rotation in radians. /// A quaternion representing the rotation. - public static JQuaternion CreateRotationY(float radians) + public static JQuaternion CreateRotationY(Real radians) { - float halfAngle = radians * 0.5f; - (float sha, float cha) = MathF.SinCos(halfAngle); + Real halfAngle = radians * (Real)0.5; + (Real sha, Real cha) = MathR.SinCos(halfAngle); return new JQuaternion(0, sha, 0, cha); } @@ -252,10 +252,10 @@ public static JQuaternion CreateRotationY(float radians) /// /// The angle of rotation in radians. /// A quaternion representing the rotation. - public static JQuaternion CreateRotationZ(float radians) + public static JQuaternion CreateRotationZ(Real radians) { - float halfAngle = radians * 0.5f; - (float sha, float cha) = MathF.SinCos(halfAngle); + Real halfAngle = radians * (Real)0.5; + (Real sha, Real cha) = MathR.SinCos(halfAngle); return new JQuaternion(0, 0, sha, cha); } @@ -268,15 +268,15 @@ public static JQuaternion CreateRotationZ(float radians) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Multiply(in JQuaternion quaternion1, in JQuaternion quaternion2, out JQuaternion result) { - float r1 = quaternion1.W; - float i1 = quaternion1.X; - float j1 = quaternion1.Y; - float k1 = quaternion1.Z; + Real r1 = quaternion1.W; + Real i1 = quaternion1.X; + Real j1 = quaternion1.Y; + Real k1 = quaternion1.Z; - float r2 = quaternion2.W; - float i2 = quaternion2.X; - float j2 = quaternion2.Y; - float k2 = quaternion2.Z; + Real r2 = quaternion2.W; + Real i2 = quaternion2.X; + Real j2 = quaternion2.Y; + Real k2 = quaternion2.Z; result.W = r1 * r2 - (i1 * i2 + j1 * j2 + k1 * k2); result.X = r1 * i2 + r2 * i1 + j1 * k2 - k1 * j2; @@ -293,15 +293,15 @@ public static void Multiply(in JQuaternion quaternion1, in JQuaternion quaternio [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ConjugateMultiply(in JQuaternion quaternion1, in JQuaternion quaternion2, out JQuaternion result) { - float r1 = quaternion1.W; - float i1 = -quaternion1.X; - float j1 = -quaternion1.Y; - float k1 = -quaternion1.Z; + Real r1 = quaternion1.W; + Real i1 = -quaternion1.X; + Real j1 = -quaternion1.Y; + Real k1 = -quaternion1.Z; - float r2 = quaternion2.W; - float i2 = quaternion2.X; - float j2 = quaternion2.Y; - float k2 = quaternion2.Z; + Real r2 = quaternion2.W; + Real i2 = quaternion2.X; + Real j2 = quaternion2.Y; + Real k2 = quaternion2.Z; result.W = r1 * r2 - (i1 * i2 + j1 * j2 + k1 * k2); result.X = r1 * i2 + r2 * i1 + j1 * k2 - k1 * j2; @@ -330,15 +330,15 @@ public static JQuaternion ConjugateMultiply(in JQuaternion quaternion1, in JQuat [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MultiplyConjugate(in JQuaternion quaternion1, in JQuaternion quaternion2, out JQuaternion result) { - float r1 = quaternion1.W; - float i1 = quaternion1.X; - float j1 = quaternion1.Y; - float k1 = quaternion1.Z; + Real r1 = quaternion1.W; + Real i1 = quaternion1.X; + Real j1 = quaternion1.Y; + Real k1 = quaternion1.Z; - float r2 = quaternion2.W; - float i2 = -quaternion2.X; - float j2 = -quaternion2.Y; - float k2 = -quaternion2.Z; + Real r2 = quaternion2.W; + Real i2 = -quaternion2.X; + Real j2 = -quaternion2.Y; + Real k2 = -quaternion2.Z; result.W = r1 * r2 - (i1 * i2 + j1 * j2 + k1 * k2); result.X = r1 * i2 + r2 * i1 + j1 * k2 - k1 * j2; @@ -365,7 +365,7 @@ public static JQuaternion MultiplyConjugate(in JQuaternion quaternion1, in JQuat /// The scalar factor. /// The scaled quaternion. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static JQuaternion Multiply(in JQuaternion quaternion1, float scaleFactor) + public static JQuaternion Multiply(in JQuaternion quaternion1, Real scaleFactor) { Multiply(in quaternion1, scaleFactor, out JQuaternion result); return result; @@ -378,7 +378,7 @@ public static JQuaternion Multiply(in JQuaternion quaternion1, float scaleFactor /// The scalar factor. /// When the method completes, contains the scaled quaternion. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Multiply(in JQuaternion quaternion1, float scaleFactor, out JQuaternion result) + public static void Multiply(in JQuaternion quaternion1, Real scaleFactor, out JQuaternion result) { result.W = quaternion1.W * scaleFactor; result.X = quaternion1.X * scaleFactor; @@ -391,9 +391,9 @@ public static void Multiply(in JQuaternion quaternion1, float scaleFactor, out J /// /// The length of the quaternion. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly float Length() + public readonly Real Length() { - return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); + return (Real)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); } /// @@ -402,8 +402,8 @@ public readonly float Length() [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Normalize() { - float num2 = X * X + Y * Y + Z * Z + W * W; - float num = 1f / (float)Math.Sqrt(num2); + Real num2 = X * X + Y * Y + Z * Z + W * W; + Real num = (Real)1.0 / MathR.Sqrt(num2); X *= num; Y *= num; Z *= num; @@ -429,18 +429,18 @@ public static JQuaternion CreateFromMatrix(in JMatrix matrix) /// When the method completes, contains the quaternion representing the rotation. public static void CreateFromMatrix(in JMatrix matrix, out JQuaternion result) { - float t; + Real t; if (matrix.M33 < 0) { if (matrix.M11 > matrix.M22) { - t = 1.0f + matrix.M11 - matrix.M22 - matrix.M33; + t = (Real)1.0 + matrix.M11 - matrix.M22 - matrix.M33; result = new JQuaternion(t, matrix.M21 + matrix.M12, matrix.M31 + matrix.M13, matrix.M32 - matrix.M23); } else { - t = 1.0f - matrix.M11 + matrix.M22 - matrix.M33; + t = (Real)1.0 - matrix.M11 + matrix.M22 - matrix.M33; result = new JQuaternion(matrix.M21 + matrix.M12, t, matrix.M32 + matrix.M23, matrix.M13 - matrix.M31); } } @@ -448,17 +448,17 @@ public static void CreateFromMatrix(in JMatrix matrix, out JQuaternion result) { if (matrix.M11 < -matrix.M22) { - t = 1.0f - matrix.M11 - matrix.M22 + matrix.M33; + t = (Real)1.0 - matrix.M11 - matrix.M22 + matrix.M33; result = new JQuaternion(matrix.M13 + matrix.M31, matrix.M32 + matrix.M23, t, matrix.M21 - matrix.M12); } else { - t = 1.0f + matrix.M11 + matrix.M22 + matrix.M33; + t = (Real)1.0 + matrix.M11 + matrix.M22 + matrix.M33; result = new JQuaternion(matrix.M32 - matrix.M23, matrix.M13 - matrix.M31, matrix.M21 - matrix.M12, t); } } - t = (float)(0.5d / Math.Sqrt(t)); + t = (Real)(0.5d / Math.Sqrt(t)); result.X *= t; result.Y *= t; result.Z *= t; @@ -485,7 +485,7 @@ public static void CreateFromMatrix(in JMatrix matrix, out JQuaternion result) /// The quaternion to multiply. /// The scaled quaternion. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static JQuaternion operator *(float value1, in JQuaternion value2) + public static JQuaternion operator *(Real value1, in JQuaternion value2) { Multiply(value2, value1, out JQuaternion result); return result; @@ -498,7 +498,7 @@ public static void CreateFromMatrix(in JMatrix matrix, out JQuaternion result) /// The scalar factor. /// The scaled quaternion. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static JQuaternion operator *(in JQuaternion value1, float value2) + public static JQuaternion operator *(in JQuaternion value1, Real value2) { Multiply(value1, value2, out JQuaternion result); return result; diff --git a/src/Jitter2/LinearMath/JVector.cs b/src/Jitter2/LinearMath/JVector.cs index 2eb96e6c..311357d6 100644 --- a/src/Jitter2/LinearMath/JVector.cs +++ b/src/Jitter2/LinearMath/JVector.cs @@ -28,17 +28,17 @@ namespace Jitter2.LinearMath; /// -/// Represents a three-dimensional vector using three floating-point numbers. +/// Represents a three-dimensional vector with components of type . /// -[StructLayout(LayoutKind.Sequential, Size = 12)] +[StructLayout(LayoutKind.Explicit, Size = 3*sizeof(Real))] public struct JVector { internal static JVector InternalZero; internal static JVector Arbitrary; - public float X; - public float Y; - public float Z; + [FieldOffset(0*sizeof(Real))] public Real X; + [FieldOffset(1*sizeof(Real))] public Real Y; + [FieldOffset(2*sizeof(Real))] public Real Z; public static readonly JVector Zero; public static readonly JVector UnitX; @@ -55,27 +55,27 @@ static JVector() UnitX = new JVector(1, 0, 0); UnitY = new JVector(0, 1, 0); UnitZ = new JVector(0, 0, 1); - MinValue = new JVector(float.MinValue); - MaxValue = new JVector(float.MaxValue); + MinValue = new JVector(Real.MinValue); + MaxValue = new JVector(Real.MaxValue); Arbitrary = new JVector(1, 1, 1); InternalZero = Zero; } - public JVector(float x, float y, float z) + public JVector(Real x, Real y, Real z) { X = x; Y = y; Z = z; } - public void Set(float x, float y, float z) + public void Set(Real x, Real y, Real z) { X = x; Y = y; Z = z; } - public JVector(float xyz) + public JVector(Real xyz) { X = xyz; Y = xyz; @@ -83,24 +83,24 @@ public JVector(float xyz) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe ref float UnsafeGet(int index) + public unsafe ref Real UnsafeGet(int index) { - float* ptr = (float*)Unsafe.AsPointer(ref this); + Real* ptr = (Real*)Unsafe.AsPointer(ref this); return ref ptr[index]; } - public unsafe float this[int i] + public unsafe Real this[int i] { get { - fixed (float* ptr = &X) + fixed (Real* ptr = &X) { return ptr[i]; } } set { - fixed (float* ptr = &X) + fixed (Real* ptr = &X) { ptr[i] = value; } @@ -160,14 +160,14 @@ public static JVector Max(in JVector value1, in JVector value2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static JVector Abs(in JVector value1) { - return new JVector(MathF.Abs(value1.X), MathF.Abs(value1.Y), MathF.Abs(value1.Z)); + return new JVector(MathR.Abs(value1.X), MathR.Abs(value1.Y), MathR.Abs(value1.Z)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float MaxAbs(in JVector value1) + public static Real MaxAbs(in JVector value1) { JVector abs = Abs(value1); - return MathF.Max(MathF.Max(abs.X, abs.Y), abs.Z); + return MathR.Max(MathR.Max(abs.X, abs.Y), abs.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -181,9 +181,9 @@ public static void Max(in JVector value1, in JVector value2, out JVector result) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MakeZero() { - X = 0.0f; - Y = 0.0f; - Z = 0.0f; + X = (Real)0.0; + Y = (Real)0.0; + Z = (Real)0.0; } /// @@ -226,9 +226,9 @@ public static JVector TransposedTransform(in JVector vector, in JQuaternion quat [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(in JVector vector, in JMatrix matrix, out JVector result) { - float num0 = vector.X * matrix.M11 + vector.Y * matrix.M12 + vector.Z * matrix.M13; - float num1 = vector.X * matrix.M21 + vector.Y * matrix.M22 + vector.Z * matrix.M23; - float num2 = vector.X * matrix.M31 + vector.Y * matrix.M32 + vector.Z * matrix.M33; + Real num0 = vector.X * matrix.M11 + vector.Y * matrix.M12 + vector.Z * matrix.M13; + Real num1 = vector.X * matrix.M21 + vector.Y * matrix.M22 + vector.Z * matrix.M23; + Real num2 = vector.X * matrix.M31 + vector.Y * matrix.M32 + vector.Z * matrix.M33; result.X = num0; result.Y = num1; @@ -241,9 +241,9 @@ public static void Transform(in JVector vector, in JMatrix matrix, out JVector r [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void TransposedTransform(in JVector vector, in JMatrix matrix, out JVector result) { - float num0 = vector.X * matrix.M11 + vector.Y * matrix.M21 + vector.Z * matrix.M31; - float num1 = vector.X * matrix.M12 + vector.Y * matrix.M22 + vector.Z * matrix.M32; - float num2 = vector.X * matrix.M13 + vector.Y * matrix.M23 + vector.Z * matrix.M33; + Real num0 = vector.X * matrix.M11 + vector.Y * matrix.M21 + vector.Z * matrix.M31; + Real num1 = vector.X * matrix.M12 + vector.Y * matrix.M22 + vector.Z * matrix.M32; + Real num2 = vector.X * matrix.M13 + vector.Y * matrix.M23 + vector.Z * matrix.M33; result.X = num0; result.Y = num1; @@ -256,13 +256,13 @@ public static void TransposedTransform(in JVector vector, in JMatrix matrix, out [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(in JVector vector, in JQuaternion quaternion, out JVector result) { - float numx = 2.0f * (quaternion.Y * vector.Z - quaternion.Z * vector.Y); - float numy = 2.0f * (quaternion.Z * vector.X - quaternion.X * vector.Z); - float numz = 2.0f * (quaternion.X * vector.Y - quaternion.Y * vector.X); + Real numx = (Real)2.0 * (quaternion.Y * vector.Z - quaternion.Z * vector.Y); + Real numy = (Real)2.0 * (quaternion.Z * vector.X - quaternion.X * vector.Z); + Real numz = (Real)2.0 * (quaternion.X * vector.Y - quaternion.Y * vector.X); - float num00 = quaternion.Y * numz - quaternion.Z * numy; - float num11 = quaternion.Z * numx - quaternion.X * numz; - float num22 = quaternion.X * numy - quaternion.Y * numx; + Real num00 = quaternion.Y * numz - quaternion.Z * numy; + Real num11 = quaternion.Z * numx - quaternion.X * numz; + Real num22 = quaternion.X * numy - quaternion.Y * numx; result.X = vector.X + quaternion.W * numx + num00; result.Y = vector.Y + quaternion.W * numy + num11; @@ -275,13 +275,13 @@ public static void Transform(in JVector vector, in JQuaternion quaternion, out J [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ConjugatedTransform(in JVector vector, in JQuaternion quaternion, out JVector result) { - float numx = 2.0f * (quaternion.Z * vector.Y - quaternion.Y * vector.Z); - float numy = 2.0f * (quaternion.X * vector.Z - quaternion.Z * vector.X); - float numz = 2.0f * (quaternion.Y * vector.X - quaternion.X * vector.Y); + Real numx = (Real)2.0 * (quaternion.Z * vector.Y - quaternion.Y * vector.Z); + Real numy = (Real)2.0 * (quaternion.X * vector.Z - quaternion.Z * vector.X); + Real numz = (Real)2.0 * (quaternion.Y * vector.X - quaternion.X * vector.Y); - float num00 = quaternion.Z * numy - quaternion.Y * numz; - float num11 = quaternion.X * numz - quaternion.Z * numx; - float num22 = quaternion.Y * numx - quaternion.X * numy; + Real num00 = quaternion.Z * numy - quaternion.Y * numz; + Real num11 = quaternion.X * numz - quaternion.Z * numx; + Real num22 = quaternion.Y * numx - quaternion.X * numy; result.X = vector.X + quaternion.W * numx + num00; result.Y = vector.Y + quaternion.W * numy + num11; @@ -308,7 +308,7 @@ public static JMatrix Outer(in JVector u, in JVector v) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Dot(in JVector vector1, in JVector vector2) + public static Real Dot(in JVector vector1, in JVector vector2) { return vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z; } @@ -338,9 +338,9 @@ public static JVector Subtract(JVector value1, JVector value2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Subtract(in JVector value1, in JVector value2, out JVector result) { - float num0 = value1.X - value2.X; - float num1 = value1.Y - value2.Y; - float num2 = value1.Z - value2.Z; + Real num0 = value1.X - value2.X; + Real num1 = value1.Y - value2.Y; + Real num2 = value1.Z - value2.Z; result.X = num0; result.Y = num1; @@ -357,9 +357,9 @@ public static JVector Cross(in JVector vector1, in JVector vector2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Cross(in JVector vector1, in JVector vector2, out JVector result) { - float num0 = vector1.Y * vector2.Z - vector1.Z * vector2.Y; - float num1 = vector1.Z * vector2.X - vector1.X * vector2.Z; - float num2 = vector1.X * vector2.Y - vector1.Y * vector2.X; + Real num0 = vector1.Y * vector2.Z - vector1.Z * vector2.Y; + Real num1 = vector1.Z * vector2.X - vector1.X * vector2.Z; + Real num2 = vector1.X * vector2.Y - vector1.Y * vector2.X; result.X = num0; result.Y = num1; @@ -390,9 +390,9 @@ public static JVector Negate(in JVector value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(in JVector value, out JVector result) { - float num0 = -value.X; - float num1 = -value.Y; - float num2 = -value.Z; + Real num0 = -value.X; + Real num1 = -value.Y; + Real num2 = -value.Z; result.X = num0; result.Y = num1; @@ -409,8 +409,8 @@ public static JVector Normalize(in JVector value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Normalize() { - float num2 = X * X + Y * Y + Z * Z; - float num = 1f / (float)Math.Sqrt(num2); + Real num2 = X * X + Y * Y + Z * Z; + Real num = (Real)1.0 / MathR.Sqrt(num2); X *= num; Y *= num; Z *= num; @@ -419,23 +419,23 @@ public void Normalize() [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(in JVector value, out JVector result) { - float num2 = value.X * value.X + value.Y * value.Y + value.Z * value.Z; - float num = 1f / (float)Math.Sqrt(num2); + Real num2 = value.X * value.X + value.Y * value.Y + value.Z * value.Z; + Real num = (Real)1.0 / MathR.Sqrt(num2); result.X = value.X * num; result.Y = value.Y * num; result.Z = value.Z * num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly float LengthSquared() + public readonly Real LengthSquared() { return X * X + Y * Y + Z * Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly float Length() + public readonly Real Length() { - return MathF.Sqrt(X * X + Y * Y + Z * Z); + return MathR.Sqrt(X * X + Y * Y + Z * Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -445,14 +445,14 @@ public static void Swap(ref JVector vector1, ref JVector vector2) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static JVector Multiply(in JVector value1, float scaleFactor) + public static JVector Multiply(in JVector value1, Real scaleFactor) { Multiply(value1, scaleFactor, out JVector result); return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Multiply(float factor) + public void Multiply(Real factor) { X *= factor; Y *= factor; @@ -460,7 +460,7 @@ public void Multiply(float factor) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Multiply(in JVector value1, float scaleFactor, out JVector result) + public static void Multiply(in JVector value1, Real scaleFactor, out JVector result) { result.X = value1.X * scaleFactor; result.Y = value1.Y * scaleFactor; @@ -481,13 +481,13 @@ public static void Multiply(in JVector value1, float scaleFactor, out JVector re } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float operator *(in JVector vector1, in JVector vector2) + public static Real operator *(in JVector vector1, in JVector vector2) { return vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static JVector operator *(in JVector value1, float value2) + public static JVector operator *(in JVector value1, Real value2) { JVector result; result.X = value1.X * value2; @@ -497,7 +497,7 @@ public static void Multiply(in JVector value1, float scaleFactor, out JVector re } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static JVector operator *(float value1, in JVector value2) + public static JVector operator *(Real value1, in JVector value2) { JVector result; result.X = value2.X * value1; @@ -519,7 +519,7 @@ public static void Multiply(in JVector value1, float scaleFactor, out JVector re [MethodImpl(MethodImplOptions.AggressiveInlining)] public static JVector operator -(in JVector left) { - return Multiply(left, -1.0f); + return Multiply(left, -(Real)1.0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Jitter2/LinearMath/MathHelper.cs b/src/Jitter2/LinearMath/MathHelper.cs index 37bf2779..debd24e6 100644 --- a/src/Jitter2/LinearMath/MathHelper.cs +++ b/src/Jitter2/LinearMath/MathHelper.cs @@ -35,9 +35,9 @@ public static class MathHelper // Line 1: p1 + (p2 - p1)*mua // Line 2: p3 + (p4 - p3)*mub - public static bool LineLineIntersect(in JVector p1, in JVector p2, in JVector p3, in JVector P4, out JVector Pa, out JVector Pb, out float mua, out float mub) + public static bool LineLineIntersect(in JVector p1, in JVector p2, in JVector p3, in JVector P4, out JVector Pa, out JVector Pb, out Real mua, out Real mub) { - const float Epsilon = 1e-12f; + const Real Epsilon = (Real)1e-12; Pa = Pb = JVector.Zero; mua = mub = 0; @@ -46,16 +46,16 @@ public static bool LineLineIntersect(in JVector p1, in JVector p2, in JVector p3 JVector p43 = P4 - p3; JVector p21 = p2 - p1; - float d1343 = p13 * p43; - float d4321 = p43 * p21; - float d1321 = p13 * p21; - float d4343 = p43 * p43; - float d2121 = p21 * p21; + Real d1343 = p13 * p43; + Real d4321 = p43 * p21; + Real d1321 = p13 * p21; + Real d4343 = p43 * p43; + Real d2121 = p21 * p21; - float denom = d2121 * d4343 - d4321 * d4321; + Real denom = d2121 * d4343 - d4321 * d4321; if (Math.Abs(denom) < Epsilon) return false; - float numer = d1343 * d4321 - d1321 * d4343; + Real numer = d1343 * d4321 - d1321 * d4343; mua = numer / denom; mub = (d1343 + d4321 * mua) / d4343; @@ -71,7 +71,7 @@ public static bool LineLineIntersect(in JVector p1, in JVector p2, in JVector p3 /// /// Checks if matrix is a pure rotation matrix. /// - public static bool IsRotationMatrix(in JMatrix matrix, float epsilon = 1e-06f) + public static bool IsRotationMatrix(in JMatrix matrix, Real epsilon = (Real)1e-06) { JMatrix delta = JMatrix.MultiplyTransposed(matrix, matrix) - JMatrix.Identity; @@ -80,25 +80,25 @@ public static bool IsRotationMatrix(in JMatrix matrix, float epsilon = 1e-06f) return false; } - return MathF.Abs(matrix.Determinant() - 1.0f) < epsilon; + return MathR.Abs(matrix.Determinant() - (Real)1.0) < epsilon; } /// /// Checks if all entries of a vector are close to zero. /// - public static bool IsZero(in JVector vector, float epsilon = 1e-6f) + public static bool IsZero(in JVector vector, Real epsilon = (Real)1e-6) { - float x = MathF.Abs(vector.X); - float y = MathF.Abs(vector.Y); - float z = MathF.Abs(vector.Z); + Real x = MathR.Abs(vector.X); + Real y = MathR.Abs(vector.Y); + Real z = MathR.Abs(vector.Z); - return MathF.Max(x, MathF.Max(y, z)) < epsilon; + return MathR.Max(x, MathR.Max(y, z)) < epsilon; } /// /// Checks if all entries of a matrix are close to zero. /// - public static bool UnsafeIsZero(ref JMatrix matrix, float epsilon = 1e-6f) + public static bool UnsafeIsZero(ref JMatrix matrix, Real epsilon = (Real)1e-6) { if (!IsZero(matrix.UnsafeGet(0), epsilon)) return false; if (!IsZero(matrix.UnsafeGet(1), epsilon)) return false; @@ -112,7 +112,7 @@ public static bool UnsafeIsZero(ref JMatrix matrix, float epsilon = 1e-6f) /// The number of Jacobi iterations. public static JMatrix InverseSquareRoot(JMatrix m, int sweeps = 2) { - float phi, cp, sp; + Real phi, cp, sp; Unsafe.SkipInit(out JMatrix r); JMatrix rotation = JMatrix.Identity; @@ -120,10 +120,10 @@ public static JMatrix InverseSquareRoot(JMatrix m, int sweeps = 2) for (int i = 0; i < sweeps; i++) { // M32 - if (MathF.Abs(m.M23) > 1e-6f) + if (MathR.Abs(m.M23) > (Real)1e-6) { - phi = MathF.Atan2(1, (m.M33 - m.M22) / (2.0f * m.M23)) / 2.0f; - (sp, cp) = MathF.SinCos(phi); + phi = MathR.Atan2(1, (m.M33 - m.M22) / ((Real)2.0 * m.M23)) / (Real)2.0; + (sp, cp) = MathR.SinCos(phi); r = new JMatrix(1, 0, 0, 0, cp, sp, 0, -sp, cp); JMatrix.Multiply(m, r, out m); JMatrix.TransposedMultiply(r, m, out m); @@ -131,10 +131,10 @@ public static JMatrix InverseSquareRoot(JMatrix m, int sweeps = 2) } // M21 - if (MathF.Abs(m.M21) > 1e-6f) + if (MathR.Abs(m.M21) > (Real)1e-6) { - phi = MathF.Atan2(1, (m.M22 - m.M11) / (2.0f * m.M21)) / 2.0f; - (sp, cp) = MathF.SinCos(phi); + phi = MathR.Atan2(1, (m.M22 - m.M11) / ((Real)2.0 * m.M21)) / (Real)2.0; + (sp, cp) = MathR.SinCos(phi); r = new JMatrix(cp, sp, 0, -sp, cp, 0, 0, 0, 1); JMatrix.Multiply(m, r, out m); JMatrix.TransposedMultiply(r, m, out m); @@ -142,10 +142,10 @@ public static JMatrix InverseSquareRoot(JMatrix m, int sweeps = 2) } // M31 - if (MathF.Abs(m.M31) > 1e-6f) + if (MathR.Abs(m.M31) > (Real)1e-6) { - phi = MathF.Atan2(1, (m.M33 - m.M11) / (2.0f * m.M31)) / 2.0f; - (sp, cp) = MathF.SinCos(phi); + phi = MathR.Atan2(1, (m.M33 - m.M11) / ((Real)2.0 * m.M31)) / (Real)2.0; + (sp, cp) = MathR.SinCos(phi); r = new JMatrix(cp, 0, sp, 0, 1, 0, -sp, 0, cp); JMatrix.Multiply(m, r, out m); JMatrix.TransposedMultiply(r, m, out m); @@ -153,9 +153,9 @@ public static JMatrix InverseSquareRoot(JMatrix m, int sweeps = 2) } } - JMatrix d = new JMatrix(1.0f / MathF.Sqrt(m.M11), 0, 0, - 0, 1.0f / MathF.Sqrt(m.M22), 0, - 0, 0, 1.0f / MathF.Sqrt(m.M33)); + JMatrix d = new JMatrix((Real)1.0 / MathR.Sqrt(m.M11), 0, 0, + 0, (Real)1.0 / MathR.Sqrt(m.M22), 0, + 0, 0, (Real)1.0 / MathR.Sqrt(m.M33)); return rotation * d * JMatrix.Transpose(rotation); } @@ -172,9 +172,9 @@ public static JVector CreateOrthonormal(in JVector vec) Debug.Assert(!CloseToZero(vec)); - float xa = Math.Abs(vec.X); - float ya = Math.Abs(vec.Y); - float za = Math.Abs(vec.Z); + Real xa = Math.Abs(vec.X); + Real ya = Math.Abs(vec.Y); + Real za = Math.Abs(vec.Z); if ((xa > ya && xa > za) || (ya > xa && ya > za)) { @@ -191,7 +191,7 @@ public static JVector CreateOrthonormal(in JVector vec) result.Normalize(); - Debug.Assert(MathF.Abs(JVector.Dot(result, vec)) < 1e-6f); + Debug.Assert(MathR.Abs(JVector.Dot(result, vec)) < (Real)1e-6); return result; } @@ -202,7 +202,7 @@ public static JVector CreateOrthonormal(in JVector vec) /// /// The input matrix to check for an orthonormal basis. /// True if the columns of the matrix form an orthonormal basis; otherwise, false. - public static bool CheckOrthonormalBasis(in JMatrix matrix, float epsilon = 1e-6f) + public static bool CheckOrthonormalBasis(in JMatrix matrix, Real epsilon = (Real)1e-6) { JMatrix delta = JMatrix.MultiplyTransposed(matrix, matrix) - JMatrix.Identity; return UnsafeIsZero(ref delta, epsilon); @@ -215,7 +215,7 @@ public static bool CheckOrthonormalBasis(in JMatrix matrix, float epsilon = 1e-6 /// A threshold value below which the squared magnitude of the vector /// is considered to be zero or close to zero. /// True if the vector is close to zero; otherwise, false. - public static bool CloseToZero(in JVector v, float epsilonSq = 1e-16f) + public static bool CloseToZero(in JVector v, Real epsilonSq = (Real)1e-16) { return v.LengthSquared() < epsilonSq; } diff --git a/src/Jitter2/Precision.cs b/src/Jitter2/Precision.cs new file mode 100644 index 00000000..275b0608 --- /dev/null +++ b/src/Jitter2/Precision.cs @@ -0,0 +1,62 @@ +/* + * Copyright (c) Thorben Linneweber and others + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// Uncomment here to build Jitter using double precision +// -------------------------------------------------------- +// #define USE_DOUBLE_PRECISION +// -------------------------------------------------------- +// Or use command line option, e.g. +// dotnet build -c Release -p:DoublePrecision=true + +#if USE_DOUBLE_PRECISION + +global using Real = System.Double; +global using MathR = System.Math; +global using Vector = System.Runtime.Intrinsics.Vector256; +global using VectorReal = System.Runtime.Intrinsics.Vector256; + +#else + +global using Real = System.Single; +global using MathR = System.MathF; +global using Vector = System.Runtime.Intrinsics.Vector128; +global using VectorReal = System.Runtime.Intrinsics.Vector128; + +#endif + +namespace Jitter2; +public static class Precision +{ + #if USE_DOUBLE_PRECISION + public const int ConstraintSizeFull = 512; + public const int ConstraintSizeSmall = 256; + #else + public const int ConstraintSizeFull = 256; + public const int ConstraintSizeSmall = 128; + #endif + + /// + /// Gets a value indicating whether the engine is configured to use double-precision floating-point numbers. + /// + public static bool IsDoublePrecision => sizeof(Real) == sizeof(double); +} \ No newline at end of file diff --git a/src/Jitter2/SoftBodies/BroadPhaseCollisionFilter.cs b/src/Jitter2/SoftBodies/BroadPhaseCollisionFilter.cs index 5c0acc48..63f8375b 100644 --- a/src/Jitter2/SoftBodies/BroadPhaseCollisionFilter.cs +++ b/src/Jitter2/SoftBodies/BroadPhaseCollisionFilter.cs @@ -52,7 +52,7 @@ public bool Filter(IDynamicTreeProxy proxyA, IDynamicTreeProxy proxyB) bool colliding = NarrowPhase.MPREPA(i1, i2, JQuaternion.Identity, JVector.Zero, - out JVector pA, out JVector pB, out JVector normal, out float penetration); + out JVector pA, out JVector pB, out JVector normal, out Real penetration); if (!colliding) return false; @@ -72,7 +72,7 @@ public bool Filter(IDynamicTreeProxy proxyA, IDynamicTreeProxy proxyB) if (!i1.SoftBody.IsActive && !rb.Data.IsActive) return false; bool colliding = NarrowPhase.MPREPA(i1, (proxyB as RigidBodyShape)!, rb.Orientation, rb.Position, - out JVector pA, out JVector pB, out JVector normal, out float penetration); + out JVector pA, out JVector pB, out JVector normal, out Real penetration); if (!colliding) return false; @@ -91,7 +91,7 @@ public bool Filter(IDynamicTreeProxy proxyA, IDynamicTreeProxy proxyB) if (!i2.SoftBody.IsActive && !ra.Data.IsActive) return false; bool colliding = NarrowPhase.MPREPA(i2, (proxyA as RigidBodyShape)!, ra.Orientation, ra.Position, - out JVector pA, out JVector pB, out JVector normal, out float penetration); + out JVector pA, out JVector pB, out JVector normal, out Real penetration); if (!colliding) return false; diff --git a/src/Jitter2/SoftBodies/SoftBody.cs b/src/Jitter2/SoftBodies/SoftBody.cs index c4fc9eb0..ea0ea34d 100644 --- a/src/Jitter2/SoftBodies/SoftBody.cs +++ b/src/Jitter2/SoftBodies/SoftBody.cs @@ -65,7 +65,7 @@ public void Destroy() private bool active = true; - protected virtual void WorldOnPostStep(float dt) + protected virtual void WorldOnPostStep(Real dt) { if (IsActive == active) return; active = IsActive; diff --git a/src/Jitter2/SoftBodies/SoftBodyShape.cs b/src/Jitter2/SoftBodies/SoftBodyShape.cs index 1afeee22..cdf80515 100644 --- a/src/Jitter2/SoftBodies/SoftBodyShape.cs +++ b/src/Jitter2/SoftBodies/SoftBodyShape.cs @@ -33,7 +33,7 @@ public abstract class SoftBodyShape : Shape public abstract RigidBody GetClosest(in JVector pos); public SoftBody SoftBody { get; internal init; } = null!; - public override bool RayCast(in JVector origin, in JVector direction, out JVector normal, out float lambda) + public override bool RayCast(in JVector origin, in JVector direction, out JVector normal, out Real lambda) { return NarrowPhase.RayCast(this, origin, direction, out lambda, out normal); } diff --git a/src/Jitter2/SoftBodies/SoftBodyTetrahedron.cs b/src/Jitter2/SoftBodies/SoftBodyTetrahedron.cs index 26144ff3..d90b13f6 100644 --- a/src/Jitter2/SoftBodies/SoftBodyTetrahedron.cs +++ b/src/Jitter2/SoftBodies/SoftBodyTetrahedron.cs @@ -53,7 +53,7 @@ public override JVector Velocity vel += Vertices[i].Velocity; } - vel *= 0.25f; + vel *= (Real)0.25; return vel; } @@ -61,12 +61,12 @@ public override JVector Velocity public override RigidBody GetClosest(in JVector pos) { - float dist = float.MaxValue; + Real dist = Real.MaxValue; int closest = 0; for (int i = 0; i < 4; i++) { - float len = (pos - Vertices[i].Position).LengthSquared(); + Real len = (pos - Vertices[i].Position).LengthSquared(); if (len < dist) { dist = len; @@ -79,12 +79,12 @@ public override RigidBody GetClosest(in JVector pos) public override void SupportMap(in JVector direction, out JVector result) { - float maxDot = float.MinValue; + Real maxDot = Real.MinValue; int furthest = 0; for (int i = 0; i < 4; i++) { - float dot = JVector.Dot(direction, Vertices[i].Position); + Real dot = JVector.Dot(direction, Vertices[i].Position); if (dot > maxDot) { maxDot = dot; @@ -97,13 +97,13 @@ public override void SupportMap(in JVector direction, out JVector result) public override void GetCenter(out JVector point) { - point = 0.25f * (Vertices[0].Position + Vertices[1].Position + + point = (Real)0.25 * (Vertices[0].Position + Vertices[1].Position + Vertices[2].Position + Vertices[3].Position); } - public override void UpdateWorldBoundingBox(float dt = 0.0f) + public override void UpdateWorldBoundingBox(Real dt = (Real)0.0) { - const float extraMargin = 0.01f; + const Real extraMargin = (Real)0.01; JBBox box = JBBox.SmallBox; box.AddPoint(Vertices[0].Position); diff --git a/src/Jitter2/SoftBodies/SoftBodyTriangle.cs b/src/Jitter2/SoftBodies/SoftBodyTriangle.cs index d8a06d76..74619371 100644 --- a/src/Jitter2/SoftBodies/SoftBodyTriangle.cs +++ b/src/Jitter2/SoftBodies/SoftBodyTriangle.cs @@ -37,12 +37,12 @@ public class SoftBodyTriangle : SoftBodyShape public RigidBody Vertex2 => v2; public RigidBody Vertex3 => v3; - private float halfThickness = 0.05f; + private Real halfThickness = (Real)0.05; - public float Thickness + public Real Thickness { - get => halfThickness * 2.0f; - set => halfThickness = value * 0.5f; + get => halfThickness * (Real)2.0; + set => halfThickness = value * (Real)0.5; } public SoftBodyTriangle(SoftBody body, RigidBody v1, RigidBody v2, RigidBody v3) @@ -55,13 +55,13 @@ public SoftBodyTriangle(SoftBody body, RigidBody v1, RigidBody v2, RigidBody v3) UpdateWorldBoundingBox(); } - public override JVector Velocity => 1.0f / 3.0f * (v1.Data.Velocity + v2.Data.Velocity + v3.Data.Velocity); + public override JVector Velocity => (Real)(1.0 / 3.0) * (v1.Data.Velocity + v2.Data.Velocity + v3.Data.Velocity); public override RigidBody GetClosest(in JVector pos) { - float len1 = (pos - v1.Position).LengthSquared(); - float len2 = (pos - v2.Position).LengthSquared(); - float len3 = (pos - v3.Position).LengthSquared(); + Real len1 = (pos - v1.Position).LengthSquared(); + Real len2 = (pos - v2.Position).LengthSquared(); + Real len3 = (pos - v3.Position).LengthSquared(); if (len1 < len2 && len1 < len3) { @@ -76,9 +76,9 @@ public override RigidBody GetClosest(in JVector pos) return v3; } - public override void UpdateWorldBoundingBox(float dt = 0.0f) + public override void UpdateWorldBoundingBox(Real dt = (Real)0.0) { - float extraMargin = MathF.Max(halfThickness, 0.01f); + Real extraMargin = MathR.Max(halfThickness, (Real)0.01); JBBox box = JBBox.SmallBox; @@ -100,8 +100,8 @@ public override void SupportMap(in JVector direction, out JVector result) JVector b = v2.Position; JVector c = v3.Position; - float min = JVector.Dot(a, direction); - float dot = JVector.Dot(b, direction); + Real min = JVector.Dot(a, direction); + Real dot = JVector.Dot(b, direction); result = a; @@ -123,6 +123,6 @@ public override void SupportMap(in JVector direction, out JVector result) public override void GetCenter(out JVector point) { - point = (1.0f / 3.0f) * (Vertex1.Position + Vertex2.Position + Vertex3.Position); + point = ((Real)(1.0 / 3.0)) * (Vertex1.Position + Vertex2.Position + Vertex3.Position); } } \ No newline at end of file diff --git a/src/Jitter2/SoftBodies/SpringConstraint.cs b/src/Jitter2/SoftBodies/SpringConstraint.cs index 2763f596..cef6920a 100644 --- a/src/Jitter2/SoftBodies/SpringConstraint.cs +++ b/src/Jitter2/SoftBodies/SpringConstraint.cs @@ -43,7 +43,7 @@ public struct SpringData { internal int _internal; public delegate* Iterate; - public delegate* PrepareForIteration; + public delegate* PrepareForIteration; public JHandle Body1; public JHandle Body2; @@ -51,13 +51,13 @@ public struct SpringData public JVector LocalAnchor1; public JVector LocalAnchor2; - public float BiasFactor; - public float Softness; - public float Distance; + public Real BiasFactor; + public Real Softness; + public Real Distance; - public float EffectiveMass; - public float AccumulatedImpulse; - public float Bias; + public Real EffectiveMass; + public Real AccumulatedImpulse; + public Real Bias; public JVector Jacobian; } @@ -88,12 +88,12 @@ public void Initialize(JVector anchor1, JVector anchor2) JVector.Subtract(anchor1, body1.Position, out data.LocalAnchor1); JVector.Subtract(anchor2, body2.Position, out data.LocalAnchor2); - data.Softness = 0.001f; - data.BiasFactor = 0.2f; + data.Softness = (Real)0.001; + data.BiasFactor = (Real)0.2; data.Distance = (anchor2 - anchor1).Length(); } - public float Impulse + public Real Impulse { get { @@ -136,7 +136,7 @@ public JVector Anchor2 } } - public float TargetDistance + public Real TargetDistance { set { @@ -146,7 +146,7 @@ public float TargetDistance get => handle.Data.Distance; } - public float Distance + public Real Distance { get { @@ -166,7 +166,7 @@ public float Distance } } - public static void PrepareForIteration(ref ConstraintData constraint, float idt) + public static void PrepareForIteration(ref ConstraintData constraint, Real idt) { ref SpringData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref data.Body1.Data; @@ -180,15 +180,15 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) JVector.Subtract(p2, p1, out JVector dp); - float error = dp.Length() - data.Distance; + Real error = dp.Length() - data.Distance; JVector n = p2 - p1; - if (n.LengthSquared() != 0.0f) n.Normalize(); + if (n.LengthSquared() != (Real)0.0) n.Normalize(); data.Jacobian = n; data.EffectiveMass = body1.InverseMass + body2.InverseMass; data.EffectiveMass += data.Softness * idt; - data.EffectiveMass = 1.0f / data.EffectiveMass; + data.EffectiveMass = (Real)1.0 / data.EffectiveMass; data.Bias = error * data.BiasFactor * idt; @@ -196,31 +196,31 @@ public static void PrepareForIteration(ref ConstraintData constraint, float idt) body2.Velocity += body2.InverseMass * data.AccumulatedImpulse * data.Jacobian; } - public float Softness + public Real Softness { get => handle.Data.Softness; set => handle.Data.Softness = value; } - public float Bias + public Real Bias { get => handle.Data.BiasFactor; set => handle.Data.BiasFactor = value; } - public static void Iterate(ref ConstraintData constraint, float idt) + public static void Iterate(ref ConstraintData constraint, Real idt) { ref SpringData data = ref Unsafe.AsRef(Unsafe.AsPointer(ref constraint)); ref RigidBodyData body1 = ref constraint.Body1.Data; ref RigidBodyData body2 = ref constraint.Body2.Data; - float jv = (body2.Velocity - body1.Velocity) * data.Jacobian; + Real jv = (body2.Velocity - body1.Velocity) * data.Jacobian; - float softnessScalar = data.AccumulatedImpulse * data.Softness * idt; + Real softnessScalar = data.AccumulatedImpulse * data.Softness * idt; - float lambda = -data.EffectiveMass * (jv + data.Bias + softnessScalar); + Real lambda = -data.EffectiveMass * (jv + data.Bias + softnessScalar); - float oldacc = data.AccumulatedImpulse; + Real oldacc = data.AccumulatedImpulse; data.AccumulatedImpulse += lambda; lambda = data.AccumulatedImpulse - oldacc; diff --git a/src/Jitter2/UnmanagedMemory/MemoryHelper.cs b/src/Jitter2/UnmanagedMemory/MemoryHelper.cs index 4600d190..84ff3703 100644 --- a/src/Jitter2/UnmanagedMemory/MemoryHelper.cs +++ b/src/Jitter2/UnmanagedMemory/MemoryHelper.cs @@ -28,54 +28,81 @@ namespace Jitter2.UnmanagedMemory; public static unsafe class MemoryHelper { /// - /// A block of 32 bytes of memory. + /// A memory block with a size equivalent to six instances of the type. /// - [StructLayout(LayoutKind.Sequential, Size = 16)] - public struct MemBlock16 - { - } + /// + /// The struct uses sequential layout and a fixed size to ensure consistent memory alignment and layout. + /// + [StructLayout(LayoutKind.Sequential, Size = 6 * sizeof(Real))] + public struct MemBlock6Real { } /// - /// A block of 32 bytes of memory. + /// A memory block with a size equivalent to nine instances of the type. /// - [StructLayout(LayoutKind.Sequential, Size = 32)] - public struct MemBlock32 - { - } + /// + /// The struct uses sequential layout and a fixed size to ensure consistent memory alignment and layout. + /// + [StructLayout(LayoutKind.Sequential, Size = 9 * sizeof(Real))] + public struct MemBlock9Real { } /// - /// A block of 48 bytes of memory. + /// A memory block with a size equivalent to twelve instances of the type. /// - [StructLayout(LayoutKind.Sequential, Size = 48)] - public struct MemBlock48 - { - } + /// + /// The struct uses sequential layout and a fixed size to ensure consistent memory alignment and layout. + /// + [StructLayout(LayoutKind.Sequential, Size = 12 * sizeof(Real))] + public struct MemBlock12Real { } /// - /// A block of 64 bytes of memory. + /// A memory block with a size equivalent to twelve instances of the type. /// - [StructLayout(LayoutKind.Sequential, Size = 64)] - public struct MemBlock64 - { - } + /// + /// The struct uses sequential layout and a fixed size to ensure consistent memory alignment and layout. + /// + [StructLayout(LayoutKind.Sequential, Size = 16 * sizeof(Real))] + public struct MemBlock16Real { } + /// + /// Allocates a block of unmanaged memory for an array of the specified type. + /// + /// The unmanaged type of the elements to allocate memory for. + /// The number of elements to allocate memory for. + /// A pointer to the allocated memory block. public static T* AllocateHeap(int num) where T : unmanaged { return (T*)AllocateHeap(num * sizeof(T)); } + /// + /// Frees a block of unmanaged memory previously allocated for an array of the specified type. + /// + /// The unmanaged type of the elements in the memory block. + /// A pointer to the memory block to free. public static void Free(T* ptr) where T : unmanaged { Free((void*)ptr); } + /// + /// Allocates a block of unmanaged memory of the specified length in bytes. + /// + /// The length of the memory block to allocate, in bytes. + /// A pointer to the allocated memory block. public static void* AllocateHeap(int len) => NativeMemory.Alloc((nuint)len); + + /// + /// Frees a block of unmanaged memory previously allocated. + /// + /// A pointer to the memory block to free. public static void Free(void* ptr) => NativeMemory.Free(ptr); /// /// Zeros out unmanaged memory. /// - public static void Memset(void* buffer, int len) + /// A pointer to the memory block to zero out. + /// The length of the memory block to zero out, in bytes. + public static void MemSet(void* buffer, int len) { for (int i = 0; i < len; i++) { diff --git a/src/Jitter2/UnmanagedMemory/UnmanagedActiveList.cs b/src/Jitter2/UnmanagedMemory/UnmanagedActiveList.cs index e1465073..6e8afb08 100644 --- a/src/Jitter2/UnmanagedMemory/UnmanagedActiveList.cs +++ b/src/Jitter2/UnmanagedMemory/UnmanagedActiveList.cs @@ -244,7 +244,7 @@ public JHandle Allocate(bool active = false, bool clear = false) if (clear) { - MemoryHelper.Memset((byte*)handles[hdl] + sizeof(IntPtr), + MemoryHelper.MemSet((byte*)handles[hdl] + sizeof(IntPtr), sizeof(T) - sizeof(IntPtr)); } diff --git a/src/Jitter2/World.Detect.cs b/src/Jitter2/World.Detect.cs index 09b35f2f..de877d2a 100644 --- a/src/Jitter2/World.Detect.cs +++ b/src/Jitter2/World.Detect.cs @@ -49,7 +49,7 @@ private struct ConvexHullIntersection private void PushLeft(Span left, in JVector v) { - const float epsilon = 0.001f; + const Real epsilon = (Real)0.001; if (leftCount > 0) { @@ -66,7 +66,7 @@ private void PushLeft(Span left, in JVector v) private void PushRight(Span right, in JVector v) { - const float epsilon = 0.001f; + const Real epsilon = (Real)0.001; if (rightCount > 0) { @@ -90,7 +90,7 @@ public void Reset() [System.Runtime.CompilerServices.SkipLocalsInit] public void BuildManifold(RigidBodyShape shapeA, RigidBodyShape shapeB, - in JVector pA, in JVector pB, in JVector normal, float penetration) + in JVector pA, in JVector pB, in JVector normal, Real penetration) { manifoldData ??= new JVector[12]; Reset(); @@ -109,15 +109,15 @@ static void Support(RigidBodyShape shape, in JVector direction, out JVector v) Span left = stackalloc JVector[6]; Span right = stackalloc JVector[6]; - const float sqrt3Over2 = 0.8660254f; + const Real sqrt3Over2 = (Real)0.8660254; - Span hexagonVertices = stackalloc float[] - { 1f, 0f, 0.5f, sqrt3Over2, -0.5f, sqrt3Over2, -1f, 0f, -0.5f, -sqrt3Over2, 0.5f, -sqrt3Over2 }; + Span hexagonVertices = stackalloc Real[] + {(Real)1,(Real)0, (Real)0.5, sqrt3Over2, -(Real)0.5, sqrt3Over2, -1f,(Real)0, -(Real)0.5, -sqrt3Over2, (Real)0.5, -sqrt3Over2 }; for (int e = 0; e < 6; e++) { - JVector ptNormal = normal + hexagonVertices[2 * e + 0] * 0.01f * crossVector1 + - hexagonVertices[2 * e + 1] * 0.01f * crossVector2; + JVector ptNormal = normal + hexagonVertices[2 * e + 0] * (Real)0.01 * crossVector1 + + hexagonVertices[2 * e + 1] * (Real)0.01 * crossVector2; Support(shapeA, ptNormal, out JVector np1); PushLeft(left, np1); @@ -151,13 +151,13 @@ static void Support(RigidBodyShape shape, in JVector direction, out JVector v) JVector cr2 = (b - a) % (p - a); - sameSign = JVector.Dot(cr, cr2) > 1e-3f; + sameSign = JVector.Dot(cr, cr2) > (Real)1e-3; if (!sameSign) break; } if (sameSign) { - float diff = JVector.Dot(p - pA, normal); + Real diff = JVector.Dot(p - pA, normal); mB[manifoldCount] = p; mA[manifoldCount++] = p - diff * normal; @@ -186,13 +186,13 @@ static void Support(RigidBodyShape shape, in JVector direction, out JVector v) JVector cr2 = (b - a) % (p - a); - sameSign = JVector.Dot(cr, cr2) > 1e-3f; + sameSign = JVector.Dot(cr, cr2) > (Real)1e-3; if (!sameSign) break; } if (sameSign) { - float diff = JVector.Dot(p - pB, normal); + Real diff = JVector.Dot(p - pB, normal); mA[manifoldCount] = p; mB[manifoldCount++] = p - diff * normal; @@ -239,7 +239,7 @@ public InvalidCollisionTypeException(Type proxyA, Type proxyB) /// obstacle just touch after the next velocity integration). A value below 1 is preferred, as the leftover velocity /// might be sufficient to trigger another speculative contact in the next frame. /// - public float SpeculativeRelaxationFactor { get; set; } = 0.9f; + public Real SpeculativeRelaxationFactor { get; set; } = (Real)0.9; /// /// Speculative contacts are generated when the velocity towards an obstacle exceeds @@ -247,11 +247,11 @@ public InvalidCollisionTypeException(Type proxyA, Type proxyB) /// threshold should be set to approximately D / timestep, e.g., 100 for a unit cube and a /// timestep of 0.01s. /// - public float SpeculativeVelocityThreshold { get; set; } = 10f; + public Real SpeculativeVelocityThreshold { get; set; } =(Real)10; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RegisterContact(Arbiter arbiter, in JVector point1, in JVector point2, - in JVector normal, float penetration, bool speculative = false) + in JVector normal, Real penetration, bool speculative = false) { lock (arbiter) { @@ -263,7 +263,7 @@ public void RegisterContact(Arbiter arbiter, in JVector point1, in JVector point } public void RegisterContact(ulong id0, ulong id1, RigidBody body1, RigidBody body2, - in JVector point1, in JVector point2, in JVector normal, float penetration, bool speculative = false) + in JVector point1, in JVector point2, in JVector normal, Real penetration, bool speculative = false) { GetArbiter(id0, id1, body1, body2, out Arbiter arbiter); RegisterContact(arbiter, point1, point2, normal, penetration, speculative); @@ -296,7 +296,7 @@ private void Detect(IDynamicTreeProxy proxyA, IDynamicTreeProxy proxyB) Unsafe.SkipInit(out JVector normal); Unsafe.SkipInit(out JVector pA); Unsafe.SkipInit(out JVector pB); - float penetration; + Real penetration; Debug.Assert(sA.RigidBody != sB.RigidBody); Debug.Assert(sA.RigidBody.World == this); @@ -320,7 +320,7 @@ private void Detect(IDynamicTreeProxy proxyA, IDynamicTreeProxy proxyB) if (!success) return; - colliding = penetration >= 0.0f; + colliding = penetration >= (Real)0.0; } else { @@ -338,9 +338,9 @@ private void Detect(IDynamicTreeProxy proxyA, IDynamicTreeProxy proxyB) bool success = NarrowPhase.Sweep(sA, sB, b1.Orientation, b2.Orientation, b1.Position, b2.Position,b1.Velocity, b2.Velocity, - out pA, out pB, out normal, out float toi); + out pA, out pB, out normal, out Real toi); - if (!success || toi > step_dt || toi == 0.0f) return; + if (!success || toi > step_dt || toi == (Real)0.0) return; penetration = normal * (pA - pB) * SpeculativeRelaxationFactor; @@ -401,8 +401,8 @@ private void Detect(IDynamicTreeProxy proxyA, IDynamicTreeProxy proxyB) JVector mfA = cvh.ManifoldA[e]; JVector mfB = cvh.ManifoldB[e]; - float nd = JVector.Dot(mfA - mfB, normal); - if (nd < 0.0f) continue; + Real nd = JVector.Dot(mfA - mfB, normal); + if (nd < (Real)0.0) continue; arbiter.Handle.Data.AddContact(mfA, mfB, normal, nd); } diff --git a/src/Jitter2/World.Step.cs b/src/Jitter2/World.Step.cs index 6c18a22c..09d7190e 100644 --- a/src/Jitter2/World.Step.cs +++ b/src/Jitter2/World.Step.cs @@ -90,7 +90,7 @@ public enum Timings } /// - /// Contains timings for the stages of the last call to . + /// Contains timings for the stages of the last call to . /// Array elements correspond to the enums in . Can be used to identify /// bottlenecks. /// @@ -101,16 +101,16 @@ public enum Timings /// /// The duration of time to simulate. This should remain fixed and not exceed 1/60 of a second. /// Indicates whether multithreading should be utilized. The behavior of the engine can be modified using . - public void Step(float dt, bool multiThread = true) + public void Step(Real dt, bool multiThread = true) { AssertNullBody(); - if (dt < 0.0f) + if (dt < (Real)0.0) { throw new ArgumentException("Time step cannot be negative.", nameof(dt)); } - if (dt == 0.0f) return; // nothing to do + if (dt == (Real)0.0) return; // nothing to do long time = Stopwatch.GetTimestamp(); double invFrequency = 1.0d / Stopwatch.Frequency; @@ -188,7 +188,7 @@ void SetTime(Timings type) // substep_dt = +dt; // Integrate(multiThread); ForeachActiveBody(multiThread); - + SetTime(Timings.UpdateBodies); // Perform collision detection. @@ -260,7 +260,7 @@ private void UpdateBodiesCallback(Parallel.Batch batch) private void PrepareContactsCallback(Parallel.Batch batch) { - float istep_dt = 1.0f / step_dt; + Real istep_dt = (Real)1.0 / step_dt; var span = memContacts.Active[batch.Start..batch.End]; @@ -286,7 +286,7 @@ private void PrepareContactsCallback(Parallel.Batch batch) private unsafe void PrepareSmallConstraintsCallback(Parallel.Batch batch) { - float istep_dt = 1.0f / step_dt; + Real istep_dt = (Real)1.0 / step_dt; var span = memSmallConstraints.Active[batch.Start..batch.End]; @@ -308,7 +308,7 @@ private unsafe void PrepareSmallConstraintsCallback(Parallel.Batch batch) private unsafe void IterateSmallConstraintsCallback(Parallel.Batch batch) { - float istep_dt = 1.0f / step_dt; + Real istep_dt = (Real)1.0 / step_dt; var span = memSmallConstraints.Active[batch.Start..batch.End]; @@ -328,7 +328,7 @@ private unsafe void IterateSmallConstraintsCallback(Parallel.Batch batch) private unsafe void PrepareConstraintsCallback(Parallel.Batch batch) { - float istep_dt = 1.0f / step_dt; + Real istep_dt = (Real)1.0 / step_dt; var span = memConstraints.Active[batch.Start..batch.End]; @@ -350,7 +350,7 @@ private unsafe void PrepareConstraintsCallback(Parallel.Batch batch) private unsafe void IterateConstraintsCallback(Parallel.Batch batch) { - float istep_dt = 1.0f / step_dt; + Real istep_dt = (Real)1.0 / step_dt; var span = memConstraints.Active[batch.Start..batch.End]; @@ -423,7 +423,7 @@ private void AssertNullBody() { ref RigidBodyData rigidBody = ref NullBody.Data; Debug.Assert(rigidBody.IsStatic); - Debug.Assert(rigidBody.InverseMass == 0.0f); + Debug.Assert(rigidBody.InverseMass == (Real)0.0); Debug.Assert(MathHelper.UnsafeIsZero(ref rigidBody.InverseInertiaWorld)); } @@ -435,7 +435,7 @@ private void ForeachActiveBody(bool multiThread) if (body.IsStatic) { System.Diagnostics.Debug.Assert(MathHelper.UnsafeIsZero(ref body.Data.InverseInertiaWorld)); - System.Diagnostics.Debug.Assert(body.Data.InverseMass == 0.0f); + System.Diagnostics.Debug.Assert(body.Data.InverseMass == (Real)0.0); } } #endif @@ -599,24 +599,24 @@ private void IntegrateCallback(Parallel.Batch batch) rigidBody.Position += lvel * substep_dt; - float angle = avel.Length(); + Real angle = avel.Length(); JVector axis; - if (angle < 0.001f) + if (angle < (Real)0.001) { // use Taylor's expansions of sync function - // axis = body.angularVelocity * (0.5f * timestep - (timestep * timestep * timestep) * (0.020833333333f) * angle * angle); + // axis = body.angularVelocity * ((Real)0.5 * timestep - (timestep * timestep * timestep) * ((Real)0.020833333333) * angle * angle); JVector.Multiply(avel, - 0.5f * substep_dt - substep_dt * substep_dt * substep_dt * 0.020833333333f * angle * angle, + (Real)0.5 * substep_dt - substep_dt * substep_dt * substep_dt * (Real)0.020833333333 * angle * angle, out axis); } else { // sync(fAngle) = sin(c*fAngle)/t - JVector.Multiply(avel, (float)Math.Sin(0.5f * angle * substep_dt) / angle, out axis); + JVector.Multiply(avel, MathR.Sin((Real)0.5 * angle * substep_dt) / angle, out axis); } - JQuaternion dorn = new(axis.X, axis.Y, axis.Z, (float)Math.Cos(angle * substep_dt * 0.5f)); + JQuaternion dorn = new(axis.X, axis.Y, axis.Z, MathR.Cos(angle * substep_dt * (Real)0.5)); //JQuaternion.CreateFromMatrix(rigidBody.Orientation, out JQuaternion ornA); JQuaternion ornA = rigidBody.Orientation; diff --git a/src/Jitter2/World.cs b/src/Jitter2/World.cs index bffda35d..d74bdc6e 100644 --- a/src/Jitter2/World.cs +++ b/src/Jitter2/World.cs @@ -91,7 +91,7 @@ public SpanData(World world) private readonly UnmanagedActiveList memConstraints; private readonly UnmanagedActiveList memSmallConstraints; - public delegate void WorldStep(float dt); + public delegate void WorldStep(Real dt); // Post- and Pre-step public event WorldStep? PreStep; @@ -135,9 +135,9 @@ public static (ulong min, ulong max) RequestId(int count) /// /// Defines the two available thread models. The model keeps the worker - /// threads active continuously, even when the is not in operation, which might + /// threads active continuously, even when the is not in operation, which might /// consume more CPU cycles and possibly affect the performance of other operations such as rendering. However, it ensures that the threads - /// remain 'warm' for the next invocation of . Conversely, the model allows + /// remain 'warm' for the next invocation of . Conversely, the model allows /// the worker threads to yield and undertake other tasks. /// public ThreadModelType ThreadModel { get; set; } = ThreadModelType.Regular; @@ -197,7 +197,7 @@ public static (ulong min, ulong max) RequestId(int count) } /// - /// The number of substeps for each call to . + /// The number of substeps for each call to . /// Substepping is deactivated when set to one. /// public int SubstepCount @@ -215,7 +215,7 @@ public int SubstepCount } } - private JVector gravity = new(0, -9.81f, 0); + private JVector gravity = new(0, -(Real)9.81, 0); /// /// Default gravity, see also . @@ -232,8 +232,8 @@ public JVector Gravity private volatile int velocityRelaxations = 4; private volatile int substeps = 1; - private volatile float substep_dt = 1.0f / 100.0f; - private volatile float step_dt = 1.0f / 100.0f; + private Real substep_dt = (Real)(1.0 / 100.0); + private Real step_dt = (Real)(1.0 / 100.0); /// /// Uses a slower alternative narrow phase collision detection method, instead @@ -392,7 +392,7 @@ internal void ActivateBodyNextStep(RigidBody body) internal void DeactivateBodyNextStep(RigidBody body) { - body.sleepTime = float.PositiveInfinity; + body.sleepTime = Real.PositiveInfinity; } /// diff --git a/src/JitterTests/AddRemoveTests.cs b/src/JitterTests/AddRemoveTests.cs index c05154cf..6e066ca8 100644 --- a/src/JitterTests/AddRemoveTests.cs +++ b/src/JitterTests/AddRemoveTests.cs @@ -29,7 +29,7 @@ public void RemoveStaticShape1() world.BroadPhaseFilter = new FilterOut(staticShape); - world.Step(0.01f); + world.Step((Real)0.01); Assert.That(world.DynamicTree.PotentialPairs.Count == 1); world.Clear(); @@ -47,7 +47,7 @@ public void RemoveStaticShape0() world.BroadPhaseFilter = new FilterOut(staticShape); - world.Step(0.01f); + world.Step((Real)0.01); Assert.That(world.DynamicTree.PotentialPairs.Count == 1); world.Remove(body); @@ -57,6 +57,8 @@ public void RemoveStaticShape0() [TestCase] public void AddRemoveBodies() { + void TinyStep() => world.Step((Real)1e-12); + var bA = world.CreateRigidBody(); bA.AddShape(new SphereShape()); var bB = world.CreateRigidBody(); @@ -69,23 +71,23 @@ public void AddRemoveBodies() bD.AddShape(new SphereShape()); bD.AddShape(new SphereShape()); Assert.That(world.DynamicTree.PotentialPairs.Count == 9); - world.Step(1e-12f); + TinyStep(); Assert.That(world.DynamicTree.PotentialPairs.Count == 9); world.Remove(bB); Assert.That(world.DynamicTree.PotentialPairs.Count == 5); - world.Step(1e-12f); + TinyStep(); bD.RemoveShape(bD.Shapes[0]); Assert.That(world.DynamicTree.PotentialPairs.Count == 3); - world.Step(1e-12f); + TinyStep(); world.Remove(bD); Assert.That(world.DynamicTree.PotentialPairs.Count == 1); - world.Step(1e-12f); + TinyStep(); world.NullBody.AddShape(new SphereShape()); - world.Step(1e-12f); + TinyStep(); Assert.That(world.DynamicTree.PotentialPairs.Count == 3); - world.Step(1e-12f); + TinyStep(); world.Remove(world.NullBody); Assert.That(world.DynamicTree.PotentialPairs.Count == 1); - world.Step(1e-12f); + TinyStep(); } } \ No newline at end of file diff --git a/src/JitterTests/BoundingBoxTests.cs b/src/JitterTests/BoundingBoxTests.cs index 49feb9a7..65fa571a 100644 --- a/src/JitterTests/BoundingBoxTests.cs +++ b/src/JitterTests/BoundingBoxTests.cs @@ -14,10 +14,10 @@ private static void CheckBoundingBox(RigidBodyShape shape) ShapeHelper.CalculateBoundingBox(shape, ori, pos, out JBBox shr); shape.CalculateBoundingBox(ori, pos, out JBBox sbb); - float fraction = shr.GetVolume() / sbb.GetVolume(); + Real fraction = shr.GetVolume() / sbb.GetVolume(); - Assert.That(fraction - 1e-7f, Is.LessThan(1.0f)); - Assert.That(fraction, Is.GreaterThan(0.2f)); + Assert.That(fraction - (Real)1e-7, Is.LessThan((Real)1.0)); + Assert.That(fraction, Is.GreaterThan((Real)0.2)); } [TestCase] diff --git a/src/JitterTests/CollisionTests.cs b/src/JitterTests/CollisionTests.cs index f1e2ac57..0c4861b5 100644 --- a/src/JitterTests/CollisionTests.cs +++ b/src/JitterTests/CollisionTests.cs @@ -13,10 +13,10 @@ public void Setup() [TestCase] public void NoBodyWorldBoundingBox() { - const float boxSize = 10.0f; + const Real boxSize = (Real)10.0; BoxShape shape = new BoxShape(boxSize); - Assert.That(MathHelper.CloseToZero(shape.WorldBoundingBox.Max - shape.Size * 0.5f)); - Assert.That(MathHelper.CloseToZero(shape.WorldBoundingBox.Min + shape.Size * 0.5f)); + Assert.That(MathHelper.CloseToZero(shape.WorldBoundingBox.Max - shape.Size * (Real)0.5)); + Assert.That(MathHelper.CloseToZero(shape.WorldBoundingBox.Min + shape.Size * (Real)0.5)); } [TestCase] @@ -26,24 +26,24 @@ public void OverlapDistanceTest() SphereShape ss = new SphereShape(1); var overlap = NarrowPhase.Overlap(bs, ss, - JQuaternion.CreateRotationX(0.2f), JVector.UnitY * 3.0f); + JQuaternion.CreateRotationX((Real)0.2), JVector.UnitY * (Real)3.0); var separated = NarrowPhase.Distance(bs, ss, - JQuaternion.CreateRotationX(0.2f), JVector.UnitY * 3.0f, - out JVector pA, out JVector pB, out float dist); + JQuaternion.CreateRotationX((Real)0.2), JVector.UnitY * (Real)3.0, + out JVector pA, out JVector pB, out Real dist); Assert.That(!overlap); Assert.That(separated); - Assert.That(MathF.Abs(dist - 1.5f) < 1e-4f); - Assert.That(MathHelper.CloseToZero(pA - new JVector(0, 0.5f, 0), 1e-4f)); - Assert.That(MathHelper.CloseToZero(pB - new JVector(0, 2.0f, 0), 1e-4f)); + Assert.That(MathR.Abs(dist - (Real)1.5) < (Real)1e-4); + Assert.That(MathHelper.CloseToZero(pA - new JVector(0, (Real)0.5, 0), (Real)1e-4)); + Assert.That(MathHelper.CloseToZero(pB - new JVector(0, (Real)2.0, 0), (Real)1e-4)); overlap = NarrowPhase.Overlap(bs, ss, - JQuaternion.CreateRotationX(0.2f), JVector.UnitY * 0.5f); + JQuaternion.CreateRotationX((Real)0.2), JVector.UnitY * (Real)0.5); separated = NarrowPhase.Distance(bs, ss, - JQuaternion.CreateRotationX(0.2f), JVector.UnitY * 0.5f, + JQuaternion.CreateRotationX((Real)0.2), JVector.UnitY * (Real)0.5, out pA, out pB, out dist); Assert.That(overlap); @@ -52,190 +52,190 @@ public void OverlapDistanceTest() JVector delta = new JVector(10, 13, -22); overlap = NarrowPhase.Overlap(ss, ss, - JQuaternion.CreateRotationX(0.2f), delta); + JQuaternion.CreateRotationX((Real)0.2), delta); separated = NarrowPhase.Distance(ss, ss, - JQuaternion.CreateRotationX(0.2f), delta, + JQuaternion.CreateRotationX((Real)0.2), delta, out pA, out pB, out dist); Assert.That(!overlap); Assert.That(separated); - Assert.That(MathF.Abs(dist - delta.Length() + 2) < 1e-4f); - Assert.That(MathHelper.CloseToZero(pA - JVector.Normalize(delta), 1e-4f)); - Assert.That(MathHelper.CloseToZero(pB - delta + JVector.Normalize(delta), 1e-4f)); + Assert.That(MathR.Abs(dist - delta.Length() + 2) < (Real)1e-4); + Assert.That(MathHelper.CloseToZero(pA - JVector.Normalize(delta), (Real)1e-4)); + Assert.That(MathHelper.CloseToZero(pB - delta + JVector.Normalize(delta), (Real)1e-4)); } [TestCase] public void SphereRayCast() { - SphereShape ss = new SphereShape(1.2f); + SphereShape ss = new SphereShape((Real)1.2); - const float epsilon = 1e-12f; + const Real epsilon = (Real)1e-12; - bool hit = ss.LocalRayCast(new JVector(0, 1.2f + 0.25f, 0), -JVector.UnitY, out JVector normal, out float lambda); + bool hit = ss.LocalRayCast(new JVector(0, (Real)1.2 + (Real)0.25, 0), -JVector.UnitY, out JVector normal, out Real lambda); Assert.That(hit); - Assert.That(MathF.Abs(lambda - 0.25f), Is.LessThan(epsilon)); + Assert.That(MathR.Abs(lambda - (Real)0.25), Is.LessThan(epsilon)); Assert.That(MathHelper.CloseToZero(normal - JVector.UnitY)); - hit = ss.LocalRayCast(new JVector(0, 1.2f + 0.25f, 0), -2.0f * JVector.UnitY, out normal, out lambda); + hit = ss.LocalRayCast(new JVector(0, (Real)1.2 + (Real)0.25, 0), -(Real)2.0 * JVector.UnitY, out normal, out lambda); Assert.That(hit); - Assert.That(MathF.Abs(lambda - 0.125f), Is.LessThan(epsilon)); + Assert.That(MathR.Abs(lambda - (Real)0.125), Is.LessThan(epsilon)); Assert.That(MathHelper.CloseToZero(normal - JVector.UnitY)); - hit = ss.LocalRayCast(new JVector(0, 1.2f - 0.25f, 0), -JVector.UnitY, out normal, out lambda); + hit = ss.LocalRayCast(new JVector(0, (Real)1.2 - (Real)0.25, 0), -JVector.UnitY, out normal, out lambda); Assert.That(hit); - Assert.That(MathF.Abs(lambda), Is.LessThan(epsilon)); + Assert.That(MathR.Abs(lambda), Is.LessThan(epsilon)); Assert.That(MathHelper.CloseToZero(normal)); - hit = ss.LocalRayCast(new JVector(0, -1.2f - 0.25f, 0), -JVector.UnitY * 1.1f, out normal, out lambda); + hit = ss.LocalRayCast(new JVector(0, -(Real)1.2 - (Real)0.25, 0), -JVector.UnitY * (Real)1.1, out normal, out lambda); Assert.That(!hit); - Assert.That(MathF.Abs(lambda), Is.LessThan(epsilon)); + Assert.That(MathR.Abs(lambda), Is.LessThan(epsilon)); Assert.That(MathHelper.CloseToZero(normal)); } [TestCase] public void BoxRayCast() { - BoxShape bs = new BoxShape(1.2f * 2.0f); + BoxShape bs = new BoxShape((Real)1.2 * (Real)2.0); - const float epsilon = 1e-12f; + const Real epsilon = (Real)1e-12; - bool hit = bs.LocalRayCast(new JVector(0, 1.2f + 0.25f, 0), -JVector.UnitY, out JVector normal, out float lambda); + bool hit = bs.LocalRayCast(new JVector(0, (Real)1.2 + (Real)0.25, 0), -JVector.UnitY, out JVector normal, out Real lambda); Assert.That(hit); - Assert.That(MathF.Abs(lambda - 0.25f), Is.LessThan(epsilon)); + Assert.That(MathR.Abs(lambda - (Real)0.25), Is.LessThan(epsilon)); Assert.That(MathHelper.CloseToZero(normal - JVector.UnitY)); - hit = bs.LocalRayCast(new JVector(0, 1.2f + 0.25f, 0), -2.0f * JVector.UnitY, out normal, out lambda); + hit = bs.LocalRayCast(new JVector(0, (Real)1.2 + (Real)0.25, 0), -(Real)2.0 * JVector.UnitY, out normal, out lambda); Assert.That(hit); - Assert.That(MathF.Abs(lambda - 0.125f), Is.LessThan(epsilon)); + Assert.That(MathR.Abs(lambda - (Real)0.125), Is.LessThan(epsilon)); Assert.That(MathHelper.CloseToZero(normal - JVector.UnitY)); - hit = bs.LocalRayCast(new JVector(0, 1.2f - 0.25f, 0), -JVector.UnitY, out normal, out lambda); + hit = bs.LocalRayCast(new JVector(0, (Real)1.2 - (Real)0.25, 0), -JVector.UnitY, out normal, out lambda); Assert.That(hit); - Assert.That(MathF.Abs(lambda), Is.LessThan(epsilon)); + Assert.That(MathR.Abs(lambda), Is.LessThan(epsilon)); Assert.That(MathHelper.CloseToZero(normal)); - hit = bs.LocalRayCast(new JVector(0, -1.2f - 0.25f, 0), -JVector.UnitY * 1.1f, out normal, out lambda); + hit = bs.LocalRayCast(new JVector(0, -(Real)1.2 - (Real)0.25, 0), -JVector.UnitY * (Real)1.1, out normal, out lambda); Assert.That(!hit); - Assert.That(MathF.Abs(lambda), Is.LessThan(epsilon)); + Assert.That(MathR.Abs(lambda), Is.LessThan(epsilon)); Assert.That(MathHelper.CloseToZero(normal)); } [TestCase] public void RayCast() { - const float radius = 4; + const Real radius = 4; JVector sp = new JVector(10, 11, 12); JVector op = new JVector(1, 2, 3); SphereShape s1 = new(radius); - bool hit = NarrowPhase.RayCast(s1, JQuaternion.CreateRotationX(0.32f), sp, - op, sp - op, out float lambda, out JVector normal); + bool hit = NarrowPhase.RayCast(s1, JQuaternion.CreateRotationX((Real)0.32), sp, + op, sp - op, out Real lambda, out JVector normal); JVector cn = JVector.Normalize(op - sp); // analytical normal JVector hp = op + (sp - op) * lambda; // hit point Assert.That(hit); - Assert.That(MathHelper.CloseToZero(normal - cn, 1e-6f)); + Assert.That(MathHelper.CloseToZero(normal - cn, (Real)1e-6)); - float distance = (hp - sp).Length(); - Assert.That(MathF.Abs(distance - radius), Is.LessThan(1e-4f)); + Real distance = (hp - sp).Length(); + Assert.That(MathR.Abs(distance - radius), Is.LessThan((Real)1e-4)); } [TestCase] public void SweepTest() { - var s1 = new SphereShape(0.5f); + var s1 = new SphereShape((Real)0.5); var s2 = new BoxShape(1); - var rot = JQuaternion.CreateRotationZ(MathF.PI / 4.0f); + var rot = JQuaternion.CreateRotationZ(MathR.PI / (Real)4.0); var sweep = JVector.Normalize(new JVector(1, 1, 0)); bool hit = NarrowPhase.Sweep(s1, s2, rot, rot, new JVector(1, 1, 3), new JVector(11, 11, 3), - sweep, -2.0f * sweep, - out JVector pA, out JVector pB, out JVector normal, out float lambda); + sweep, -(Real)2.0 * sweep, + out JVector pA, out JVector pB, out JVector normal, out Real lambda); Assert.That(hit); - float expectedlambda = (MathF.Sqrt(200.0f) - 1.0f) * (1.0f / 3.0f); + Real expectedlambda = (MathR.Sqrt((Real)200.0) - (Real)1.0) * ((Real)(1.0 / 3.0)); JVector expectedNormal = JVector.Normalize(new JVector(1, 1, 0)); - JVector expectedPoint = new JVector(1, 1, 3) + expectedNormal * (0.5f + expectedlambda); + JVector expectedPoint = new JVector(1, 1, 3) + expectedNormal * ((Real)0.5 + expectedlambda); JVector expectedPointA = expectedPoint - sweep * lambda; - JVector expectedPointB = expectedPoint + 2.0f * sweep * lambda; + JVector expectedPointB = expectedPoint + (Real)2.0 * sweep * lambda; - Assert.That((normal - expectedNormal).LengthSquared(), Is.LessThan(1e-4f)); - Assert.That((pA - expectedPointA).LengthSquared(), Is.LessThan(1e-4f)); - Assert.That((pB - expectedPointB).LengthSquared(), Is.LessThan(1e-4f)); - Assert.That(MathF.Abs(lambda - expectedlambda), Is.LessThan(1e-4f)); + Assert.That((normal - expectedNormal).LengthSquared(), Is.LessThan((Real)1e-4)); + Assert.That((pA - expectedPointA).LengthSquared(), Is.LessThan((Real)1e-4)); + Assert.That((pB - expectedPointB).LengthSquared(), Is.LessThan((Real)1e-4)); + Assert.That(MathR.Abs(lambda - expectedlambda), Is.LessThan((Real)1e-4)); } [TestCase] public void NormalDirection() { - SphereShape s1 = new(0.5f); - SphereShape s2 = new(0.5f); + SphereShape s1 = new((Real)0.5); + SphereShape s2 = new((Real)0.5); // ----------------------------------------------- - NarrowPhase.MPREPA(s1, s2, JQuaternion.Identity, JQuaternion.Identity, new JVector(-0.25f, 0, 0), new JVector(+0.25f, 0, 0), - out JVector pointA, out JVector pointB, out JVector normal, out float penetration); + NarrowPhase.MPREPA(s1, s2, JQuaternion.Identity, JQuaternion.Identity, new JVector(-(Real)0.25, 0, 0), new JVector(+(Real)0.25, 0, 0), + out JVector pointA, out JVector pointB, out JVector normal, out Real penetration); // pointA is on s1 and pointB is on s2 - Assert.That(pointA.X, Is.GreaterThan(0.0f)); - Assert.That(pointB.X, Is.LessThan(0.0f)); + Assert.That(pointA.X, Is.GreaterThan((Real)0.0)); + Assert.That(pointB.X, Is.LessThan((Real)0.0)); // the collision normal points from s2 to s1 - Assert.That(normal.X, Is.GreaterThan(0.0f)); + Assert.That(normal.X, Is.GreaterThan(0)); // the separation is negative - Assert.That(penetration, Is.GreaterThan(0.0f)); + Assert.That(penetration, Is.GreaterThan(0)); // ----------------------------------------------- - NarrowPhase.Collision(s1, s2, JQuaternion.Identity, JQuaternion.Identity, new JVector(-0.25f, 0, 0), new JVector(+0.25f, 0, 0), + NarrowPhase.Collision(s1, s2, JQuaternion.Identity, JQuaternion.Identity, new JVector(-(Real)0.25, 0, 0), new JVector(+(Real)0.25, 0, 0), out pointA, out pointB, out normal, out penetration); // pointA is on s1 and pointB is on s2 - Assert.That(pointA.X, Is.GreaterThan(0.0f)); - Assert.That(pointB.X, Is.LessThan(0.0f)); + Assert.That(pointA.X, Is.GreaterThan(0)); + Assert.That(pointB.X, Is.LessThan(0)); // the collision normal points from s2 to s1 - Assert.That(normal.X, Is.GreaterThan(0.0f)); + Assert.That(normal.X, Is.GreaterThan(0)); // the separation is negative - Assert.That(penetration, Is.GreaterThan(0.0f)); + Assert.That(penetration, Is.GreaterThan(0)); // ----------------------------------------------- BoxShape b1 = new(1); BoxShape b2 = new(1); - NarrowPhase.MPREPA(b1, b2, JQuaternion.Identity, JQuaternion.Identity, new JVector(-0.25f, 0.1f, 0), new JVector(+0.25f, -0.1f, 0), + NarrowPhase.MPREPA(b1, b2, JQuaternion.Identity, JQuaternion.Identity, new JVector(-(Real)0.25, (Real)0.1, 0), new JVector(+(Real)0.25, -(Real)0.1, 0), out pointA, out pointB, out normal, out penetration); // pointA is on s1 and pointB is on s2 - Assert.That(pointA.X, Is.GreaterThan(0.0f)); - Assert.That(pointB.X, Is.LessThan(0.0f)); + Assert.That(pointA.X, Is.GreaterThan(0)); + Assert.That(pointB.X, Is.LessThan(0)); // the collision normal points from s2 to s1 - Assert.That(normal.X, Is.GreaterThan(0.0f)); + Assert.That(normal.X, Is.GreaterThan(0)); // the penetration is positive - Assert.That(penetration, Is.GreaterThan(0.0f)); + Assert.That(penetration, Is.GreaterThan(0)); // ----------------------------------------------- - NarrowPhase.Collision(b1, b2, JQuaternion.Identity, JQuaternion.Identity, new JVector(-2.25f, 0, 0), new JVector(+2.25f, 0, 0), + NarrowPhase.Collision(b1, b2, JQuaternion.Identity, JQuaternion.Identity, new JVector(-(Real)2.25, 0, 0), new JVector(+(Real)2.25, 0, 0), out pointA, out pointB, out normal, out penetration); // the collision normal points from s2 to s1 - Assert.That(normal.X, Is.GreaterThan(0.0f)); + Assert.That(normal.X, Is.GreaterThan(0)); // the penetration is negative - Assert.That(penetration, Is.LessThan(0.0f)); + Assert.That(penetration, Is.LessThan(0)); } } \ No newline at end of file diff --git a/src/JitterTests/Helper.cs b/src/JitterTests/Helper.cs index bddf40e0..4337e01a 100644 --- a/src/JitterTests/Helper.cs +++ b/src/JitterTests/Helper.cs @@ -2,7 +2,7 @@ namespace JitterTests; public static class Helper { - public static void AdvanceWorld(World world, int seconds, float dt, bool multiThread) + public static void AdvanceWorld(World world, int seconds, Real dt, bool multiThread) { int total = (int)(seconds / dt); for (int i = 0; i < total; i++) @@ -11,7 +11,7 @@ public static void AdvanceWorld(World world, int seconds, float dt, bool multiTh public static RigidBody BuildTower(World world, JVector pos, int size = 40) { - JQuaternion halfRotationStep = JQuaternion.CreateRotationY(MathF.PI * 2.0f / 64.0f); + JQuaternion halfRotationStep = JQuaternion.CreateRotationY(MathR.PI * (Real)(2.0 / 64.0)); JQuaternion fullRotationStep = halfRotationStep * halfRotationStep; JQuaternion orientation = JQuaternion.Identity; @@ -24,9 +24,9 @@ public static RigidBody BuildTower(World world, JVector pos, int size = 40) for (int i = 0; i < 32; i++) { JVector position = pos + JVector.Transform( - new JVector(0, 0.5f + e, 19.5f), orientation); + new JVector(0, (Real)0.5 + e, (Real)19.5), orientation); - var shape = new BoxShape(3f, 1, 0.5f); + var shape = new BoxShape(3f, 1, (Real)0.5); last = world.CreateRigidBody(); @@ -51,9 +51,9 @@ public static RigidBody BuildSimpleStack(World world, int size = 12) { last = world.CreateRigidBody(); //body.AddShape(new BoxShape(1)); - last.Position = new JVector(0, 0.5f + i * 0.99f, 0); + last.Position = new JVector(0, (Real)0.5 + i * (Real)0.99, 0); last.AddShape(new BoxShape(1)); - last.Damping = (0.002f, 0.002f); + last.Damping = ((Real)0.002, (Real)0.002); if (i == 0) last.IsStatic = true; } @@ -69,7 +69,7 @@ public static RigidBody BuildPyramidBox(World world, JVector position, int size for (int e = i; e < size; e++) { last = world.CreateRigidBody(); - last.Position = position + new JVector((e - i * 0.5f) * 1.01f, 0.5f + i * 1.0f, 0.0f); + last.Position = position + new JVector((e - i * (Real)0.5) * (Real)1.01, (Real)0.5 + i * (Real)1.0, (Real)0.0); var shape = new BoxShape(1); last.AddShape(shape); @@ -88,8 +88,8 @@ public static RigidBody BuildPyramidCylinder(World world, JVector position, int for (int e = i; e < size; e++) { last = world.CreateRigidBody(); - last.Position = position + new JVector((e - i * 0.5f) * 1.01f, 0.5f + i * 1.0f, 0.0f); - var shape = new CylinderShape(1.0f, 0.5f); + last.Position = position + new JVector((e - i * (Real)0.5) * (Real)1.01, (Real)0.5 + i * (Real)1.0, (Real)0.0); + var shape = new CylinderShape((Real)1.0, (Real)0.5); last.AddShape(shape); if (i == 0) last.IsStatic = true; diff --git a/src/JitterTests/InertiaTests.cs b/src/JitterTests/InertiaTests.cs index d8519db7..b59f2d72 100644 --- a/src/JitterTests/InertiaTests.cs +++ b/src/JitterTests/InertiaTests.cs @@ -3,70 +3,70 @@ namespace JitterTests; [TestFixture] public class InertiaTests { - private static void Check(RigidBodyShape shape, JMatrix inertia, JVector com, float mass) + private static void Check(RigidBodyShape shape, JMatrix inertia, JVector com, Real mass) { - shape.CalculateMassInertia(out JMatrix shapeInertia, out JVector shapeCom, out float shapeMass); + shape.CalculateMassInertia(out JMatrix shapeInertia, out JVector shapeCom, out Real shapeMass); JMatrix dInertia = shapeInertia - inertia; - Assert.That(MathHelper.IsZero(dInertia.UnsafeGet(0), 1e-3f)); - Assert.That(MathHelper.IsZero(dInertia.UnsafeGet(1), 1e-3f)); - Assert.That(MathHelper.IsZero(dInertia.UnsafeGet(2), 1e-3f)); + Assert.That(MathHelper.IsZero(dInertia.UnsafeGet(0), (Real)1e-3)); + Assert.That(MathHelper.IsZero(dInertia.UnsafeGet(1), (Real)1e-3)); + Assert.That(MathHelper.IsZero(dInertia.UnsafeGet(2), (Real)1e-3)); - float dmass = shapeMass - mass; - Assert.That(MathF.Abs(dmass), Is.LessThan(1e-3f)); + Real dmass = shapeMass - mass; + Assert.That(MathR.Abs(dmass), Is.LessThan((Real)1e-3)); JVector dcom = shapeCom - com; - Assert.That(MathHelper.IsZero(dcom, 1e-3f)); + Assert.That(MathHelper.IsZero(dcom, (Real)1e-3)); } [TestCase] public static void CapsuleInertia() { - var ts = new CapsuleShape(0.429f, 1.7237f); - ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out float mass, 8); + var ts = new CapsuleShape((Real)0.429, (Real)1.7237); + ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out Real mass, 8); Check(ts, inertia, com, mass); } [TestCase] public static void CylinderInertia() { - var ts = new CylinderShape(0.429f, 1.7237f); - ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out float mass, 8); + var ts = new CylinderShape((Real)0.429, (Real)1.7237); + ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out Real mass, 8); Check(ts, inertia, com, mass); } [TestCase] public static void ConeInertia() { - var ts = new ConeShape(0.429f, 1.7237f); - ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out float mass, 8); + var ts = new ConeShape((Real)0.429, (Real)1.7237); + ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out Real mass, 8); Check(ts, inertia, com, mass); } [TestCase] public static void BoxInertia() { - var ts = new BoxShape(0.429f, 1.7237f, 2.11383f); - ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out float mass, 8); + var ts = new BoxShape((Real)0.429, (Real)1.7237, (Real)2.11383); + ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out Real mass, 8); Check(ts, inertia, com, mass); } [TestCase] public static void SphereInertia() { - var ts = new SphereShape(0.429f); - ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out float mass, 8); + var ts = new SphereShape((Real)0.429); + ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out Real mass, 8); Check(ts, inertia, com, mass); } [TestCase] public static void TransformedInertia() { - var ss = new SphereShape(0.429f); - var translation = new JVector(2.847f, 3.432f, 1.234f); + var ss = new SphereShape((Real)0.429); + var translation = new JVector((Real)2.847, (Real)3.432, (Real)1.234); var ts = new TransformedShape(ss, translation); - ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out float mass, 8); + ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out Real mass, 8); Check(ts, inertia, com, mass); } @@ -75,10 +75,10 @@ public static void ConvexHullInertia() { List cvh = new List(); - JVector a = new JVector(0.234f, 1.23f, 3.54f); - JVector b = new JVector(7.788f, 0.23f, 8.14f); - JVector c = new JVector(2.234f, 8.23f, 8.14f); - JVector d = new JVector(6.234f, 3.23f, 9.04f); + JVector a = new JVector((Real)0.234, (Real)1.23, (Real)3.54); + JVector b = new JVector((Real)7.788, (Real)0.23, (Real)8.14); + JVector c = new JVector((Real)2.234, (Real)8.23, (Real)8.14); + JVector d = new JVector((Real)6.234, (Real)3.23, (Real)9.04); cvh.Add(new JTriangle(a, b, c)); cvh.Add(new JTriangle(a, b, d)); @@ -86,7 +86,7 @@ public static void ConvexHullInertia() cvh.Add(new JTriangle(a, c, d)); var ts = new ConvexHullShape(cvh); - ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out float mass, 8); + ShapeHelper.CalculateMassInertia(ts, out JMatrix inertia, out JVector com, out Real mass, 8); Check(ts, inertia, com, mass); } } \ No newline at end of file diff --git a/src/JitterTests/JitterTests.csproj b/src/JitterTests/JitterTests.csproj index fd4e0ba9..5454359f 100644 --- a/src/JitterTests/JitterTests.csproj +++ b/src/JitterTests/JitterTests.csproj @@ -20,4 +20,10 @@ + + + Precision.cs + + + diff --git a/src/JitterTests/MathTests.cs b/src/JitterTests/MathTests.cs index 475ec52a..159a8825 100644 --- a/src/JitterTests/MathTests.cs +++ b/src/JitterTests/MathTests.cs @@ -12,8 +12,8 @@ public void Setup() [TestCase] public static void QMatrixProjectMultiplyLeftRight() { - JQuaternion jq1 = new(0.2f, 0.3f, 0.4f, 0.5f); - JQuaternion jq2 = new(0.1f, 0.7f, 0.1f, 0.8f); + JQuaternion jq1 = new((Real)0.2, (Real)0.3, (Real)0.4, (Real)0.5); + JQuaternion jq2 = new((Real)0.1, (Real)0.7, (Real)0.1, (Real)0.8); var qm1 = QMatrix.CreateLM(jq1); var qm2 = QMatrix.CreateRM(jq2); @@ -22,9 +22,9 @@ public static void QMatrixProjectMultiplyLeftRight() JMatrix res2 = QMatrix.ProjectMultiplyLeftRight(jq1, jq2); JMatrix delta = res1 - res2; - Assert.That(JVector.MaxAbs(delta.GetColumn(0)), Is.LessThan(1e-06f)); - Assert.That(JVector.MaxAbs(delta.GetColumn(1)), Is.LessThan(1e-06f)); - Assert.That(JVector.MaxAbs(delta.GetColumn(2)), Is.LessThan(1e-06f)); + Assert.That(JVector.MaxAbs(delta.GetColumn(0)), Is.LessThan((Real)1e-06)); + Assert.That(JVector.MaxAbs(delta.GetColumn(1)), Is.LessThan((Real)1e-06)); + Assert.That(JVector.MaxAbs(delta.GetColumn(2)), Is.LessThan((Real)1e-06)); } [TestCase] @@ -34,21 +34,21 @@ public static void TransformTests() JVector b = JVector.UnitY; JVector c = JVector.UnitZ; - Assert.That((a - b % c).Length(), Is.LessThan(1e-06f)); - Assert.That((b - c % a).Length(), Is.LessThan(1e-06f)); - Assert.That((c - a % b).Length(), Is.LessThan(1e-06f)); + Assert.That((a - b % c).Length(), Is.LessThan((Real)1e-06)); + Assert.That((b - c % a).Length(), Is.LessThan((Real)1e-06)); + Assert.That((c - a % b).Length(), Is.LessThan((Real)1e-06)); - JMatrix ar = JMatrix.CreateRotationX(0.123f) * - JMatrix.CreateRotationY(0.321f) * - JMatrix.CreateRotationZ(0.213f); + JMatrix ar = JMatrix.CreateRotationX((Real)0.123) * + JMatrix.CreateRotationY((Real)0.321) * + JMatrix.CreateRotationZ((Real)0.213); JVector.Transform(a, ar, out a); JVector.Transform(b, ar, out b); JVector.Transform(c, ar, out c); - Assert.That((a - b % c).Length(), Is.LessThan(1e-06f)); - Assert.That((b - c % a).Length(), Is.LessThan(1e-06f)); - Assert.That((c - a % b).Length(), Is.LessThan(1e-06f)); + Assert.That((a - b % c).Length(), Is.LessThan((Real)1e-06)); + Assert.That((b - c % a).Length(), Is.LessThan((Real)1e-06)); + Assert.That((c - a % b).Length(), Is.LessThan((Real)1e-06)); JMatrix.Inverse(ar, out ar); @@ -56,30 +56,30 @@ public static void TransformTests() JVector.Transform(b, ar, out b); JVector.Transform(c, ar, out c); - Assert.That((a - JVector.UnitX).Length(), Is.LessThan(1e-06f)); - Assert.That((b - JVector.UnitY).Length(), Is.LessThan(1e-06f)); - Assert.That((c - JVector.UnitZ).Length(), Is.LessThan(1e-06f)); + Assert.That((a - JVector.UnitX).Length(), Is.LessThan((Real)1e-06)); + Assert.That((b - JVector.UnitY).Length(), Is.LessThan((Real)1e-06)); + Assert.That((c - JVector.UnitZ).Length(), Is.LessThan((Real)1e-06)); // --- // https://arxiv.org/abs/1801.07478 - float cos = (float)Math.Cos(0.321f / 2.0f); - float sin = (float)Math.Sin(0.321f / 2.0f); + float cos = (float)MathR.Cos((Real)(0.321 / 2.0)); + float sin = (float)MathR.Sin((Real)(0.321 / 2.0)); JQuaternion quat1 = new(sin, 0, 0, cos); - JQuaternion quat2 = JQuaternion.CreateFromMatrix(JMatrix.CreateRotationZ(0.321f)); + JQuaternion quat2 = JQuaternion.CreateFromMatrix(JMatrix.CreateRotationZ((Real)0.321)); JQuaternion quat = JQuaternion.Multiply(quat1, quat2); JQuaternion tv = new(1, 2, 3, 0); JQuaternion tmp = JQuaternion.Multiply(JQuaternion.Multiply(quat, tv), JQuaternion.Conjugate(quat)); JVector resQuaternion = new(tmp.X, tmp.Y, tmp.Z); JVector.Transform(new JVector(1, 2, 3), JMatrix.CreateFromQuaternion(quat), out JVector resMatrix1); - Assert.That((resMatrix1 - resQuaternion).Length(), Is.LessThan(1e-06f)); + Assert.That((resMatrix1 - resQuaternion).Length(), Is.LessThan((Real)1e-06)); - JMatrix rot1 = JMatrix.CreateRotationX(0.321f); - JMatrix rot2 = JMatrix.CreateRotationZ(0.321f); + JMatrix rot1 = JMatrix.CreateRotationX((Real)0.321); + JMatrix rot2 = JMatrix.CreateRotationZ((Real)0.321); JMatrix rot = JMatrix.Multiply(rot1, rot2); JVector.Transform(new JVector(1, 2, 3), rot, out JVector resMatrix2); - Assert.That((resMatrix2 - resQuaternion).Length(), Is.LessThan(1e-06f)); + Assert.That((resMatrix2 - resQuaternion).Length(), Is.LessThan((Real)1e-06)); } } \ No newline at end of file diff --git a/src/JitterTests/StackingTests.cs b/src/JitterTests/StackingTests.cs index 2b859640..b517f096 100644 --- a/src/JitterTests/StackingTests.cs +++ b/src/JitterTests/StackingTests.cs @@ -23,11 +23,11 @@ public void SimpleStack(bool fullEPA) world.UseFullEPASolver = fullEPA; - float stackHeight = last.Position.Y; - Helper.AdvanceWorld(world, 10, 1.0f / 100.0f, true); - float delta = Math.Abs(stackHeight - last.Position.Y); + Real stackHeight = last.Position.Y; + Helper.AdvanceWorld(world, 10, (Real)(1.0 / 100.0), true); + Real delta = MathR.Abs(stackHeight - last.Position.Y); - Assert.That(delta, Is.LessThan(1f)); + Assert.That(delta, Is.LessThan(1)); } [TestCase(0, 0, 0, true)] @@ -39,9 +39,9 @@ public void PyramidStack(int x, int y, int z, bool multiThread) RigidBody last = Helper.BuildPyramidBox(world, new JVector(x, y, z)); - float stackHeight = last.Position.Y; - Helper.AdvanceWorld(world, 10, 1.0f / 100.0f, multiThread); - float delta = Math.Abs(stackHeight - last.Position.Y); + Real stackHeight = last.Position.Y; + Helper.AdvanceWorld(world, 10, (Real)(1.0 / 100.0), multiThread); + Real delta = MathR.Abs(stackHeight - last.Position.Y); Assert.That(delta, Is.LessThan(1f)); } @@ -57,9 +57,9 @@ public void PyramidStackCylinder(int x, int y, int z, bool fullEPA, bool multiTh RigidBody last = Helper.BuildPyramidCylinder(world, new JVector(x, y, z)); - float stackHeight = last.Position.Y; - Helper.AdvanceWorld(world, 10, 1.0f / 100.0f, multiThread); - float delta = Math.Abs(stackHeight - last.Position.Y); + Real stackHeight = last.Position.Y; + Helper.AdvanceWorld(world, 10, (Real)(1.0 / 100.0), multiThread); + Real delta = MathR.Abs(stackHeight - last.Position.Y); Assert.That(delta, Is.LessThan(1f)); } @@ -73,9 +73,9 @@ public void TowerStack(bool fullEPA, bool multiThread) RigidBody last = Helper.BuildTower(world, JVector.Zero, 30); - float stackHeight = last.Position.Y; - Helper.AdvanceWorld(world, 10, 1.0f / 100.0f, multiThread); - float delta = Math.Abs(stackHeight - last.Position.Y); + Real stackHeight = last.Position.Y; + Helper.AdvanceWorld(world, 10, (Real)(1.0 / 100.0), multiThread); + Real delta = MathR.Abs(stackHeight - last.Position.Y); Assert.That(delta, Is.LessThan(1f)); }